diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2013-04-25 21:46:31 +0900 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2013-04-25 21:46:31 +0900 |
| commit | 90abec8a362d6224bfff76d12fc9365fac36ddaa (patch) | |
| tree | 115a8248adda60f01004bdae167571c3f95d3806 /src | |
| parent | bbb978948d87790c6dfb78eaca1d47d45101443d (diff) | |
Move initialization code in aria2::main to struct Context
Diffstat (limited to 'src')
| -rw-r--r-- | src/Context.cc | 298 | ||||
| -rw-r--r-- | src/Context.h | 53 | ||||
| -rw-r--r-- | src/DownloadEngine.cc | 18 | ||||
| -rw-r--r-- | src/DownloadEngine.h | 6 | ||||
| -rw-r--r-- | src/Makefile.am | 5 | ||||
| -rw-r--r-- | src/MultiUrlRequestInfo.cc | 169 | ||||
| -rw-r--r-- | src/MultiUrlRequestInfo.h | 19 | ||||
| -rw-r--r-- | src/RequestGroupMan.cc | 5 | ||||
| -rw-r--r-- | src/SingletonHolder.h | 15 | ||||
| -rw-r--r-- | src/main.cc | 249 |
10 files changed, 510 insertions, 327 deletions
diff --git a/src/Context.cc b/src/Context.cc new file mode 100644 index 00000000..da23982d --- /dev/null +++ b/src/Context.cc @@ -0,0 +1,298 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2013 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#include "Context.h" + +#include <signal.h> +#include <unistd.h> +#include <getopt.h> + +#include <numeric> +#include <vector> +#include <iostream> + +#include "SharedHandle.h" +#include "LogFactory.h" +#include "Logger.h" +#include "util.h" +#include "FeatureConfig.h" +#include "MultiUrlRequestInfo.h" +#include "SimpleRandomizer.h" +#include "File.h" +#include "message.h" +#include "prefs.h" +#include "Option.h" +#include "a2algo.h" +#include "a2io.h" +#include "a2time.h" +#include "Platform.h" +#include "FileEntry.h" +#include "RequestGroup.h" +#include "ConsoleStatCalc.h" +#include "NullStatCalc.h" +#include "download_helper.h" +#include "Exception.h" +#include "ProtocolDetector.h" +#include "RecoverableException.h" +#include "SocketCore.h" +#include "DownloadContext.h" +#include "fmt.h" +#include "NullOutputFile.h" +#include "console.h" +#include "UriListParser.h" +#ifdef ENABLE_BITTORRENT +# include "bittorrent_helper.h" +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK +# include "metalink_helper.h" +# include "MetalinkEntry.h" +#endif // ENABLE_METALINK +#ifdef ENABLE_MESSAGE_DIGEST +# include "message_digest_helper.h" +#endif // ENABLE_MESSAGE_DIGEST + +extern char* optarg; +extern int optind, opterr, optopt; + +namespace aria2 { + +SharedHandle<StatCalc> getStatCalc(const SharedHandle<Option>& op) +{ + SharedHandle<StatCalc> statCalc; + if(op->getAsBool(PREF_QUIET)) { + statCalc.reset(new NullStatCalc()); + } else { + SharedHandle<ConsoleStatCalc> impl + (new ConsoleStatCalc(op->getAsInt(PREF_SUMMARY_INTERVAL), + op->getAsBool(PREF_HUMAN_READABLE))); + impl->setReadoutVisibility(op->getAsBool(PREF_SHOW_CONSOLE_READOUT)); + impl->setTruncate(op->getAsBool(PREF_TRUNCATE_CONSOLE_READOUT)); + statCalc = impl; + } + return statCalc; +} + +SharedHandle<OutputFile> getSummaryOut(const SharedHandle<Option>& op) +{ + if(op->getAsBool(PREF_QUIET)) { + return SharedHandle<OutputFile>(new NullOutputFile()); + } else { + return global::cout(); + } +} + +#ifdef ENABLE_BITTORRENT +namespace { +void showTorrentFile(const std::string& uri) +{ + SharedHandle<Option> op(new Option()); + SharedHandle<DownloadContext> dctx(new DownloadContext()); + bittorrent::load(uri, dctx, op); + bittorrent::print(*global::cout(), dctx); +} +} // namespace +#endif // ENABLE_BITTORRENT + +#ifdef ENABLE_METALINK +namespace { +void showMetalinkFile +(const std::string& uri, const SharedHandle<Option>& op) +{ + std::vector<SharedHandle<MetalinkEntry> > metalinkEntries; + metalink::parseAndQuery(metalinkEntries, uri, op.get(), + op->get(PREF_METALINK_BASE_URI)); + std::vector<SharedHandle<FileEntry> > fileEntries; + MetalinkEntry::toFileEntry(fileEntries, metalinkEntries); + util::toStream(fileEntries.begin(), fileEntries.end(), *global::cout()); + global::cout()->write("\n"); + global::cout()->flush(); +} +} // namespace +#endif // ENABLE_METALINK + +#if defined ENABLE_BITTORRENT || defined ENABLE_METALINK +namespace { +void showFiles +(const std::vector<std::string>& uris, const SharedHandle<Option>& op) +{ + ProtocolDetector dt; + for(std::vector<std::string>::const_iterator i = uris.begin(), + eoi = uris.end(); i != eoi; ++i) { + printf(">>> "); + printf(MSG_SHOW_FILES, (*i).c_str()); + printf("\n"); + try { +#ifdef ENABLE_BITTORRENT + if(dt.guessTorrentFile(*i)) { + showTorrentFile(*i); + } else +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK + if(dt.guessMetalinkFile(*i)) { + showMetalinkFile(*i, op); + } else +#endif // ENABLE_METALINK + { + printf(MSG_NOT_TORRENT_METALINK); + printf("\n\n"); + } + } catch(RecoverableException& e) { + global::cout()->printf("%s\n", e.stackTrace().c_str()); + } + } +} +} // namespace +#endif // ENABLE_BITTORRENT || ENABLE_METALINK + +extern void option_processing(Option& option, std::vector<std::string>& uris, + int argc, char* argv[]); + +Context::Context(int argc, char** argv) +{ + std::vector<std::string> args; + SharedHandle<Option> op(new Option()); + option_processing(*op.get(), args, argc, argv); + + SimpleRandomizer::init(); +#ifdef ENABLE_BITTORRENT + bittorrent::generateStaticPeerId(op->get(PREF_PEER_ID_PREFIX)); +#endif // ENABLE_BITTORRENT + LogFactory::setLogFile(op->get(PREF_LOG)); + LogFactory::setLogLevel(op->get(PREF_LOG_LEVEL)); + LogFactory::setConsoleLogLevel(op->get(PREF_CONSOLE_LOG_LEVEL)); + if(op->getAsBool(PREF_QUIET)) { + LogFactory::setConsoleOutput(false); + } + LogFactory::reconfigure(); + A2_LOG_INFO("<<--- --- --- ---"); + A2_LOG_INFO(" --- --- --- ---"); + A2_LOG_INFO(" --- --- --- --->>"); + A2_LOG_INFO(fmt("%s %s %s", PACKAGE, PACKAGE_VERSION, TARGET)); + A2_LOG_INFO(MSG_LOGGING_STARTED); + + if(op->getAsBool(PREF_DISABLE_IPV6)) { + SocketCore::setProtocolFamily(AF_INET); + // Get rid of AI_ADDRCONFIG. It causes name resolution error + // when none of network interface has IPv4 address. + setDefaultAIFlags(0); + } + net::checkAddrconfig(); + // Bind interface + if(!op->get(PREF_INTERFACE).empty()) { + std::string iface = op->get(PREF_INTERFACE); + SocketCore::bindAddress(iface); + } + sigset_t mask; +#ifdef HAVE_SIGACTION + sigemptyset(&mask); +#else // !HAVE_SIGACTION + mask = 0; +#endif // !HAVE_SIGACTION +#ifdef SIGPIPE + util::setGlobalSignalHandler(SIGPIPE, &mask, SIG_IGN, 0); +#endif +#ifdef SIGCHLD + // Avoid to create zombie process when forked child processes are + // died. + util::setGlobalSignalHandler(SIGCHLD, &mask, SIG_IGN, 0); +#endif // SIGCHILD + std::vector<SharedHandle<RequestGroup> > requestGroups; + SharedHandle<UriListParser> uriListParser; +#ifdef ENABLE_BITTORRENT + if(!op->blank(PREF_TORRENT_FILE)) { + if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { + showTorrentFile(op->get(PREF_TORRENT_FILE)); + return; + } else { + createRequestGroupForBitTorrent(requestGroups, op, args, + op->get(PREF_TORRENT_FILE)); + } + } + else +#endif // ENABLE_BITTORRENT +#ifdef ENABLE_METALINK + if(!op->blank(PREF_METALINK_FILE)) { + if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { + showMetalinkFile(op->get(PREF_METALINK_FILE), op); + return; + } else { + createRequestGroupForMetalink(requestGroups, op); + } + } + else +#endif // ENABLE_METALINK + if(!op->blank(PREF_INPUT_FILE)) { + if(op->getAsBool(PREF_DEFERRED_INPUT)) { + uriListParser = openUriListParser(op->get(PREF_INPUT_FILE)); + } else { + createRequestGroupForUriList(requestGroups, op); + } +#if defined ENABLE_BITTORRENT || defined ENABLE_METALINK + } else if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { + showFiles(args, op); + return; +#endif // ENABLE_METALINK || ENABLE_METALINK + } else { + createRequestGroupForUri(requestGroups, op, args, false, false, true); + } + + // Remove option values which is only valid for URIs specified in + // command-line. If they are left, because op is used as a template + // for new RequestGroup(such as created in RPC command), they causes + // unintentional effect. + for(SharedHandle<Option> i = op; i; i = i->getParent()) { + i->remove(PREF_OUT); + i->remove(PREF_FORCE_SEQUENTIAL); + i->remove(PREF_INPUT_FILE); + i->remove(PREF_INDEX_OUT); + i->remove(PREF_SELECT_FILE); + i->remove(PREF_PAUSE); + i->remove(PREF_CHECKSUM); + i->remove(PREF_GID); + } + if(!op->getAsBool(PREF_ENABLE_RPC) && requestGroups.empty() && + !uriListParser) { + global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD); + } else { + reqinfo.reset(new MultiUrlRequestInfo(requestGroups, op, getStatCalc(op), + getSummaryOut(op), + uriListParser)); + } +} + +Context::~Context() +{ +} + +} // namespace aria2 diff --git a/src/Context.h b/src/Context.h new file mode 100644 index 00000000..7a873bdd --- /dev/null +++ b/src/Context.h @@ -0,0 +1,53 @@ +/* <!-- copyright */ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2013 Tatsuhiro Tsujikawa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. + */ +/* copyright --> */ +#ifndef CONTEXT_H +#define CONTEXT_H + +#include "common.h" +#include "SharedHandle.h" + +namespace aria2 { + +class MultiUrlRequestInfo; + +struct Context { + Context(int argc, char** argv); + ~Context(); + SharedHandle<MultiUrlRequestInfo> reqinfo; +}; + +} // namespace aria2 + +#endif // CONTEXT_H diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index 05478fe8..0f266b58 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -86,7 +86,7 @@ volatile sig_atomic_t globalHaltRequested = 0; DownloadEngine::DownloadEngine(const SharedHandle<EventPoll>& eventPoll) : eventPoll_(eventPoll), haltRequested_(0), - noWait_(false), + noWait_(true), refreshInterval_(DEFAULT_REFRESH_INTERVAL), cookieStorage_(new CookieStorage()), #ifdef ENABLE_BITTORRENT @@ -139,11 +139,15 @@ void executeCommand(std::deque<Command*>& commands, } } // namespace -void DownloadEngine::run() +int DownloadEngine::run(bool oneshot) { Timer cp; cp.reset(0); while(!commands_.empty() || !routineCommands_.empty()) { + if(!commands_.empty()) { + waitData(); + } + noWait_ = false; global::wallclock().reset(); calculateStatistics(); if(cp.differenceInMillis(global::wallclock())+A2_DELTA_MILLIS >= @@ -156,12 +160,14 @@ void DownloadEngine::run() } executeCommand(routineCommands_, Command::STATUS_ALL); afterEachIteration(); - if(!commands_.empty()) { - waitData(); + if(oneshot) { + return 1; } - noWait_ = false; } - onEndOfRun(); + if(!oneshot) { + onEndOfRun(); + } + return 0; } void DownloadEngine::waitData() diff --git a/src/DownloadEngine.h b/src/DownloadEngine.h index d949bff6..f382a6c1 100644 --- a/src/DownloadEngine.h +++ b/src/DownloadEngine.h @@ -167,7 +167,11 @@ public: ~DownloadEngine(); - void run(); + // If oneshot is true, this function returns after one event polling + // and performing action for them. This function returns 1 when + // oneshot is true and there are still downloads to be + // processed. Otherwise, returns 0. + int run(bool oneshot=false); void cleanQueue(); diff --git a/src/Makefile.am b/src/Makefile.am index 5a52d4ac..ef4ff62b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,10 @@ SUBDIRS = includes bin_PROGRAMS = aria2c aria2c_SOURCES = main.cc\ - option_processing.cc\ version_usage.cc -SRCS = SocketCore.cc SocketCore.h\ +SRCS = option_processing.cc\ + Context.cc Context.h\ + SocketCore.cc SocketCore.h\ BinaryStream.h\ Command.cc Command.h\ AbstractCommand.cc AbstractCommand.h\ diff --git a/src/MultiUrlRequestInfo.cc b/src/MultiUrlRequestInfo.cc index b0156aca..3f2b3e9f 100644 --- a/src/MultiUrlRequestInfo.cc +++ b/src/MultiUrlRequestInfo.cc @@ -109,12 +109,14 @@ MultiUrlRequestInfo::MultiUrlRequestInfo const SharedHandle<StatCalc>& statCalc, const SharedHandle<OutputFile>& summaryOut, const SharedHandle<UriListParser>& uriListParser) - : requestGroups_(requestGroups), - option_(op), + : option_(op), statCalc_(statCalc), summaryOut_(summaryOut), uriListParser_(uriListParser) -{} + // TODO init mask_ +{ + requestGroups_.swap(requestGroups); +} MultiUrlRequestInfo::~MultiUrlRequestInfo() {} @@ -126,17 +128,15 @@ void MultiUrlRequestInfo::printMessageForContinue() _("If there are any errors, then see the log file. See '-l' option in help/man page for details.")); } -error_code::Value MultiUrlRequestInfo::execute() +error_code::Value MultiUrlRequestInfo::prepare() { - error_code::Value returnValue = error_code::FINISHED; - sigset_t mask; try { SharedHandle<rpc::WebSocketSessionMan> wsSessionMan; if(option_->getAsBool(PREF_ENABLE_RPC)) { wsSessionMan.reset(new rpc::WebSocketSessionMan()); } - Notifier notifier(wsSessionMan); - SingletonHolder<Notifier>::instance(¬ifier); + SharedHandle<Notifier> notifier(new Notifier(wsSessionMan)); + SingletonHolder<Notifier>::instance(notifier); #ifdef ENABLE_SSL if(option_->getAsBool(PREF_ENABLE_RPC) && @@ -159,15 +159,16 @@ error_code::Value MultiUrlRequestInfo::execute() } #endif // ENABLE_SSL - SharedHandle<DownloadEngine> e = - DownloadEngineFactory().newDownloadEngine(option_.get(), requestGroups_); + e_ = DownloadEngineFactory().newDownloadEngine(option_.get(), + requestGroups_); // Avoid keeping RequestGroups alive longer than necessary requestGroups_.clear(); if(!option_->blank(PREF_LOAD_COOKIES)) { File cookieFile(option_->get(PREF_LOAD_COOKIES)); if(cookieFile.isFile() && - e->getCookieStorage()->load(cookieFile.getPath(), Time().getTime())) { + e_->getCookieStorage()->load(cookieFile.getPath(), + Time().getTime())) { A2_LOG_INFO(fmt("Loaded cookies from '%s'.", cookieFile.getPath().c_str())); } else { @@ -194,7 +195,7 @@ error_code::Value MultiUrlRequestInfo::execute() authConfigFactory->setNetrc(netrc); } } - e->setAuthConfigFactory(authConfigFactory); + e_->setAuthConfigFactory(authConfigFactory); #ifdef ENABLE_SSL SharedHandle<TLSContext> clTlsContext(TLSContext::make(TLS_CLIENT)); @@ -220,7 +221,7 @@ error_code::Value MultiUrlRequestInfo::execute() #ifdef HAVE_ARES_ADDR_NODE ares_addr_node* asyncDNSServers = parseAsyncDNSServers(option_->get(PREF_ASYNC_DNS_SERVER)); - e->setAsyncDNSServers(asyncDNSServers); + e_->setAsyncDNSServers(asyncDNSServers); #endif // HAVE_ARES_ADDR_NODE if(!Timer::monotonicClock()) { A2_LOG_WARN("Don't change system time while aria2c is running." @@ -229,86 +230,120 @@ error_code::Value MultiUrlRequestInfo::execute() std::string serverStatIf = option_->get(PREF_SERVER_STAT_IF); if(!serverStatIf.empty()) { - e->getRequestGroupMan()->loadServerStat(serverStatIf); - e->getRequestGroupMan()->removeStaleServerStat + e_->getRequestGroupMan()->loadServerStat(serverStatIf); + e_->getRequestGroupMan()->removeStaleServerStat (option_->getAsInt(PREF_SERVER_STAT_TIMEOUT)); } - e->setStatCalc(statCalc_); + e_->setStatCalc(statCalc_); if(uriListParser_) { - e->getRequestGroupMan()->setUriListParser(uriListParser_); + e_->getRequestGroupMan()->setUriListParser(uriListParser_); } #ifdef HAVE_SIGACTION - sigemptyset(&mask); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGTERM); + sigemptyset(&mask_); + sigaddset(&mask_, SIGINT); + sigaddset(&mask_, SIGTERM); #ifdef SIGHUP - sigaddset(&mask, SIGHUP); + sigaddset(&mask_, SIGHUP); #endif // SIGHUP #else // !HAVE_SIGACTION - mask = 0; + mask_ = 0; #endif // !HAVE_SIGACTION #ifdef SIGHUP - util::setGlobalSignalHandler(SIGHUP, &mask, handler, 0); + util::setGlobalSignalHandler(SIGHUP, &mask_, handler, 0); #endif // SIGHUP - util::setGlobalSignalHandler(SIGINT, &mask, handler, 0); - util::setGlobalSignalHandler(SIGTERM, &mask, handler, 0); + util::setGlobalSignalHandler(SIGINT, &mask_, handler, 0); + util::setGlobalSignalHandler(SIGTERM, &mask_, handler, 0); - e->getRequestGroupMan()->getNetStat().downloadStart(); - e->run(); + e_->getRequestGroupMan()->getNetStat().downloadStart(); + } catch(RecoverableException& e) { + SingletonHolder<Notifier>::clear(); + resetSignalHandlers(); + return error_code::UNKNOWN_ERROR; + } + return error_code::FINISHED; +} - if(!option_->blank(PREF_SAVE_COOKIES)) { - e->getCookieStorage()->saveNsFormat(option_->get(PREF_SAVE_COOKIES)); - } +error_code::Value MultiUrlRequestInfo::getResult() +{ + error_code::Value returnValue = error_code::FINISHED; + if(!option_->blank(PREF_SAVE_COOKIES)) { + e_->getCookieStorage()->saveNsFormat(option_->get(PREF_SAVE_COOKIES)); + } - const std::string& serverStatOf = option_->get(PREF_SERVER_STAT_OF); - if(!serverStatOf.empty()) { - e->getRequestGroupMan()->saveServerStat(serverStatOf); - } - e->getRequestGroupMan()->showDownloadResults - (*summaryOut_, option_->get(PREF_DOWNLOAD_RESULT) == A2_V_FULL); - summaryOut_->flush(); + const std::string& serverStatOf = option_->get(PREF_SERVER_STAT_OF); + if(!serverStatOf.empty()) { + e_->getRequestGroupMan()->saveServerStat(serverStatOf); + } + e_->getRequestGroupMan()->showDownloadResults + (*summaryOut_, option_->get(PREF_DOWNLOAD_RESULT) == A2_V_FULL); + summaryOut_->flush(); - RequestGroupMan::DownloadStat s = - e->getRequestGroupMan()->getDownloadStat(); - if(!s.allCompleted()) { - printMessageForContinue(); - if(s.getLastErrorResult() == error_code::FINISHED && - s.getInProgress() > 0) { - returnValue = error_code::IN_PROGRESS; - } else { - returnValue = s.getLastErrorResult(); - } + RequestGroupMan::DownloadStat s = + e_->getRequestGroupMan()->getDownloadStat(); + if(!s.allCompleted()) { + printMessageForContinue(); + if(s.getLastErrorResult() == error_code::FINISHED && + s.getInProgress() > 0) { + returnValue = error_code::IN_PROGRESS; + } else { + returnValue = s.getLastErrorResult(); } - SessionSerializer sessionSerializer(e->getRequestGroupMan()); - // TODO Add option: --save-session-status=error,inprogress,waiting - if(!option_->blank(PREF_SAVE_SESSION)) { - const std::string& filename = option_->get(PREF_SAVE_SESSION); - if(sessionSerializer.save(filename)) { - A2_LOG_NOTICE(fmt(_("Serialized session to '%s' successfully."), - filename.c_str())); - } else { - A2_LOG_NOTICE(fmt(_("Failed to serialize session to '%s'."), - filename.c_str())); - } + } + SessionSerializer sessionSerializer(e_->getRequestGroupMan()); + // TODO Add option: --save-session-status=error,inprogress,waiting + if(!option_->blank(PREF_SAVE_SESSION)) { + const std::string& filename = option_->get(PREF_SAVE_SESSION); + if(sessionSerializer.save(filename)) { + A2_LOG_NOTICE(fmt(_("Serialized session to '%s' successfully."), + filename.c_str())); + } else { + A2_LOG_NOTICE(fmt(_("Failed to serialize session to '%s'."), + filename.c_str())); } + } + SingletonHolder<Notifier>::clear(); + return returnValue; +} + +int MultiUrlRequestInfo::run() +{ + int rv; + try { + rv = e_->run(true); + } catch(RecoverableException& e) { + rv = -1; + } + return rv; +} + +error_code::Value MultiUrlRequestInfo::execute() +{ + error_code::Value returnValue; + returnValue = prepare(); + if(returnValue != error_code::FINISHED) { + return returnValue; + } + try { + e_->run(); } catch(RecoverableException& e) { - if(returnValue == error_code::FINISHED) { - returnValue = error_code::UNKNOWN_ERROR; - } A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, e); } - SingletonHolder<Notifier>::instance(0); + returnValue = getResult(); + resetSignalHandlers(); + return returnValue; +} +void MultiUrlRequestInfo::resetSignalHandlers() +{ #ifdef HAVE_SIGACTION - sigemptyset(&mask); + sigemptyset(&mask_); #endif // HAVE_SIGACTION #ifdef SIGHUP - util::setGlobalSignalHandler(SIGHUP, &mask, SIG_DFL, 0); + util::setGlobalSignalHandler(SIGHUP, &mask_, SIG_DFL, 0); #endif // SIGHUP - util::setGlobalSignalHandler(SIGINT, &mask, SIG_DFL, 0); - util::setGlobalSignalHandler(SIGTERM, &mask, SIG_DFL, 0); - return returnValue; + util::setGlobalSignalHandler(SIGINT, &mask_, SIG_DFL, 0); + util::setGlobalSignalHandler(SIGTERM, &mask_, SIG_DFL, 0); } } // namespace aria2 diff --git a/src/MultiUrlRequestInfo.h b/src/MultiUrlRequestInfo.h index 45a627df..0d6b7377 100644 --- a/src/MultiUrlRequestInfo.h +++ b/src/MultiUrlRequestInfo.h @@ -37,10 +37,13 @@ #include "common.h" +#include <signal.h> + #include <vector> #include "SharedHandle.h" #include "DownloadResult.h" +#include "util.h" namespace aria2 { @@ -49,10 +52,11 @@ class Option; class StatCalc; class OutputFile; class UriListParser; +class DownloadEngine; class MultiUrlRequestInfo { private: - std::vector<SharedHandle<RequestGroup> >& requestGroups_; + std::vector<SharedHandle<RequestGroup> > requestGroups_; SharedHandle<Option> option_; @@ -62,7 +66,12 @@ private: SharedHandle<UriListParser> uriListParser_; + SharedHandle<DownloadEngine> e_; + + sigset_t mask_; + void printMessageForContinue(); + void resetSignalHandlers(); public: /* * MultiRequestInfo effectively takes ownership of the @@ -82,6 +91,14 @@ public: * last download result. */ error_code::Value execute(); + + error_code::Value prepare(); + error_code::Value getResult(); + // Returns 1 if the caller needs to call this function one or more + // time. Returns 0 if the function succeeds. Returns -1 on error. + // For return value 0 and -1, the caller must call tearDown() to get + // final error code. + int run(); }; } // namespace aria2 diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index d24e274f..fb8b4994 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -214,9 +214,8 @@ void notifyDownloadEvent (const std::string& event, const SharedHandle<RequestGroup>& group) { // Check NULL to make unit test easier. - Notifier* notifier = SingletonHolder<Notifier>::instance(); - if(notifier) { - notifier->notifyDownloadEvent(event, group); + if(SingletonHolder<Notifier>::instance()) { + SingletonHolder<Notifier>::instance()->notifyDownloadEvent(event, group); } } diff --git a/src/SingletonHolder.h b/src/SingletonHolder.h index 7f8e2d69..dcfe9e33 100644 --- a/src/SingletonHolder.h +++ b/src/SingletonHolder.h @@ -35,30 +35,37 @@ #ifndef D_SINGLETON_HOLDER_H #define D_SINGLETON_HOLDER_H +#include "SharedHandle.h" + namespace aria2 { template<typename T> class SingletonHolder { private: - static T* instance_; + static SharedHandle<T> instance_; SingletonHolder() {} public: ~SingletonHolder() {} - static T* instance() + static const SharedHandle<T>& instance() { return instance_; } - static void instance(T* instance) + static void instance(const SharedHandle<T>& instance) { instance_ = instance; } + + static void clear() + { + instance_.reset(); + } }; template<typename T> -T* SingletonHolder<T>::instance_ = 0; +SharedHandle<T> SingletonHolder<T>::instance_; } // namespace aria2 diff --git a/src/main.cc b/src/main.cc index c58300f3..47968f2e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -34,268 +34,31 @@ /* copyright --> */ #include "common.h" -#include <signal.h> #include <unistd.h> -#include <getopt.h> - -#include <numeric> -#include <vector> -#include <iostream> #include "SharedHandle.h" -#include "LogFactory.h" -#include "Logger.h" -#include "util.h" -#include "FeatureConfig.h" +#include "Context.h" #include "MultiUrlRequestInfo.h" -#include "SimpleRandomizer.h" -#include "File.h" #include "message.h" -#include "prefs.h" -#include "Option.h" -#include "a2algo.h" -#include "a2io.h" -#include "a2time.h" #include "Platform.h" -#include "FileEntry.h" -#include "RequestGroup.h" -#include "ConsoleStatCalc.h" -#include "NullStatCalc.h" -#include "download_helper.h" #include "Exception.h" -#include "ProtocolDetector.h" -#include "RecoverableException.h" -#include "SocketCore.h" -#include "DownloadContext.h" -#include "fmt.h" -#include "NullOutputFile.h" #include "console.h" -#include "UriListParser.h" -#ifdef ENABLE_BITTORRENT -# include "bittorrent_helper.h" -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK -# include "metalink_helper.h" -# include "MetalinkEntry.h" -#endif // ENABLE_METALINK -#ifdef ENABLE_MESSAGE_DIGEST -# include "message_digest_helper.h" -#endif // ENABLE_MESSAGE_DIGEST - -extern char* optarg; -extern int optind, opterr, optopt; namespace aria2 { -SharedHandle<StatCalc> getStatCalc(const SharedHandle<Option>& op) -{ - SharedHandle<StatCalc> statCalc; - if(op->getAsBool(PREF_QUIET)) { - statCalc.reset(new NullStatCalc()); - } else { - SharedHandle<ConsoleStatCalc> impl - (new ConsoleStatCalc(op->getAsInt(PREF_SUMMARY_INTERVAL), - op->getAsBool(PREF_HUMAN_READABLE))); - impl->setReadoutVisibility(op->getAsBool(PREF_SHOW_CONSOLE_READOUT)); - impl->setTruncate(op->getAsBool(PREF_TRUNCATE_CONSOLE_READOUT)); - statCalc = impl; - } - return statCalc; -} - -SharedHandle<OutputFile> getSummaryOut(const SharedHandle<Option>& op) +error_code::Value main(int argc, char** argv) { - if(op->getAsBool(PREF_QUIET)) { - return SharedHandle<OutputFile>(new NullOutputFile()); - } else { - return global::cout(); - } -} - -#ifdef ENABLE_BITTORRENT -namespace { -void showTorrentFile(const std::string& uri) -{ - SharedHandle<Option> op(new Option()); - SharedHandle<DownloadContext> dctx(new DownloadContext()); - bittorrent::load(uri, dctx, op); - bittorrent::print(*global::cout(), dctx); -} -} // namespace -#endif // ENABLE_BITTORRENT - -#ifdef ENABLE_METALINK -namespace { -void showMetalinkFile -(const std::string& uri, const SharedHandle<Option>& op) -{ - std::vector<SharedHandle<MetalinkEntry> > metalinkEntries; - metalink::parseAndQuery(metalinkEntries, uri, op.get(), - op->get(PREF_METALINK_BASE_URI)); - std::vector<SharedHandle<FileEntry> > fileEntries; - MetalinkEntry::toFileEntry(fileEntries, metalinkEntries); - util::toStream(fileEntries.begin(), fileEntries.end(), *global::cout()); - global::cout()->write("\n"); - global::cout()->flush(); -} -} // namespace -#endif // ENABLE_METALINK - -#if defined ENABLE_BITTORRENT || defined ENABLE_METALINK -namespace { -void showFiles -(const std::vector<std::string>& uris, const SharedHandle<Option>& op) -{ - ProtocolDetector dt; - for(std::vector<std::string>::const_iterator i = uris.begin(), - eoi = uris.end(); i != eoi; ++i) { - printf(">>> "); - printf(MSG_SHOW_FILES, (*i).c_str()); - printf("\n"); - try { -#ifdef ENABLE_BITTORRENT - if(dt.guessTorrentFile(*i)) { - showTorrentFile(*i); - } else -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - if(dt.guessMetalinkFile(*i)) { - showMetalinkFile(*i, op); - } else -#endif // ENABLE_METALINK - { - printf(MSG_NOT_TORRENT_METALINK); - printf("\n\n"); - } - } catch(RecoverableException& e) { - global::cout()->printf("%s\n", e.stackTrace().c_str()); - } - } -} -} // namespace -#endif // ENABLE_BITTORRENT || ENABLE_METALINK - -extern void option_processing(Option& option, std::vector<std::string>& uris, - int argc, char* argv[]); - -error_code::Value main(int argc, char* argv[]) -{ - std::vector<std::string> args; - SharedHandle<Option> op(new Option()); - option_processing(*op.get(), args, argc, argv); - - SimpleRandomizer::init(); -#ifdef ENABLE_BITTORRENT - bittorrent::generateStaticPeerId(op->get(PREF_PEER_ID_PREFIX)); -#endif // ENABLE_BITTORRENT - LogFactory::setLogFile(op->get(PREF_LOG)); - LogFactory::setLogLevel(op->get(PREF_LOG_LEVEL)); - LogFactory::setConsoleLogLevel(op->get(PREF_CONSOLE_LOG_LEVEL)); - if(op->getAsBool(PREF_QUIET)) { - LogFactory::setConsoleOutput(false); - } - LogFactory::reconfigure(); + Context context(argc, argv); error_code::Value exitStatus = error_code::FINISHED; - A2_LOG_INFO("<<--- --- --- ---"); - A2_LOG_INFO(" --- --- --- ---"); - A2_LOG_INFO(" --- --- --- --->>"); - A2_LOG_INFO(fmt("%s %s %s", PACKAGE, PACKAGE_VERSION, TARGET)); - A2_LOG_INFO(MSG_LOGGING_STARTED); - - if(op->getAsBool(PREF_DISABLE_IPV6)) { - SocketCore::setProtocolFamily(AF_INET); - // Get rid of AI_ADDRCONFIG. It causes name resolution error - // when none of network interface has IPv4 address. - setDefaultAIFlags(0); - } - net::checkAddrconfig(); - // Bind interface - if(!op->get(PREF_INTERFACE).empty()) { - std::string iface = op->get(PREF_INTERFACE); - SocketCore::bindAddress(iface); - } - sigset_t mask; -#ifdef HAVE_SIGACTION - sigemptyset(&mask); -#else // !HAVE_SIGACTION - mask = 0; -#endif // !HAVE_SIGACTION -#ifdef SIGPIPE - util::setGlobalSignalHandler(SIGPIPE, &mask, SIG_IGN, 0); -#endif -#ifdef SIGCHLD - // Avoid to create zombie process when forked child processes are - // died. - util::setGlobalSignalHandler(SIGCHLD, &mask, SIG_IGN, 0); -#endif // SIGCHILD - std::vector<SharedHandle<RequestGroup> > requestGroups; - SharedHandle<UriListParser> uriListParser; -#ifdef ENABLE_BITTORRENT - if(!op->blank(PREF_TORRENT_FILE)) { - if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { - showTorrentFile(op->get(PREF_TORRENT_FILE)); - return exitStatus; - } else { - createRequestGroupForBitTorrent(requestGroups, op, args, - op->get(PREF_TORRENT_FILE)); - } - } - else -#endif // ENABLE_BITTORRENT -#ifdef ENABLE_METALINK - if(!op->blank(PREF_METALINK_FILE)) { - if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { - showMetalinkFile(op->get(PREF_METALINK_FILE), op); - return exitStatus; - } else { - createRequestGroupForMetalink(requestGroups, op); - } - } - else -#endif // ENABLE_METALINK - if(!op->blank(PREF_INPUT_FILE)) { - if(op->getAsBool(PREF_DEFERRED_INPUT)) { - uriListParser = openUriListParser(op->get(PREF_INPUT_FILE)); - } else { - createRequestGroupForUriList(requestGroups, op); - } -#if defined ENABLE_BITTORRENT || defined ENABLE_METALINK - } else if(op->get(PREF_SHOW_FILES) == A2_V_TRUE) { - showFiles(args, op); - return exitStatus; -#endif // ENABLE_METALINK || ENABLE_METALINK - } else { - createRequestGroupForUri(requestGroups, op, args, false, false, true); - } - - // Remove option values which is only valid for URIs specified in - // command-line. If they are left, because op is used as a template - // for new RequestGroup(such as created in RPC command), they causes - // unintentional effect. - for(SharedHandle<Option> i = op; i; i = i->getParent()) { - i->remove(PREF_OUT); - i->remove(PREF_FORCE_SEQUENTIAL); - i->remove(PREF_INPUT_FILE); - i->remove(PREF_INDEX_OUT); - i->remove(PREF_SELECT_FILE); - i->remove(PREF_PAUSE); - i->remove(PREF_CHECKSUM); - i->remove(PREF_GID); - } - if(!op->getAsBool(PREF_ENABLE_RPC) && requestGroups.empty() && - !uriListParser) { - global::cout()->printf("%s\n", MSG_NO_FILES_TO_DOWNLOAD); - } else { - exitStatus = MultiUrlRequestInfo(requestGroups, op, getStatCalc(op), - getSummaryOut(op), - uriListParser).execute(); + if(context.reqinfo) { + exitStatus = context.reqinfo->execute(); } return exitStatus; } } // namespace aria2 -int main(int argc, char* argv[]) +int main(int argc, char** argv) { aria2::error_code::Value r; try { |
