aria2api.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2013 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 "aria2api.h"
  36. #include <functional>
  37. #include "Platform.h"
  38. #include "Context.h"
  39. #include "DownloadEngine.h"
  40. #include "OptionParser.h"
  41. #include "Option.h"
  42. #include "DlAbortEx.h"
  43. #include "fmt.h"
  44. #include "OptionHandler.h"
  45. #include "RequestGroupMan.h"
  46. #include "RequestGroup.h"
  47. #include "MultiUrlRequestInfo.h"
  48. #include "prefs.h"
  49. #include "download_helper.h"
  50. #include "LogFactory.h"
  51. #include "PieceStorage.h"
  52. #include "DownloadContext.h"
  53. #include "FileEntry.h"
  54. #include "BitfieldMan.h"
  55. #include "DownloadContext.h"
  56. #include "RpcMethodImpl.h"
  57. namespace aria2 {
  58. Session::Session(const KeyVals& options)
  59. : context(new Context(false, 0, 0, options))
  60. {}
  61. Session::~Session()
  62. {}
  63. namespace {
  64. Platform* platform = 0;
  65. } // namespace
  66. int libraryInit()
  67. {
  68. platform = new Platform();
  69. return 0;
  70. }
  71. int libraryDeinit()
  72. {
  73. delete platform;
  74. return 0;
  75. }
  76. Session* sessionNew(const KeyVals& options)
  77. {
  78. int rv;
  79. Session* session = new Session(options);
  80. if(session->context->reqinfo) {
  81. rv = session->context->reqinfo->prepare();
  82. if(rv != 0) {
  83. delete session;
  84. session = 0;
  85. }
  86. } else {
  87. delete session;
  88. session = 0;
  89. }
  90. return session;
  91. }
  92. int sessionFinal(Session* session)
  93. {
  94. error_code::Value rv = session->context->reqinfo->getResult();
  95. delete session;
  96. return rv;
  97. }
  98. int sessionConfigSetKeepRunning(Session* session, bool flag)
  99. {
  100. session->context->reqinfo->getDownloadEngine()->getRequestGroupMan()
  101. ->setKeepRunning(flag);
  102. return 0;
  103. }
  104. int run(Session* session, RUN_MODE mode)
  105. {
  106. const SharedHandle<DownloadEngine>& e =
  107. session->context->reqinfo->getDownloadEngine();
  108. return e->run(mode == RUN_ONCE);
  109. }
  110. int shutdown(Session* session, bool force)
  111. {
  112. const SharedHandle<DownloadEngine>& e =
  113. session->context->reqinfo->getDownloadEngine();
  114. if(force) {
  115. e->requestForceHalt();
  116. } else {
  117. e->requestHalt();
  118. }
  119. return 0;
  120. }
  121. std::string gidToHex(const A2Gid& gid)
  122. {
  123. return GroupId::toHex(gid);
  124. }
  125. A2Gid hexToGid(const std::string& hex)
  126. {
  127. A2Gid gid;
  128. if(GroupId::toNumericId(gid, hex.c_str()) == 0) {
  129. return gid;
  130. } else {
  131. return 0;
  132. }
  133. }
  134. bool isNull(const A2Gid& gid)
  135. {
  136. return gid == 0;
  137. }
  138. namespace {
  139. template<typename InputIterator, typename Pred>
  140. void apiGatherOption
  141. (InputIterator first, InputIterator last,
  142. Pred pred,
  143. Option* option,
  144. const SharedHandle<OptionParser>& optionParser)
  145. {
  146. for(; first != last; ++first) {
  147. const std::string& optionName = (*first).first;
  148. const Pref* pref = option::k2p(optionName);
  149. if(!pref) {
  150. throw DL_ABORT_EX
  151. (fmt("We don't know how to deal with %s option", optionName.c_str()));
  152. }
  153. const OptionHandler* handler = optionParser->find(pref);
  154. if(!handler || !pred(handler)) {
  155. // Just ignore the unacceptable options in this context.
  156. continue;
  157. }
  158. handler->parse(*option, (*first).second);
  159. }
  160. }
  161. } // namespace
  162. namespace {
  163. void apiGatherRequestOption(Option* option, const KeyVals& options,
  164. const SharedHandle<OptionParser>& optionParser)
  165. {
  166. apiGatherOption(options.begin(), options.end(),
  167. std::mem_fun(&OptionHandler::getInitialOption),
  168. option, optionParser);
  169. }
  170. } // namespace
  171. namespace {
  172. void addRequestGroup(const SharedHandle<RequestGroup>& group,
  173. const SharedHandle<DownloadEngine>& e,
  174. int position)
  175. {
  176. if(position >= 0) {
  177. e->getRequestGroupMan()->insertReservedGroup(position, group);
  178. } else {
  179. e->getRequestGroupMan()->addReservedGroup(group);
  180. }
  181. }
  182. } // namespace
  183. int addUri(Session* session,
  184. A2Gid& gid,
  185. const std::vector<std::string>& uris,
  186. const KeyVals& options,
  187. int position)
  188. {
  189. const SharedHandle<DownloadEngine>& e =
  190. session->context->reqinfo->getDownloadEngine();
  191. SharedHandle<Option> requestOption(new Option(*e->getOption()));
  192. try {
  193. apiGatherRequestOption(requestOption.get(), options,
  194. OptionParser::getInstance());
  195. } catch(RecoverableException& e) {
  196. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
  197. return -1;
  198. }
  199. std::vector<SharedHandle<RequestGroup> > result;
  200. createRequestGroupForUri(result, requestOption, uris,
  201. /* ignoreForceSeq = */ true,
  202. /* ignoreLocalPath = */ true);
  203. if(!result.empty()) {
  204. gid = result.front()->getGID();
  205. addRequestGroup(result.front(), e, position);
  206. }
  207. return 0;
  208. }
  209. int addMetalink(Session* session,
  210. std::vector<A2Gid>& gids,
  211. const std::string& metalinkFile,
  212. const KeyVals& options,
  213. int position)
  214. {
  215. #ifdef ENABLE_METALINK
  216. const SharedHandle<DownloadEngine>& e =
  217. session->context->reqinfo->getDownloadEngine();
  218. SharedHandle<Option> requestOption(new Option(*e->getOption()));
  219. std::vector<SharedHandle<RequestGroup> > result;
  220. try {
  221. apiGatherRequestOption(requestOption.get(), options,
  222. OptionParser::getInstance());
  223. requestOption->put(PREF_METALINK_FILE, metalinkFile);
  224. createRequestGroupForMetalink(result, requestOption);
  225. } catch(RecoverableException& e) {
  226. A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, e);
  227. return -1;
  228. }
  229. if(!result.empty()) {
  230. if(position >= 0) {
  231. e->getRequestGroupMan()->insertReservedGroup(position, result);
  232. } else {
  233. e->getRequestGroupMan()->addReservedGroup(result);
  234. }
  235. for(std::vector<SharedHandle<RequestGroup> >::const_iterator i =
  236. result.begin(), eoi = result.end(); i != eoi; ++i) {
  237. gids.push_back((*i)->getGID());
  238. }
  239. }
  240. return 0;
  241. #else // !ENABLE_METALINK
  242. return -1;
  243. #endif // !ENABLE_METALINK
  244. }
  245. int removeDownload(Session* session, const A2Gid& gid, bool force)
  246. {
  247. const SharedHandle<DownloadEngine>& e =
  248. session->context->reqinfo->getDownloadEngine();
  249. SharedHandle<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid);
  250. if(group) {
  251. if(group->getState() == RequestGroup::STATE_ACTIVE) {
  252. if(force) {
  253. group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
  254. } else {
  255. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  256. }
  257. e->setRefreshInterval(0);
  258. } else {
  259. if(group->isDependencyResolved()) {
  260. e->getRequestGroupMan()->removeReservedGroup(gid);
  261. } else {
  262. return -1;
  263. }
  264. }
  265. } else {
  266. return -1;
  267. }
  268. return 0;
  269. }
  270. int pauseDownload(Session* session, const A2Gid& gid, bool force)
  271. {
  272. const SharedHandle<DownloadEngine>& e =
  273. session->context->reqinfo->getDownloadEngine();
  274. SharedHandle<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid);
  275. if(group) {
  276. bool reserved = group->getState() == RequestGroup::STATE_WAITING;
  277. if(pauseRequestGroup(group, reserved, force)) {
  278. e->setRefreshInterval(0);
  279. return 0;
  280. }
  281. }
  282. return -1;
  283. }
  284. int unpauseDownload(Session* session, const A2Gid& gid)
  285. {
  286. const SharedHandle<DownloadEngine>& e =
  287. session->context->reqinfo->getDownloadEngine();
  288. SharedHandle<RequestGroup> group = e->getRequestGroupMan()->findGroup(gid);
  289. if(!group ||
  290. group->getState() != RequestGroup::STATE_WAITING ||
  291. !group->isPauseRequested()) {
  292. return -1;
  293. } else {
  294. group->setPauseRequested(false);
  295. e->getRequestGroupMan()->requestQueueCheck();
  296. }
  297. return 0;
  298. }
  299. std::vector<A2Gid> getActiveDownload(Session* session)
  300. {
  301. const SharedHandle<DownloadEngine>& e =
  302. session->context->reqinfo->getDownloadEngine();
  303. const RequestGroupList& groups = e->getRequestGroupMan()->getRequestGroups();
  304. std::vector<A2Gid> res;
  305. for(RequestGroupList::const_iterator i = groups.begin(),
  306. eoi = groups.end(); i != eoi; ++i) {
  307. res.push_back((*i)->getGID());
  308. }
  309. return res;
  310. }
  311. namespace {
  312. template<typename OutputIterator, typename InputIterator>
  313. void createUriEntry
  314. (OutputIterator out,
  315. InputIterator first, InputIterator last,
  316. UriStatus status)
  317. {
  318. for(; first != last; ++first) {
  319. UriData uriData;
  320. uriData.uri = *first;
  321. uriData.status = status;
  322. out++ = uriData;
  323. }
  324. }
  325. } // namespace
  326. namespace {
  327. template<typename OutputIterator>
  328. void createUriEntry
  329. (OutputIterator out, const SharedHandle<FileEntry>& file)
  330. {
  331. createUriEntry(out,
  332. file->getSpentUris().begin(),
  333. file->getSpentUris().end(),
  334. URI_USED);
  335. createUriEntry(out,
  336. file->getRemainingUris().begin(),
  337. file->getRemainingUris().end(),
  338. URI_WAITING);
  339. }
  340. } // namespace
  341. namespace {
  342. template<typename OutputIterator, typename InputIterator>
  343. void createFileEntry
  344. (OutputIterator out,
  345. InputIterator first, InputIterator last,
  346. const BitfieldMan* bf)
  347. {
  348. size_t index = 1;
  349. for(; first != last; ++first) {
  350. FileData file;
  351. file.index = index++;
  352. file.path = (*first)->getPath();
  353. file.length = (*first)->getLength();
  354. file.completedLength = bf->getOffsetCompletedLength
  355. ((*first)->getOffset(), (*first)->getLength());
  356. file.selected = (*first)->isRequested();
  357. createUriEntry(std::back_inserter(file.uris), *first);
  358. out++ = file;
  359. }
  360. }
  361. } // namespace
  362. namespace {
  363. template<typename OutputIterator, typename InputIterator>
  364. void createFileEntry
  365. (OutputIterator out,
  366. InputIterator first, InputIterator last,
  367. int64_t totalLength,
  368. int32_t pieceLength,
  369. const std::string& bitfield)
  370. {
  371. BitfieldMan bf(pieceLength, totalLength);
  372. bf.setBitfield(reinterpret_cast<const unsigned char*>(bitfield.data()),
  373. bitfield.size());
  374. createFileEntry(out, first, last, &bf);
  375. }
  376. } // namespace
  377. namespace {
  378. template<typename OutputIterator, typename InputIterator>
  379. void createFileEntry
  380. (OutputIterator out,
  381. InputIterator first, InputIterator last,
  382. int64_t totalLength,
  383. int32_t pieceLength,
  384. const SharedHandle<PieceStorage>& ps)
  385. {
  386. BitfieldMan bf(pieceLength, totalLength);
  387. if(ps) {
  388. bf.setBitfield(ps->getBitfield(), ps->getBitfieldLength());
  389. }
  390. createFileEntry(out, first, last, &bf);
  391. }
  392. } // namespace
  393. namespace {
  394. struct RequestGroupDH : public DownloadHandle {
  395. RequestGroupDH(const SharedHandle<RequestGroup>& group)
  396. : group(group),
  397. ts(group->calculateStat())
  398. {}
  399. virtual ~RequestGroupDH() {}
  400. virtual DownloadStatus getStatus()
  401. {
  402. if(group->getState() == RequestGroup::STATE_ACTIVE) {
  403. return DOWNLOAD_ACTIVE;
  404. } else {
  405. if(group->isPauseRequested()) {
  406. return DOWNLOAD_PAUSED;
  407. } else {
  408. return DOWNLOAD_WAITING;
  409. }
  410. }
  411. }
  412. virtual int64_t getTotalLength()
  413. {
  414. return group->getTotalLength();
  415. }
  416. virtual int64_t getCompletedLength()
  417. {
  418. return group->getCompletedLength();
  419. }
  420. virtual int64_t getUploadLength()
  421. {
  422. return ts.allTimeUploadLength;
  423. }
  424. virtual std::string getBitfield()
  425. {
  426. const SharedHandle<PieceStorage>& ps = group->getPieceStorage();
  427. if(ps) {
  428. return std::string(reinterpret_cast<const char*>(ps->getBitfield()),
  429. ps->getBitfieldLength());
  430. } else {
  431. return "";
  432. }
  433. }
  434. virtual int getDownloadSpeed()
  435. {
  436. return ts.downloadSpeed;
  437. }
  438. virtual int getUploadSpeed()
  439. {
  440. return ts.uploadSpeed;
  441. }
  442. virtual size_t getNumPieces()
  443. {
  444. return group->getDownloadContext()->getNumPieces();
  445. }
  446. virtual int getConnections()
  447. {
  448. return group->getNumConnection();
  449. }
  450. virtual int getErrorCode()
  451. {
  452. return 0;
  453. }
  454. virtual const std::vector<A2Gid>& getFollowedBy()
  455. {
  456. return group->followedBy();
  457. }
  458. virtual A2Gid getBelongsTo()
  459. {
  460. return group->belongsTo();
  461. }
  462. virtual const std::string& getDir()
  463. {
  464. return group->getOption()->get(PREF_DIR);
  465. }
  466. virtual std::vector<FileData> getFiles()
  467. {
  468. std::vector<FileData> res;
  469. const SharedHandle<DownloadContext>& dctx = group->getDownloadContext();
  470. createFileEntry(std::back_inserter(res),
  471. dctx->getFileEntries().begin(),
  472. dctx->getFileEntries().end(),
  473. dctx->getTotalLength(), dctx->getPieceLength(),
  474. group->getPieceStorage());
  475. return res;
  476. }
  477. SharedHandle<RequestGroup> group;
  478. TransferStat ts;
  479. };
  480. } // namespace
  481. namespace {
  482. struct DownloadResultDH : public DownloadHandle {
  483. DownloadResultDH(const SharedHandle<DownloadResult>& dr)
  484. : dr(dr)
  485. {}
  486. virtual ~DownloadResultDH() {}
  487. virtual DownloadStatus getStatus()
  488. {
  489. switch(dr->result) {
  490. case error_code::FINISHED:
  491. return DOWNLOAD_COMPLETE;
  492. case error_code::REMOVED:
  493. return DOWNLOAD_REMOVED;
  494. default:
  495. return DOWNLOAD_ERROR;
  496. }
  497. }
  498. virtual int64_t getTotalLength()
  499. {
  500. return dr->totalLength;
  501. }
  502. virtual int64_t getCompletedLength()
  503. {
  504. return dr->completedLength;
  505. }
  506. virtual int64_t getUploadLength()
  507. {
  508. return dr->uploadLength;
  509. }
  510. virtual std::string getBitfield()
  511. {
  512. return dr->bitfield;
  513. }
  514. virtual int getDownloadSpeed()
  515. {
  516. return 0;
  517. }
  518. virtual int getUploadSpeed()
  519. {
  520. return 0;
  521. }
  522. virtual size_t getNumPieces()
  523. {
  524. return dr->numPieces;
  525. }
  526. virtual int getConnections()
  527. {
  528. return 0;
  529. }
  530. virtual int getErrorCode()
  531. {
  532. return dr->result;
  533. }
  534. virtual const std::vector<A2Gid>& getFollowedBy()
  535. {
  536. return dr->followedBy;
  537. }
  538. virtual A2Gid getBelongsTo()
  539. {
  540. return dr->belongsTo;
  541. }
  542. virtual const std::string& getDir()
  543. {
  544. return dr->dir;
  545. }
  546. virtual std::vector<FileData> getFiles()
  547. {
  548. std::vector<FileData> res;
  549. createFileEntry(std::back_inserter(res),
  550. dr->fileEntries.begin(), dr->fileEntries.end(),
  551. dr->totalLength, dr->pieceLength, dr->bitfield);
  552. return res;
  553. }
  554. SharedHandle<DownloadResult> dr;
  555. };
  556. } // namespace
  557. DownloadHandle* getDownloadHandle(Session* session, const A2Gid& gid)
  558. {
  559. const SharedHandle<DownloadEngine>& e =
  560. session->context->reqinfo->getDownloadEngine();
  561. const SharedHandle<RequestGroupMan>& rgman = e->getRequestGroupMan();
  562. SharedHandle<RequestGroup> group = rgman->findGroup(gid);
  563. if(group) {
  564. return new RequestGroupDH(group);
  565. } else {
  566. SharedHandle<DownloadResult> ds = rgman->findDownloadResult(gid);
  567. if(ds) {
  568. return new DownloadResultDH(ds);
  569. }
  570. }
  571. return 0;
  572. }
  573. void deleteDownloadHandle(DownloadHandle* dh)
  574. {
  575. delete dh;
  576. }
  577. } // namespace aria2