main.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "common.h"
  36. #include "SharedHandle.h"
  37. #include "LogFactory.h"
  38. #include "Logger.h"
  39. #include "Util.h"
  40. #include "BitfieldManFactory.h"
  41. #include "AuthConfigFactory.h"
  42. #include "FeatureConfig.h"
  43. #include "MultiUrlRequestInfo.h"
  44. #include "SimpleRandomizer.h"
  45. #include "Netrc.h"
  46. #include "FatalException.h"
  47. #include "File.h"
  48. #include "CUIDCounter.h"
  49. #include "UriListParser.h"
  50. #include "message.h"
  51. #include "prefs.h"
  52. #include "Option.h"
  53. #include "a2algo.h"
  54. #include "a2io.h"
  55. #include "a2time.h"
  56. #include "Platform.h"
  57. #include "ParameterizedStringParser.h"
  58. #include "PStringBuildVisitor.h"
  59. #include "SingleFileDownloadContext.h"
  60. #include "DefaultBtContext.h"
  61. #include "FileEntry.h"
  62. #include "RequestGroup.h"
  63. #include "ProtocolDetector.h"
  64. #include "ConsoleStatCalc.h"
  65. #include "NullStatCalc.h"
  66. #include "StringFormat.h"
  67. #include "A2STR.h"
  68. #include "RecoverableException.h"
  69. #ifdef ENABLE_METALINK
  70. # include "MetalinkHelper.h"
  71. # include "Metalink2RequestGroup.h"
  72. # include "MetalinkEntry.h"
  73. #endif // ENABLE_METALINK
  74. #ifdef ENABLE_MESSAGE_DIGEST
  75. # include "MessageDigestHelper.h"
  76. #endif // ENABLE_MESSAGE_DIGEST
  77. #include <deque>
  78. #include <signal.h>
  79. #include <unistd.h>
  80. #include <fstream>
  81. #include <iostream>
  82. #include <numeric>
  83. extern char* optarg;
  84. extern int optind, opterr, optopt;
  85. #include <getopt.h>
  86. namespace aria2 {
  87. // output stream to /dev/null
  88. std::ofstream nullout(DEV_NULL);
  89. std::deque<std::string> unfoldURI(const std::deque<std::string>& args)
  90. {
  91. std::deque<std::string> nargs;
  92. ParameterizedStringParser p;
  93. PStringBuildVisitor v;
  94. for(std::deque<std::string>::const_iterator itr = args.begin(); itr != args.end();
  95. ++itr) {
  96. v.reset();
  97. p.parse(*itr)->accept(&v);
  98. nargs.insert(nargs.end(), v.getURIs().begin(), v.getURIs().end());
  99. }
  100. return nargs;
  101. }
  102. RequestGroupHandle createRequestGroup(const Option* op, const std::deque<std::string>& uris,
  103. const std::string& ufilename = A2STR::NIL)
  104. {
  105. RequestGroupHandle rg(new RequestGroup(op, uris));
  106. SingleFileDownloadContextHandle dctx
  107. (new SingleFileDownloadContext(op->getAsInt(PREF_SEGMENT_SIZE),
  108. 0,
  109. A2STR::NIL,
  110. ufilename));
  111. dctx->setDir(op->get(PREF_DIR));
  112. rg->setDownloadContext(dctx);
  113. return rg;
  114. }
  115. SharedHandle<StatCalc> getStatCalc(const Option* op)
  116. {
  117. SharedHandle<StatCalc> statCalc;
  118. if(op->getAsBool(PREF_QUIET)) {
  119. statCalc.reset(new NullStatCalc());
  120. } else {
  121. statCalc.reset(new ConsoleStatCalc(op->getAsInt(PREF_SUMMARY_INTERVAL)));
  122. }
  123. return statCalc;
  124. }
  125. std::ostream& getSummaryOut(const Option* op)
  126. {
  127. if(op->getAsBool(PREF_QUIET)) {
  128. return nullout;
  129. } else {
  130. return std::cout;
  131. }
  132. }
  133. extern Option* option_processing(int argc, char* const argv[]);
  134. #ifdef ENABLE_BITTORRENT
  135. SharedHandle<RequestGroup>
  136. createBtRequestGroup(const std::string& torrentFilePath,
  137. Option* op,
  138. const std::deque<std::string>& auxUris)
  139. {
  140. SharedHandle<RequestGroup> rg(new RequestGroup(op, auxUris));
  141. SharedHandle<DefaultBtContext> btContext(new DefaultBtContext());
  142. btContext->load(torrentFilePath);// may throw exception
  143. if(op->defined(PREF_PEER_ID_PREFIX)) {
  144. btContext->setPeerIdPrefix(op->get(PREF_PEER_ID_PREFIX));
  145. }
  146. btContext->setDir(op->get(PREF_DIR));
  147. rg->setDownloadContext(btContext);
  148. btContext->setOwnerRequestGroup(rg.get());
  149. return rg;
  150. }
  151. int32_t downloadBitTorrent(Option* op, const std::deque<std::string>& uris)
  152. {
  153. std::deque<std::string> nargs;
  154. if(op->get(PREF_PARAMETERIZED_URI) == V_TRUE) {
  155. nargs = unfoldURI(uris);
  156. } else {
  157. nargs = uris;
  158. }
  159. RequestGroups groups;
  160. size_t numSplit = op->getAsInt(PREF_SPLIT);
  161. if(nargs.size() >= numSplit) {
  162. RequestGroupHandle rg = createBtRequestGroup(op->get(PREF_TORRENT_FILE),
  163. op, nargs);
  164. rg->setNumConcurrentCommand(numSplit);
  165. groups.push_back(rg);
  166. } else {
  167. std::deque<std::string> xargs;
  168. if(!nargs.empty()) {
  169. ncopy(nargs.begin(), nargs.end(), numSplit, std::back_inserter(xargs));
  170. xargs.erase(xargs.begin()+numSplit, xargs.end());
  171. }
  172. RequestGroupHandle rg = createBtRequestGroup(op->get(PREF_TORRENT_FILE),
  173. op, xargs);
  174. rg->setNumConcurrentCommand(numSplit);
  175. groups.push_back(rg);
  176. }
  177. return MultiUrlRequestInfo(groups, op, getStatCalc(op), getSummaryOut(op)).execute();
  178. }
  179. #endif // ENABLE_BITTORRENT
  180. #ifdef ENABLE_METALINK
  181. int32_t downloadMetalink(Option* op)
  182. {
  183. RequestGroups groups;
  184. Metalink2RequestGroup(op).generate(groups, op->get(PREF_METALINK_FILE));
  185. if(groups.empty()) {
  186. throw FatalException("No files to download.");
  187. }
  188. return MultiUrlRequestInfo(groups, op, getStatCalc(op), getSummaryOut(op)).execute();
  189. }
  190. #endif // ENABLE_METALINK
  191. class AccRequestGroup {
  192. private:
  193. std::deque<SharedHandle<RequestGroup> >& _requestGroups;
  194. ProtocolDetector _detector;
  195. Option* _op;
  196. public:
  197. AccRequestGroup(std::deque<SharedHandle<RequestGroup> >& requestGroups,
  198. Option* op):
  199. _requestGroups(requestGroups), _op(op) {}
  200. void
  201. operator()(const std::string& uri)
  202. {
  203. if(_detector.isStreamProtocol(uri)) {
  204. std::deque<std::string> xuris;
  205. for(size_t count = _op->getAsInt(PREF_SPLIT); count; --count) {
  206. xuris.push_back(uri);
  207. }
  208. RequestGroupHandle rg = createRequestGroup(_op, xuris);
  209. _requestGroups.push_back(rg);
  210. }
  211. #ifdef ENABLE_BITTORRENT
  212. else if(_detector.guessTorrentFile(uri)) {
  213. try {
  214. _requestGroups.push_back(createBtRequestGroup(uri, _op,
  215. std::deque<std::string>()));
  216. } catch(RecoverableException& e) {
  217. // error occurred while parsing torrent file.
  218. // We simply ignore it.
  219. LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e);
  220. }
  221. }
  222. #endif // ENABLE_BITTORRENT
  223. #ifdef ENABLE_METALINK
  224. else if(_detector.guessMetalinkFile(uri)) {
  225. try {
  226. Metalink2RequestGroup(_op).generate(_requestGroups, uri);
  227. } catch(RecoverableException& e) {
  228. // error occurred while parsing metalink file.
  229. // We simply ignore it.
  230. LogFactory::getInstance()->error(EX_EXCEPTION_CAUGHT, e);
  231. }
  232. }
  233. #endif // ENABLE_METALINK
  234. else {
  235. LogFactory::getInstance()->error(MSG_UNRECOGNIZED_URI, (uri).c_str());
  236. }
  237. }
  238. };
  239. int32_t downloadUriList(Option* op, std::istream& in)
  240. {
  241. UriListParser p;
  242. RequestGroups groups;
  243. while(in) {
  244. std::deque<std::string> uris = p.parseNext(in);
  245. if(uris.size() == 1 && op->get(PREF_PARAMETERIZED_URI) == V_TRUE) {
  246. std::deque<std::string> unfoldedURIs = unfoldURI(uris);
  247. std::for_each(unfoldedURIs.begin(), unfoldedURIs.end(),
  248. AccRequestGroup(groups, op));
  249. } else if(uris.size() == 1) {
  250. std::for_each(uris.begin(), uris.end(), AccRequestGroup(groups, op));
  251. } else if(!uris.empty()) {
  252. size_t numSplit = op->getAsInt(PREF_SPLIT);
  253. if(uris.size() >= numSplit) {
  254. SharedHandle<RequestGroup> rg = createRequestGroup(op, uris);
  255. rg->setNumConcurrentCommand(numSplit);
  256. groups.push_back(rg);
  257. } else {
  258. std::deque<std::string> xuris;
  259. ncopy(uris.begin(), uris.end(), numSplit, std::back_inserter(xuris));
  260. xuris.erase(xuris.begin()+numSplit, xuris.end());
  261. SharedHandle<RequestGroup> rg = createRequestGroup(op, xuris);
  262. rg->setNumConcurrentCommand(numSplit);
  263. groups.push_back(rg);
  264. }
  265. }
  266. }
  267. return MultiUrlRequestInfo(groups, op, getStatCalc(op), getSummaryOut(op)).execute();
  268. }
  269. int32_t downloadUriList(Option* op)
  270. {
  271. if(op->get(PREF_INPUT_FILE) == "-") {
  272. return downloadUriList(op, std::cin);
  273. } else {
  274. if(!File(op->get(PREF_INPUT_FILE)).isFile()) {
  275. throw FatalException
  276. (StringFormat(EX_FILE_OPEN, op->get(PREF_INPUT_FILE).c_str(),
  277. "No such file").str());
  278. }
  279. std::ifstream f(op->get(PREF_INPUT_FILE).c_str());
  280. return downloadUriList(op, f);
  281. }
  282. }
  283. class StreamProtocolFilter {
  284. private:
  285. ProtocolDetector _detector;
  286. public:
  287. bool operator()(const std::string& uri) {
  288. return _detector.isStreamProtocol(uri);
  289. }
  290. };
  291. int32_t downloadUri(Option* op, const std::deque<std::string>& uris)
  292. {
  293. std::deque<std::string> nargs;
  294. if(op->get(PREF_PARAMETERIZED_URI) == V_TRUE) {
  295. nargs = unfoldURI(uris);
  296. } else {
  297. nargs = uris;
  298. }
  299. RequestGroups groups;
  300. if(op->get(PREF_FORCE_SEQUENTIAL) == V_TRUE) {
  301. std::for_each(nargs.begin(), nargs.end(), AccRequestGroup(groups, op));
  302. } else {
  303. std::deque<std::string>::iterator strmProtoEnd =
  304. std::stable_partition(nargs.begin(), nargs.end(), StreamProtocolFilter());
  305. // let's process http/ftp protocols first.
  306. size_t numSplit = op->getAsInt(PREF_SPLIT);
  307. size_t numURIs = std::distance(nargs.begin(), strmProtoEnd);
  308. if(numURIs >= numSplit) {
  309. std::deque<std::string> xargs(nargs.begin(), strmProtoEnd);
  310. RequestGroupHandle rg = createRequestGroup(op, xargs, op->get(PREF_OUT));
  311. rg->setNumConcurrentCommand(numSplit);
  312. groups.push_back(rg);
  313. } else if(numURIs > 0) {
  314. std::deque<std::string> xargs;
  315. ncopy(nargs.begin(), strmProtoEnd, numSplit, std::back_inserter(xargs));
  316. xargs.erase(xargs.begin()+numSplit, xargs.end());
  317. RequestGroupHandle rg = createRequestGroup(op, xargs, op->get(PREF_OUT));
  318. rg->setNumConcurrentCommand(numSplit);
  319. groups.push_back(rg);
  320. }
  321. // process remaining URIs(local metalink, BitTorrent files)
  322. std::for_each(strmProtoEnd, nargs.end(), AccRequestGroup(groups, op));
  323. }
  324. return MultiUrlRequestInfo(groups, op, getStatCalc(op), getSummaryOut(op)).execute();
  325. }
  326. int main(int argc, char* argv[])
  327. {
  328. Option* op = option_processing(argc, argv);
  329. std::deque<std::string> args(argv+optind, argv+argc);
  330. SimpleRandomizer::init();
  331. BitfieldManFactory::setDefaultRandomizer(SimpleRandomizer::getInstance());
  332. if(op->get(PREF_LOG) == "-") {
  333. LogFactory::setLogFile(DEV_STDOUT);
  334. } else if(!op->get(PREF_LOG).empty()) {
  335. LogFactory::setLogFile(op->get(PREF_LOG));
  336. } else {
  337. LogFactory::setLogFile(DEV_NULL);
  338. }
  339. LogFactory::setLogLevel(op->get(PREF_LOG_LEVEL));
  340. if(op->getAsBool(PREF_QUIET)) {
  341. LogFactory::setConsoleOutput(false);
  342. }
  343. int32_t exitStatus = EXIT_SUCCESS;
  344. try {
  345. Logger* logger = LogFactory::getInstance();
  346. logger->info("<<--- --- --- ---");
  347. logger->info(" --- --- --- ---");
  348. logger->info(" --- --- --- --->>");
  349. logger->info("%s %s %s", PACKAGE, PACKAGE_VERSION, TARGET);
  350. logger->info(MSG_LOGGING_STARTED);
  351. AuthConfigFactoryHandle authConfigFactory(new AuthConfigFactory(op));
  352. File netrccf(op->get(PREF_NETRC_PATH));
  353. if(!op->getAsBool(PREF_NO_NETRC) && netrccf.isFile()) {
  354. mode_t mode = netrccf.mode();
  355. if(mode&(S_IRWXG|S_IRWXO)) {
  356. logger->notice(MSG_INCORRECT_NETRC_PERMISSION,
  357. op->get(PREF_NETRC_PATH).c_str());
  358. } else {
  359. NetrcHandle netrc(new Netrc());
  360. netrc->parse(op->get(PREF_NETRC_PATH));
  361. authConfigFactory->setNetrc(netrc);
  362. }
  363. }
  364. AuthConfigFactorySingleton::instance(authConfigFactory);
  365. CUIDCounterHandle cuidCounter(new CUIDCounter());
  366. CUIDCounterSingletonHolder::instance(cuidCounter);
  367. #ifdef ENABLE_MESSAGE_DIGEST
  368. MessageDigestHelper::staticSHA1DigestInit();
  369. #endif // ENABLE_MESSAGE_DIGEST
  370. #ifdef SIGPIPE
  371. Util::setGlobalSignalHandler(SIGPIPE, SIG_IGN, 0);
  372. #endif
  373. int32_t returnValue = 0;
  374. #ifdef ENABLE_BITTORRENT
  375. if(op->defined(PREF_TORRENT_FILE)) {
  376. if(op->get(PREF_SHOW_FILES) == V_TRUE) {
  377. DefaultBtContextHandle btContext(new DefaultBtContext());
  378. btContext->load(op->get(PREF_TORRENT_FILE));
  379. std::cout << btContext << std::endl;
  380. } else {
  381. returnValue = downloadBitTorrent(op, args);
  382. }
  383. }
  384. else
  385. #endif // ENABLE_BITTORRENT
  386. #ifdef ENABLE_METALINK
  387. if(op->defined(PREF_METALINK_FILE)) {
  388. if(op->get(PREF_SHOW_FILES) == V_TRUE) {
  389. std::deque<SharedHandle<MetalinkEntry> > metalinkEntries;
  390. MetalinkHelper::parseAndQuery(metalinkEntries,
  391. op->get(PREF_METALINK_FILE), op);
  392. std::deque<SharedHandle<FileEntry> > fileEntries;
  393. MetalinkEntry::toFileEntry(fileEntries, metalinkEntries);
  394. Util::toStream(std::cout, fileEntries);
  395. } else {
  396. returnValue = downloadMetalink(op);
  397. }
  398. }
  399. else
  400. #endif // ENABLE_METALINK
  401. if(op->defined(PREF_INPUT_FILE)) {
  402. returnValue = downloadUriList(op);
  403. } else {
  404. returnValue = downloadUri(op, args);
  405. }
  406. if(returnValue == 1) {
  407. exitStatus = EXIT_FAILURE;
  408. }
  409. } catch(Exception& ex) {
  410. std::cerr << EX_EXCEPTION_CAUGHT << "\n" << ex.stackTrace() << std::endl;
  411. exitStatus = EXIT_FAILURE;
  412. }
  413. delete op;
  414. LogFactory::release();
  415. return exitStatus;
  416. }
  417. } // namespace aria2
  418. int main(int argc, char* argv[]) {
  419. aria2::Platform platform;
  420. int r = aria2::main(argc, argv);
  421. return r;
  422. }