main.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - a simple utility for downloading files faster
  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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. /* copyright --> */
  22. #include "HttpInitiateConnectionCommand.h"
  23. #include "DownloadEngine.h"
  24. #include "SegmentMan.h"
  25. #include "SplitSlowestSegmentSplitter.h"
  26. #include "SimpleLogger.h"
  27. #include "common.h"
  28. #include "DefaultDiskWriter.h"
  29. #include "Util.h"
  30. #include "InitiateConnectionCommandFactory.h"
  31. #include "prefs.h"
  32. #include <vector>
  33. #include <algorithm>
  34. #include <signal.h>
  35. #include <unistd.h>
  36. #include <libgen.h>
  37. #include <utility>
  38. extern char* optarg;
  39. extern int optind, opterr, optopt;
  40. #include <getopt.h>
  41. #ifdef HAVE_LIBSSL
  42. // for SSL
  43. # include <openssl/err.h>
  44. # include <openssl/ssl.h>
  45. #endif // HAVE_LIBSSL
  46. using namespace std;
  47. void clearRequest(Request* req) {
  48. delete(req);
  49. }
  50. DownloadEngine* e;
  51. void handler(int signal) {
  52. cout << "\nSIGINT signal received." << endl;
  53. e->segmentMan->save();
  54. if(e->diskWriter != NULL) {
  55. e->diskWriter->closeFile();
  56. }
  57. exit(0);
  58. }
  59. void addCommand(int cuid, const char* url, string referer, vector<Request*> requests) {
  60. Request* req = new Request();
  61. req->setReferer(referer);
  62. if(req->setUrl(url)) {
  63. e->commands.push(InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e));
  64. requests.push_back(req);
  65. } else {
  66. cerr << "Unrecognized URL or unsupported protocol: " << req->getUrl() << endl;
  67. delete(req);
  68. }
  69. }
  70. void showVersion() {
  71. cout << PACKAGE_NAME << " version " << PACKAGE_VERSION << endl;
  72. cout << "Copyright (C) 2006 Tatsuhiro Tsujikawa" << endl;
  73. cout << endl;
  74. cout << "This program is free software; you can redistribute it and/or modify" << endl;
  75. cout << "it under the terms of the GNU General Public License as published by" << endl;
  76. cout << "the Free Software Foundation; either version 2 of the License, or" << endl;
  77. cout << "(at your option) any later version." << endl;
  78. cout << endl;
  79. cout << "This program is distributed in the hope that it will be useful," << endl;
  80. cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl;
  81. cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << endl;
  82. cout << "GNU General Public License for more details." << endl;
  83. cout << endl;
  84. cout << "You should have received a copy of the GNU General Public License" << endl;
  85. cout << "along with this program; if not, write to the Free Software" << endl;
  86. cout << "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA" << endl;
  87. cout << endl;
  88. cout << "Contact Info: Tasuhiro Tsujikawa <tujikawa at users dot sourceforge dot net>" << endl;
  89. cout << endl;
  90. }
  91. void showUsage() {
  92. cout << endl;
  93. cout << "Usage: " << PACKAGE_NAME << " [options] URL ..." << endl;
  94. cout << endl;
  95. cout << "Options:" << endl;
  96. cout << " -d, --dir=DIR The directory to store downloaded file." << endl;
  97. cout << " -o, --out=FILE The file name for downloaded file." << endl;
  98. cout << " -l, --log=LOG The file path to store log. If '-' is specified," << endl;
  99. cout << " log is written to stdout." << endl;
  100. cout << " -D, --daemon Run as daemon." << endl;
  101. cout << " -s, --split=N Download a file using N connections. N must be" << endl;
  102. cout << " between 1 and 5. This option affects all URLs." << endl;
  103. cout << " Thus, aria2 connects to each URL with N connections." << endl;
  104. cout << " --retry-wait=SEC Set amount of time in second between requests" << endl;
  105. cout << " for errors. Specify a value between 0 and 60." << endl;
  106. cout << " Default: 5" << endl;
  107. cout << " -t, --timeout=SEC Set timeout in second. Default: 60" << endl;
  108. cout << " -m, --max-tries=N Set number of tries. 0 means unlimited." << endl;
  109. cout << " Default: 5" << endl;
  110. cout << " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append" << endl;
  111. cout << " K or M(1K = 1024, 1M = 1024K)." << endl;
  112. cout << " --http-proxy=HOST:PORT Use HTTP proxy server. This affects to all" << endl;
  113. cout << " URLs." << endl;
  114. cout << " --http-user=USER Set HTTP user. This affects to all URLs." << endl;
  115. cout << " --http-passwd=PASSWD Set HTTP password. This affects to all URLs." << endl;
  116. cout << " --http-proxy-user=USER Set HTTP proxy user. This affects to all URLs" << endl;
  117. cout << " --http-proxy-passwd=PASSWD Set HTTP proxy password. This affects to all URLs." << endl;
  118. cout << " --http-proxy-method=METHOD Set the method to use in proxy request." << endl;
  119. cout << " METHOD is either 'get' or 'tunnel'." << endl;
  120. cout << " Default: tunnel" << endl;
  121. cout << " --http-auth-scheme=SCHEME Set HTTP authentication scheme. Currently, basic" << endl;
  122. cout << " is the only supported scheme. You MUST specify" << endl;
  123. cout << " this option in order to use HTTP authentication" << endl;
  124. cout << " as well as --http-proxy option." << endl;
  125. cout << " --referer=REFERER Set Referer. This affects to all URLs." << endl;
  126. cout << " --ftp-user=USER Set FTP user. This affects to all URLs." << endl;
  127. cout << " Default: anonymous" << endl;
  128. cout << " --ftp-passwd=PASSWD Set FTP password. This affects to all URLs." << endl;
  129. cout << " Default: ARIA2USER@" << endl;
  130. cout << " --ftp-type=TYPE Set FTP transfer type. TYPE is either 'binary'" << endl;
  131. cout << " or 'ascii'." << endl;
  132. cout << " Default: binary" << endl;
  133. cout << " -p, --ftp-pasv Use passive mode in FTP." << endl;
  134. cout << " --ftp-via-http-proxy=METHOD Use HTTP proxy in FTP. METHOD is either 'get' or" << endl;
  135. cout << " 'tunnel'." << endl;
  136. cout << " Default: tunnel" << endl;
  137. cout << " -v, --version Print the version number and exit." << endl;
  138. cout << " -h, --help Print this message and exit." << endl;
  139. cout << endl;
  140. cout << "URL:" << endl;
  141. cout << " You can specify multiple URLs. All URLs must point to the same file" << endl;
  142. cout << " or downloading fails." << endl;
  143. cout << endl;
  144. cout << "Examples:" << endl;
  145. cout << " Download a file by 1 connection:" << endl;
  146. cout << " aria2c http://AAA.BBB.CCC/file.zip" << endl;
  147. cout << " Download a file by 2 connections:" << endl;
  148. cout << " aria2c -s 2 http://AAA.BBB.CCC/file.zip" << endl;
  149. cout << " Download a file by 2 connections, each connects to a different server:" << endl;
  150. cout << " aria2c http://AAA.BBB.CCC/file.zip http://DDD.EEE.FFF/GGG/file.zip" << endl;
  151. cout << " You can mix up different protocols:" << endl;
  152. cout << " aria2c http://AAA.BBB.CCC/file.zip ftp://DDD.EEE.FFF/GGG/file.zip" << endl;
  153. cout << endl;
  154. cout << "Reports bugs to <tujikawa at rednoah dot com>" << endl;
  155. }
  156. int main(int argc, char* argv[]) {
  157. bool stdoutLog = false;
  158. string logfile;
  159. string dir;
  160. string ufilename;
  161. int split = 1;
  162. bool daemonMode = false;
  163. string referer;
  164. int c;
  165. Option* op = new Option();
  166. op->put(PREF_RETRY_WAIT, "5");
  167. op->put(PREF_TIMEOUT, "60");
  168. op->put(PREF_MIN_SEGMENT_SIZE, "1048576");// 1M
  169. op->put(PREF_MAX_TRIES, "5");
  170. op->put(PREF_HTTP_PROXY_METHOD, V_TUNNEL);
  171. op->put(PREF_FTP_USER, "anonymous");
  172. op->put(PREF_FTP_PASSWD, "ARIA2USER@");
  173. op->put(PREF_FTP_TYPE, V_BINARY);
  174. op->put(PREF_FTP_VIA_HTTP_PROXY, V_TUNNEL);
  175. while(1) {
  176. int optIndex = 0;
  177. int lopt;
  178. static struct option longOpts[] = {
  179. { "daemon", no_argument, NULL, 'D' },
  180. { "dir", required_argument, NULL, 'd' },
  181. { "out", required_argument, NULL, 'o' },
  182. { "log", required_argument, NULL, 'l' },
  183. { "split", required_argument, NULL, 's' },
  184. { "timeout", required_argument, NULL, 't' },
  185. { "max-retries", required_argument, NULL, 'm' },
  186. { "http-proxy", required_argument, &lopt, 1 },
  187. { "http-user", required_argument, &lopt, 2 },
  188. { "http-passwd", required_argument, &lopt, 3 },
  189. { "http-proxy-user", required_argument, &lopt, 4 },
  190. { "http-proxy-passwd", required_argument, &lopt, 5 },
  191. { "http-auth-scheme", required_argument, &lopt, 6 },
  192. { "referer", required_argument, &lopt, 7 },
  193. { "retry-wait", required_argument, &lopt, 8 },
  194. { "ftp-user", required_argument, &lopt, 9 },
  195. { "ftp-passwd", required_argument, &lopt, 10 },
  196. { "ftp-type", required_argument, &lopt, 11 },
  197. { "ftp-pasv", no_argument, NULL, 'p' },
  198. { "ftp-via-http-proxy", required_argument, &lopt, 12 },
  199. { "min-segment-size", required_argument, &lopt, 13 },
  200. { "http-proxy-method", required_argument, &lopt, 14 },
  201. { "version", no_argument, NULL, 'v' },
  202. { "help", no_argument, NULL, 'h' },
  203. { 0, 0, 0, 0 }
  204. };
  205. c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vh", longOpts, &optIndex);
  206. if(c == -1) {
  207. break;
  208. }
  209. switch(c) {
  210. case 0:{
  211. switch(lopt) {
  212. case 1: {
  213. pair<string, string> proxy;
  214. Util::split(proxy, optarg, ':');
  215. int port = (int)strtol(proxy.second.c_str(), NULL, 10);
  216. if(proxy.first.empty() || proxy.second.empty() ||
  217. !(0 < port && port <= 65535)) {
  218. cerr << "unrecognized proxy format" << endl;
  219. showUsage();
  220. exit(1);
  221. }
  222. op->put(PREF_HTTP_PROXY_HOST, proxy.first);
  223. op->put(PREF_HTTP_PROXY_PORT, Util::itos(port));
  224. op->put(PREF_HTTP_PROXY_ENABLED, V_TRUE);
  225. break;
  226. }
  227. case 2:
  228. op->put(PREF_HTTP_USER, optarg);
  229. break;
  230. case 3:
  231. op->put(PREF_HTTP_PASSWD, optarg);
  232. break;
  233. case 4:
  234. op->put(PREF_HTTP_PROXY_USER, optarg);
  235. op->put(PREF_HTTP_PROXY_AUTH_ENABLED, V_TRUE);
  236. break;
  237. case 5:
  238. op->put(PREF_HTTP_PROXY_PASSWD, optarg);
  239. break;
  240. case 6:
  241. if(string(V_BASIC) == optarg) {
  242. op->put(PREF_HTTP_AUTH_SCHEME, V_BASIC);
  243. } else {
  244. cerr << "Currently, supported authentication scheme is basic." << endl;
  245. }
  246. break;
  247. case 7:
  248. referer = optarg;
  249. break;
  250. case 8: {
  251. int wait = (int)strtol(optarg, NULL, 10);
  252. if(!(0 <= wait && wait <= 60)) {
  253. cerr << "retry-wait must be between 0 and 60." << endl;
  254. showUsage();
  255. exit(1);
  256. }
  257. op->put(PREF_RETRY_WAIT, Util::itos(wait));
  258. break;
  259. }
  260. case 9:
  261. op->put(PREF_FTP_USER, optarg);
  262. break;
  263. case 10:
  264. op->put(PREF_FTP_PASSWD, optarg);
  265. break;
  266. case 11:
  267. if(string(optarg) == V_BINARY || string(optarg) == V_ASCII) {
  268. op->put(PREF_FTP_TYPE, optarg);
  269. } else {
  270. cerr << "ftp-type must be either 'binary' or 'ascii'." << endl;
  271. showUsage();
  272. exit(1);
  273. }
  274. break;
  275. case 12:
  276. if(string(optarg) == V_GET || string(optarg) == V_TUNNEL) {
  277. op->put(PREF_FTP_VIA_HTTP_PROXY, optarg);
  278. } else {
  279. cerr << "ftp-via-http-proxy must be either 'get' or 'tunnel'." << endl;
  280. showUsage();
  281. exit(1);
  282. }
  283. break;
  284. case 13: {
  285. string::size_type p = string(optarg).find_first_of("KM");
  286. int mult = 1;
  287. if(p != string::npos) {
  288. if(optarg[p] == 'K') {
  289. mult = 1024;
  290. } else if(optarg[p] == 'M') {
  291. mult = 1024*1024;
  292. }
  293. optarg[p] = '\0';
  294. }
  295. long long int size = strtoll(optarg, NULL, 10)*mult;
  296. if(size <= 0) {
  297. cerr << "min-segment-size invalid" << endl;
  298. showUsage();
  299. exit(1);
  300. }
  301. op->put(PREF_MIN_SEGMENT_SIZE, Util::llitos(size));
  302. break;
  303. }
  304. case 14:
  305. if(string(optarg) == V_GET || string(optarg) == V_TUNNEL) {
  306. op->put(PREF_HTTP_PROXY_METHOD, optarg);
  307. } else {
  308. cerr << "http-proxy-method must be either 'get' or 'tunnel'." << endl;
  309. showUsage();
  310. exit(1);
  311. }
  312. break;
  313. }
  314. break;
  315. }
  316. case 'D':
  317. daemonMode = true;
  318. break;
  319. case 'd':
  320. dir = optarg;
  321. break;
  322. case 'o':
  323. ufilename = optarg;
  324. break;
  325. case 'l':
  326. if(strcmp("-", optarg) == 0) {
  327. stdoutLog = true;
  328. } else {
  329. logfile = optarg;
  330. }
  331. break;
  332. case 's':
  333. split = (int)strtol(optarg, NULL, 10);
  334. if(!(1 <= split && split <= 5)) {
  335. cerr << "split must be between 1 and 5." << endl;
  336. showUsage();
  337. exit(1);
  338. }
  339. break;
  340. case 't': {
  341. int timeout = (int)strtol(optarg, NULL, 10);
  342. if(1 <= timeout && timeout <= 600) {
  343. op->put(PREF_TIMEOUT, Util::itos(timeout));
  344. } else {
  345. cerr << "timeout must be between 1 and 600" << endl;
  346. showUsage();
  347. exit(1);
  348. }
  349. break;
  350. }
  351. case 'm': {
  352. int retries = (int)strtol(optarg, NULL, 10);
  353. if(retries < 0) {
  354. cerr << "max-retires invalid" << endl;
  355. showUsage();
  356. exit(1);
  357. }
  358. op->put(PREF_MAX_TRIES, Util::itos(retries));
  359. break;
  360. }
  361. case 'p':
  362. op->put(PREF_FTP_PASV_ENABLED, V_TRUE);
  363. break;
  364. case 'v':
  365. showVersion();
  366. exit(0);
  367. case 'h':
  368. showUsage();
  369. exit(0);
  370. default:
  371. showUsage();
  372. exit(1);
  373. }
  374. }
  375. if(optind == argc) {
  376. cerr << "specify at least one URL" << endl;
  377. showUsage();
  378. exit(1);
  379. }
  380. if(daemonMode) {
  381. if(daemon(1, 1) < 0) {
  382. perror("daemon failed");
  383. exit(1);
  384. }
  385. }
  386. #ifdef HAVE_LIBSSL
  387. // for SSL initialization
  388. SSL_load_error_strings();
  389. SSL_library_init();
  390. #endif // HAVE_LIBSSL
  391. SimpleLogger* logger;
  392. if(stdoutLog) {
  393. logger = new SimpleLogger(stdout);
  394. } else if(logfile.size()) {
  395. logger = new SimpleLogger(logfile);
  396. } else {
  397. logger = new SimpleLogger("/dev/null");
  398. }
  399. SegmentSplitter* splitter = new SplitSlowestSegmentSplitter();
  400. splitter->setMinSegmentSize(op->getAsLLInt(PREF_MIN_SEGMENT_SIZE));
  401. splitter->logger = logger;
  402. e = new DownloadEngine();
  403. e->logger = logger;
  404. e->option = op;
  405. e->diskWriter = new DefaultDiskWriter();
  406. e->segmentMan = new SegmentMan();
  407. e->segmentMan->dir = dir;
  408. e->segmentMan->ufilename = ufilename;
  409. e->segmentMan->logger = logger;
  410. e->segmentMan->option = op;
  411. e->segmentMan->splitter = splitter;
  412. vector<Request*> requests;
  413. for(int i = 1; optind+i-1 < argc; i++) {
  414. for(int s = 1; s <= split; s++) {
  415. addCommand(split*(i-1)+s, argv[optind+i-1], referer, requests);
  416. }
  417. }
  418. struct sigaction sigact;
  419. sigact.sa_handler = handler;
  420. sigact.sa_flags = 0;
  421. sigemptyset(&sigact.sa_mask);
  422. sigaction(SIGINT, &sigact, NULL);
  423. e->run();
  424. for_each(requests.begin(), requests.end(), clearRequest);
  425. requests.clear();
  426. delete(logger);
  427. delete(e->segmentMan);
  428. delete(e->option);
  429. delete(e->diskWriter);
  430. delete(e);
  431. return 0;
  432. }