RpcMethodImpl.cc 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2009 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 "RpcMethodImpl.h"
  36. #include <cassert>
  37. #include <algorithm>
  38. #include <sstream>
  39. #include "Logger.h"
  40. #include "LogFactory.h"
  41. #include "DlAbortEx.h"
  42. #include "Option.h"
  43. #include "OptionParser.h"
  44. #include "OptionHandler.h"
  45. #include "DownloadEngine.h"
  46. #include "RequestGroup.h"
  47. #include "download_helper.h"
  48. #include "util.h"
  49. #include "fmt.h"
  50. #include "RpcRequest.h"
  51. #include "PieceStorage.h"
  52. #include "DownloadContext.h"
  53. #include "DiskAdaptor.h"
  54. #include "FileEntry.h"
  55. #include "prefs.h"
  56. #include "message.h"
  57. #include "FeatureConfig.h"
  58. #include "array_fun.h"
  59. #include "RpcMethodFactory.h"
  60. #include "RpcResponse.h"
  61. #include "SegmentMan.h"
  62. #include "TimedHaltCommand.h"
  63. #include "PeerStat.h"
  64. #include "base64.h"
  65. #include "BitfieldMan.h"
  66. #include "SessionSerializer.h"
  67. #include "MessageDigest.h"
  68. #include "message_digest_helper.h"
  69. #include "OpenedFileCounter.h"
  70. #ifdef ENABLE_BITTORRENT
  71. #include "bittorrent_helper.h"
  72. #include "BtRegistry.h"
  73. #include "PeerStorage.h"
  74. #include "Peer.h"
  75. #include "BtRuntime.h"
  76. #include "BtAnnounce.h"
  77. #endif // ENABLE_BITTORRENT
  78. namespace aria2 {
  79. namespace rpc {
  80. namespace {
  81. const char VLB_TRUE[] = "true";
  82. const char VLB_FALSE[] = "false";
  83. const char VLB_ACTIVE[] = "active";
  84. const char VLB_WAITING[] = "waiting";
  85. const char VLB_PAUSED[] = "paused";
  86. const char VLB_REMOVED[] = "removed";
  87. const char VLB_ERROR[] = "error";
  88. const char VLB_COMPLETE[] = "complete";
  89. const char VLB_USED[] = "used";
  90. const char VLB_ZERO[] = "0";
  91. const char KEY_GID[] = "gid";
  92. const char KEY_ERROR_CODE[] = "errorCode";
  93. const char KEY_ERROR_MESSAGE[] = "errorMessage";
  94. const char KEY_STATUS[] = "status";
  95. const char KEY_TOTAL_LENGTH[] = "totalLength";
  96. const char KEY_COMPLETED_LENGTH[] = "completedLength";
  97. const char KEY_DOWNLOAD_SPEED[] = "downloadSpeed";
  98. const char KEY_UPLOAD_SPEED[] = "uploadSpeed";
  99. const char KEY_UPLOAD_LENGTH[] = "uploadLength";
  100. const char KEY_CONNECTIONS[] = "connections";
  101. const char KEY_BITFIELD[] = "bitfield";
  102. const char KEY_PIECE_LENGTH[] = "pieceLength";
  103. const char KEY_NUM_PIECES[] = "numPieces";
  104. const char KEY_FOLLOWED_BY[] = "followedBy";
  105. const char KEY_BELONGS_TO[] = "belongsTo";
  106. const char KEY_INFO_HASH[] = "infoHash";
  107. const char KEY_NUM_SEEDERS[] = "numSeeders";
  108. const char KEY_PEER_ID[] = "peerId";
  109. const char KEY_IP[] = "ip";
  110. const char KEY_PORT[] = "port";
  111. const char KEY_AM_CHOKING[] = "amChoking";
  112. const char KEY_PEER_CHOKING[] = "peerChoking";
  113. const char KEY_SEEDER[] = "seeder";
  114. const char KEY_INDEX[] = "index";
  115. const char KEY_PATH[] = "path";
  116. const char KEY_SELECTED[] = "selected";
  117. const char KEY_LENGTH[] = "length";
  118. const char KEY_URI[] = "uri";
  119. const char KEY_CURRENT_URI[] = "currentUri";
  120. const char KEY_VERSION[] = "version";
  121. const char KEY_ENABLED_FEATURES[] = "enabledFeatures";
  122. const char KEY_METHOD_NAME[] = "methodName";
  123. const char KEY_PARAMS[] = "params";
  124. const char KEY_SESSION_ID[] = "sessionId";
  125. const char KEY_FILES[] = "files";
  126. const char KEY_DIR[] = "dir";
  127. const char KEY_URIS[] = "uris";
  128. const char KEY_BITTORRENT[] = "bittorrent";
  129. const char KEY_INFO[] = "info";
  130. const char KEY_NAME[] = "name";
  131. const char KEY_ANNOUNCE_LIST[] = "announceList";
  132. const char KEY_COMMENT[] = "comment";
  133. const char KEY_CREATION_DATE[] = "creationDate";
  134. const char KEY_MODE[] = "mode";
  135. const char KEY_SERVERS[] = "servers";
  136. const char KEY_NUM_WAITING[] = "numWaiting";
  137. const char KEY_NUM_STOPPED[] = "numStopped";
  138. const char KEY_NUM_ACTIVE[] = "numActive";
  139. const char KEY_NUM_STOPPED_TOTAL[] = "numStoppedTotal";
  140. } // namespace
  141. namespace {
  142. std::unique_ptr<ValueBase> createGIDResponse(a2_gid_t gid)
  143. {
  144. return String::g(GroupId::toHex(gid));
  145. }
  146. } // namespace
  147. namespace {
  148. std::unique_ptr<ValueBase> createOKResponse() { return String::g("OK"); }
  149. } // namespace
  150. namespace {
  151. std::unique_ptr<ValueBase>
  152. addRequestGroup(const std::shared_ptr<RequestGroup>& group, DownloadEngine* e,
  153. bool posGiven, int pos)
  154. {
  155. if (posGiven) {
  156. e->getRequestGroupMan()->insertReservedGroup(pos, group);
  157. }
  158. else {
  159. e->getRequestGroupMan()->addReservedGroup(group);
  160. }
  161. return createGIDResponse(group->getGID());
  162. }
  163. } // namespace
  164. namespace {
  165. bool checkPosParam(const Integer* posParam)
  166. {
  167. if (posParam) {
  168. if (posParam->i() >= 0) {
  169. return true;
  170. }
  171. else {
  172. throw DL_ABORT_EX("Position must be greater than or equal to 0.");
  173. }
  174. }
  175. return false;
  176. }
  177. } // namespace
  178. namespace {
  179. a2_gid_t str2Gid(const String* str)
  180. {
  181. assert(str);
  182. if (str->s().size() > sizeof(a2_gid_t) * 2) {
  183. throw DL_ABORT_EX(fmt("Invalid GID %s", str->s().c_str()));
  184. }
  185. a2_gid_t n;
  186. switch (GroupId::expandUnique(n, str->s().c_str())) {
  187. case GroupId::ERR_NOT_UNIQUE:
  188. throw DL_ABORT_EX(fmt("GID %s is not unique", str->s().c_str()));
  189. case GroupId::ERR_NOT_FOUND:
  190. throw DL_ABORT_EX(fmt("GID %s is not found", str->s().c_str()));
  191. case GroupId::ERR_INVALID:
  192. throw DL_ABORT_EX(fmt("Invalid GID %s", str->s().c_str()));
  193. }
  194. return n;
  195. }
  196. } // namespace
  197. namespace {
  198. template <typename OutputIterator>
  199. void extractUris(OutputIterator out, const List* src)
  200. {
  201. if (src) {
  202. for (auto& elem : *src) {
  203. const String* uri = downcast<String>(elem);
  204. if (uri) {
  205. out++ = uri->s();
  206. }
  207. }
  208. }
  209. }
  210. } // namespace
  211. std::unique_ptr<ValueBase> AddUriRpcMethod::process(const RpcRequest& req,
  212. DownloadEngine* e)
  213. {
  214. const List* urisParam = checkRequiredParam<List>(req, 0);
  215. const Dict* optsParam = checkParam<Dict>(req, 1);
  216. const Integer* posParam = checkParam<Integer>(req, 2);
  217. std::vector<std::string> uris;
  218. extractUris(std::back_inserter(uris), urisParam);
  219. if (uris.empty()) {
  220. throw DL_ABORT_EX("URI is not provided.");
  221. }
  222. auto requestOption = std::make_shared<Option>(*e->getOption());
  223. gatherRequestOption(requestOption.get(), optsParam);
  224. bool posGiven = checkPosParam(posParam);
  225. size_t pos = posGiven ? posParam->i() : 0;
  226. std::vector<std::shared_ptr<RequestGroup>> result;
  227. createRequestGroupForUri(result, requestOption, uris,
  228. /* ignoreForceSeq = */ true,
  229. /* ignoreLocalPath = */ true);
  230. if (!result.empty()) {
  231. return addRequestGroup(result.front(), e, posGiven, pos);
  232. }
  233. else {
  234. throw DL_ABORT_EX("No URI to download.");
  235. }
  236. }
  237. namespace {
  238. std::string getHexSha1(const std::string& s)
  239. {
  240. unsigned char hash[20];
  241. message_digest::digest(hash, sizeof(hash), MessageDigest::sha1().get(),
  242. s.data(), s.size());
  243. return util::toHex(hash, sizeof(hash));
  244. }
  245. } // namespace
  246. #ifdef ENABLE_BITTORRENT
  247. std::unique_ptr<ValueBase> AddTorrentRpcMethod::process(const RpcRequest& req,
  248. DownloadEngine* e)
  249. {
  250. const String* torrentParam = checkRequiredParam<String>(req, 0);
  251. const List* urisParam = checkParam<List>(req, 1);
  252. const Dict* optsParam = checkParam<Dict>(req, 2);
  253. const Integer* posParam = checkParam<Integer>(req, 3);
  254. std::unique_ptr<String> tempTorrentParam;
  255. if (req.jsonRpc) {
  256. tempTorrentParam = String::g(
  257. base64::decode(torrentParam->s().begin(), torrentParam->s().end()));
  258. torrentParam = tempTorrentParam.get();
  259. }
  260. std::vector<std::string> uris;
  261. extractUris(std::back_inserter(uris), urisParam);
  262. auto requestOption = std::make_shared<Option>(*e->getOption());
  263. gatherRequestOption(requestOption.get(), optsParam);
  264. bool posGiven = checkPosParam(posParam);
  265. size_t pos = posGiven ? posParam->i() : 0;
  266. std::string filename;
  267. if (requestOption->getAsBool(PREF_RPC_SAVE_UPLOAD_METADATA)) {
  268. filename = util::applyDir(requestOption->get(PREF_DIR),
  269. getHexSha1(torrentParam->s()) + ".torrent");
  270. // Save uploaded data in order to save this download in
  271. // --save-session file.
  272. if (util::saveAs(filename, torrentParam->s(), true)) {
  273. A2_LOG_INFO(
  274. fmt("Uploaded torrent data was saved as %s", filename.c_str()));
  275. requestOption->put(PREF_TORRENT_FILE, filename);
  276. }
  277. else {
  278. A2_LOG_INFO(fmt("Uploaded torrent data was not saved."
  279. " Failed to write file %s",
  280. filename.c_str()));
  281. filename.clear();
  282. }
  283. }
  284. std::vector<std::shared_ptr<RequestGroup>> result;
  285. createRequestGroupForBitTorrent(result, requestOption, uris, filename,
  286. torrentParam->s());
  287. if (!result.empty()) {
  288. return addRequestGroup(result.front(), e, posGiven, pos);
  289. }
  290. else {
  291. throw DL_ABORT_EX("No Torrent to download.");
  292. }
  293. }
  294. #endif // ENABLE_BITTORRENT
  295. #ifdef ENABLE_METALINK
  296. std::unique_ptr<ValueBase> AddMetalinkRpcMethod::process(const RpcRequest& req,
  297. DownloadEngine* e)
  298. {
  299. const String* metalinkParam = checkRequiredParam<String>(req, 0);
  300. const Dict* optsParam = checkParam<Dict>(req, 1);
  301. const Integer* posParam = checkParam<Integer>(req, 2);
  302. std::unique_ptr<String> tempMetalinkParam;
  303. if (req.jsonRpc) {
  304. tempMetalinkParam = String::g(
  305. base64::decode(metalinkParam->s().begin(), metalinkParam->s().end()));
  306. metalinkParam = tempMetalinkParam.get();
  307. }
  308. auto requestOption = std::make_shared<Option>(*e->getOption());
  309. gatherRequestOption(requestOption.get(), optsParam);
  310. bool posGiven = checkPosParam(posParam);
  311. size_t pos = posGiven ? posParam->i() : 0;
  312. std::vector<std::shared_ptr<RequestGroup>> result;
  313. std::string filename;
  314. if (requestOption->getAsBool(PREF_RPC_SAVE_UPLOAD_METADATA)) {
  315. // TODO RFC5854 Metalink has the extension .meta4 and Metalink
  316. // Version 3 uses .metalink extension. We use .meta4 for both
  317. // RFC5854 Metalink and Version 3. aria2 can detect which of which
  318. // by reading content rather than extension.
  319. filename = util::applyDir(requestOption->get(PREF_DIR),
  320. getHexSha1(metalinkParam->s()) + ".meta4");
  321. // Save uploaded data in order to save this download in
  322. // --save-session file.
  323. if (util::saveAs(filename, metalinkParam->s(), true)) {
  324. A2_LOG_INFO(
  325. fmt("Uploaded metalink data was saved as %s", filename.c_str()));
  326. requestOption->put(PREF_METALINK_FILE, filename);
  327. createRequestGroupForMetalink(result, requestOption);
  328. }
  329. else {
  330. A2_LOG_INFO(fmt("Uploaded metalink data was not saved."
  331. " Failed to write file %s",
  332. filename.c_str()));
  333. createRequestGroupForMetalink(result, requestOption, metalinkParam->s());
  334. }
  335. }
  336. else {
  337. createRequestGroupForMetalink(result, requestOption, metalinkParam->s());
  338. }
  339. auto gids = List::g();
  340. if (!result.empty()) {
  341. if (posGiven) {
  342. e->getRequestGroupMan()->insertReservedGroup(pos, result);
  343. }
  344. else {
  345. e->getRequestGroupMan()->addReservedGroup(result);
  346. }
  347. for (auto& i : result) {
  348. gids->append(GroupId::toHex(i->getGID()));
  349. }
  350. }
  351. return std::move(gids);
  352. }
  353. #endif // ENABLE_METALINK
  354. namespace {
  355. std::unique_ptr<ValueBase> removeDownload(const RpcRequest& req,
  356. DownloadEngine* e, bool forceRemove)
  357. {
  358. const String* gidParam = checkRequiredParam<String>(req, 0);
  359. a2_gid_t gid = str2Gid(gidParam);
  360. auto group = e->getRequestGroupMan()->findGroup(gid);
  361. if (group) {
  362. if (group->getState() == RequestGroup::STATE_ACTIVE) {
  363. if (forceRemove) {
  364. group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
  365. }
  366. else {
  367. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  368. }
  369. e->setRefreshInterval(std::chrono::milliseconds(0));
  370. }
  371. else {
  372. if (group->isDependencyResolved()) {
  373. e->getRequestGroupMan()->removeReservedGroup(gid);
  374. }
  375. else {
  376. throw DL_ABORT_EX(
  377. fmt("GID#%s cannot be removed now", GroupId::toHex(gid).c_str()));
  378. }
  379. }
  380. }
  381. else {
  382. throw DL_ABORT_EX(fmt("Active Download not found for GID#%s",
  383. GroupId::toHex(gid).c_str()));
  384. }
  385. return createGIDResponse(gid);
  386. }
  387. } // namespace
  388. std::unique_ptr<ValueBase> RemoveRpcMethod::process(const RpcRequest& req,
  389. DownloadEngine* e)
  390. {
  391. return removeDownload(req, e, false);
  392. }
  393. std::unique_ptr<ValueBase> ForceRemoveRpcMethod::process(const RpcRequest& req,
  394. DownloadEngine* e)
  395. {
  396. return removeDownload(req, e, true);
  397. }
  398. namespace {
  399. std::unique_ptr<ValueBase> pauseDownload(const RpcRequest& req,
  400. DownloadEngine* e, bool forcePause)
  401. {
  402. const String* gidParam = checkRequiredParam<String>(req, 0);
  403. a2_gid_t gid = str2Gid(gidParam);
  404. auto group = e->getRequestGroupMan()->findGroup(gid);
  405. if (group) {
  406. bool reserved = group->getState() == RequestGroup::STATE_WAITING;
  407. if (pauseRequestGroup(group, reserved, forcePause)) {
  408. e->setRefreshInterval(std::chrono::milliseconds(0));
  409. return createGIDResponse(gid);
  410. }
  411. }
  412. throw DL_ABORT_EX(
  413. fmt("GID#%s cannot be paused now", GroupId::toHex(gid).c_str()));
  414. }
  415. } // namespace
  416. std::unique_ptr<ValueBase> PauseRpcMethod::process(const RpcRequest& req,
  417. DownloadEngine* e)
  418. {
  419. return pauseDownload(req, e, false);
  420. }
  421. std::unique_ptr<ValueBase> ForcePauseRpcMethod::process(const RpcRequest& req,
  422. DownloadEngine* e)
  423. {
  424. return pauseDownload(req, e, true);
  425. }
  426. namespace {
  427. template <typename InputIterator>
  428. void pauseRequestGroups(InputIterator first, InputIterator last, bool reserved,
  429. bool forcePause)
  430. {
  431. for (; first != last; ++first) {
  432. pauseRequestGroup(*first, reserved, forcePause);
  433. }
  434. }
  435. } // namespace
  436. namespace {
  437. std::unique_ptr<ValueBase> pauseAllDownloads(const RpcRequest& req,
  438. DownloadEngine* e, bool forcePause)
  439. {
  440. auto& groups = e->getRequestGroupMan()->getRequestGroups();
  441. pauseRequestGroups(groups.begin(), groups.end(), false, forcePause);
  442. auto& reservedGroups = e->getRequestGroupMan()->getReservedGroups();
  443. pauseRequestGroups(reservedGroups.begin(), reservedGroups.end(), true,
  444. forcePause);
  445. return createOKResponse();
  446. }
  447. } // namespace
  448. std::unique_ptr<ValueBase> PauseAllRpcMethod::process(const RpcRequest& req,
  449. DownloadEngine* e)
  450. {
  451. return pauseAllDownloads(req, e, false);
  452. }
  453. std::unique_ptr<ValueBase>
  454. ForcePauseAllRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  455. {
  456. return pauseAllDownloads(req, e, true);
  457. }
  458. std::unique_ptr<ValueBase> UnpauseRpcMethod::process(const RpcRequest& req,
  459. DownloadEngine* e)
  460. {
  461. const String* gidParam = checkRequiredParam<String>(req, 0);
  462. a2_gid_t gid = str2Gid(gidParam);
  463. auto group = e->getRequestGroupMan()->findGroup(gid);
  464. if (!group || group->getState() != RequestGroup::STATE_WAITING ||
  465. !group->isPauseRequested()) {
  466. throw DL_ABORT_EX(
  467. fmt("GID#%s cannot be unpaused now", GroupId::toHex(gid).c_str()));
  468. }
  469. else {
  470. group->setPauseRequested(false);
  471. e->getRequestGroupMan()->requestQueueCheck();
  472. }
  473. return createGIDResponse(gid);
  474. }
  475. std::unique_ptr<ValueBase> UnpauseAllRpcMethod::process(const RpcRequest& req,
  476. DownloadEngine* e)
  477. {
  478. auto& groups = e->getRequestGroupMan()->getReservedGroups();
  479. for (auto& group : groups) {
  480. group->setPauseRequested(false);
  481. }
  482. e->getRequestGroupMan()->requestQueueCheck();
  483. return createOKResponse();
  484. }
  485. namespace {
  486. template <typename InputIterator>
  487. void createUriEntry(List* uriList, InputIterator first, InputIterator last,
  488. const std::string& status)
  489. {
  490. for (; first != last; ++first) {
  491. auto entry = Dict::g();
  492. entry->put(KEY_URI, *first);
  493. entry->put(KEY_STATUS, status);
  494. uriList->append(std::move(entry));
  495. }
  496. }
  497. } // namespace
  498. namespace {
  499. void createUriEntry(List* uriList, const std::shared_ptr<FileEntry>& file)
  500. {
  501. createUriEntry(uriList, std::begin(file->getSpentUris()),
  502. std::end(file->getSpentUris()), VLB_USED);
  503. createUriEntry(uriList, std::begin(file->getRemainingUris()),
  504. std::end(file->getRemainingUris()), VLB_WAITING);
  505. }
  506. } // namespace
  507. namespace {
  508. template <typename InputIterator>
  509. void createFileEntry(List* files, InputIterator first, InputIterator last,
  510. const BitfieldMan* bf)
  511. {
  512. size_t index = 1;
  513. for (; first != last; ++first, ++index) {
  514. auto entry = Dict::g();
  515. entry->put(KEY_INDEX, util::uitos(index));
  516. entry->put(KEY_PATH, (*first)->getPath());
  517. entry->put(KEY_SELECTED, (*first)->isRequested() ? VLB_TRUE : VLB_FALSE);
  518. entry->put(KEY_LENGTH, util::itos((*first)->getLength()));
  519. int64_t completedLength = bf->getOffsetCompletedLength(
  520. (*first)->getOffset(), (*first)->getLength());
  521. entry->put(KEY_COMPLETED_LENGTH, util::itos(completedLength));
  522. auto uriList = List::g();
  523. createUriEntry(uriList.get(), *first);
  524. entry->put(KEY_URIS, std::move(uriList));
  525. files->append(std::move(entry));
  526. }
  527. }
  528. } // namespace
  529. namespace {
  530. template <typename InputIterator>
  531. void createFileEntry(List* files, InputIterator first, InputIterator last,
  532. int64_t totalLength, int32_t pieceLength,
  533. const std::string& bitfield)
  534. {
  535. BitfieldMan bf(pieceLength, totalLength);
  536. bf.setBitfield(reinterpret_cast<const unsigned char*>(bitfield.data()),
  537. bitfield.size());
  538. createFileEntry(files, first, last, &bf);
  539. }
  540. } // namespace
  541. namespace {
  542. template <typename InputIterator>
  543. void createFileEntry(List* files, InputIterator first, InputIterator last,
  544. int64_t totalLength, int32_t pieceLength,
  545. const std::shared_ptr<PieceStorage>& ps)
  546. {
  547. BitfieldMan bf(pieceLength, totalLength);
  548. if (ps) {
  549. bf.setBitfield(ps->getBitfield(), ps->getBitfieldLength());
  550. }
  551. createFileEntry(files, first, last, &bf);
  552. }
  553. } // namespace
  554. namespace {
  555. bool requested_key(const std::vector<std::string>& keys, const std::string& k)
  556. {
  557. return keys.empty() || std::find(keys.begin(), keys.end(), k) != keys.end();
  558. }
  559. } // namespace
  560. void gatherProgressCommon(Dict* entryDict,
  561. const std::shared_ptr<RequestGroup>& group,
  562. const std::vector<std::string>& keys)
  563. {
  564. auto& ps = group->getPieceStorage();
  565. if (requested_key(keys, KEY_GID)) {
  566. entryDict->put(KEY_GID, GroupId::toHex(group->getGID()).c_str());
  567. }
  568. if (requested_key(keys, KEY_TOTAL_LENGTH)) {
  569. // This is "filtered" total length if --select-file is used.
  570. entryDict->put(KEY_TOTAL_LENGTH, util::itos(group->getTotalLength()));
  571. }
  572. if (requested_key(keys, KEY_COMPLETED_LENGTH)) {
  573. // This is "filtered" total length if --select-file is used.
  574. entryDict->put(KEY_COMPLETED_LENGTH,
  575. util::itos(group->getCompletedLength()));
  576. }
  577. TransferStat stat = group->calculateStat();
  578. if (requested_key(keys, KEY_DOWNLOAD_SPEED)) {
  579. entryDict->put(KEY_DOWNLOAD_SPEED, util::itos(stat.downloadSpeed));
  580. }
  581. if (requested_key(keys, KEY_UPLOAD_SPEED)) {
  582. entryDict->put(KEY_UPLOAD_SPEED, util::itos(stat.uploadSpeed));
  583. }
  584. if (requested_key(keys, KEY_UPLOAD_LENGTH)) {
  585. entryDict->put(KEY_UPLOAD_LENGTH, util::itos(stat.allTimeUploadLength));
  586. }
  587. if (requested_key(keys, KEY_CONNECTIONS)) {
  588. entryDict->put(KEY_CONNECTIONS, util::itos(group->getNumConnection()));
  589. }
  590. if (requested_key(keys, KEY_BITFIELD)) {
  591. if (ps) {
  592. if (ps->getBitfieldLength() > 0) {
  593. entryDict->put(KEY_BITFIELD,
  594. util::toHex(ps->getBitfield(), ps->getBitfieldLength()));
  595. }
  596. }
  597. }
  598. auto& dctx = group->getDownloadContext();
  599. if (requested_key(keys, KEY_PIECE_LENGTH)) {
  600. entryDict->put(KEY_PIECE_LENGTH, util::itos(dctx->getPieceLength()));
  601. }
  602. if (requested_key(keys, KEY_NUM_PIECES)) {
  603. entryDict->put(KEY_NUM_PIECES, util::uitos(dctx->getNumPieces()));
  604. }
  605. if (requested_key(keys, KEY_FOLLOWED_BY)) {
  606. if (!group->followedBy().empty()) {
  607. auto list = List::g();
  608. // The element is GID.
  609. for (auto& gid : group->followedBy()) {
  610. list->append(GroupId::toHex(gid));
  611. }
  612. entryDict->put(KEY_FOLLOWED_BY, std::move(list));
  613. }
  614. }
  615. if (requested_key(keys, KEY_BELONGS_TO)) {
  616. if (group->belongsTo()) {
  617. entryDict->put(KEY_BELONGS_TO, GroupId::toHex(group->belongsTo()));
  618. }
  619. }
  620. if (requested_key(keys, KEY_FILES)) {
  621. auto files = List::g();
  622. createFileEntry(files.get(), std::begin(dctx->getFileEntries()),
  623. std::end(dctx->getFileEntries()), dctx->getTotalLength(),
  624. dctx->getPieceLength(), ps);
  625. entryDict->put(KEY_FILES, std::move(files));
  626. }
  627. if (requested_key(keys, KEY_DIR)) {
  628. entryDict->put(KEY_DIR, group->getOption()->get(PREF_DIR));
  629. }
  630. }
  631. #ifdef ENABLE_BITTORRENT
  632. void gatherBitTorrentMetadata(Dict* btDict, TorrentAttribute* torrentAttrs)
  633. {
  634. if (!torrentAttrs->comment.empty()) {
  635. btDict->put(KEY_COMMENT, torrentAttrs->comment);
  636. }
  637. if (torrentAttrs->creationDate) {
  638. btDict->put(KEY_CREATION_DATE, Integer::g(torrentAttrs->creationDate));
  639. }
  640. if (torrentAttrs->mode) {
  641. btDict->put(KEY_MODE, bittorrent::getModeString(torrentAttrs->mode));
  642. }
  643. auto destAnnounceList = List::g();
  644. for (auto& annlist : torrentAttrs->announceList) {
  645. auto destAnnounceTier = List::g();
  646. for (auto& ann : annlist) {
  647. destAnnounceTier->append(ann);
  648. }
  649. destAnnounceList->append(std::move(destAnnounceTier));
  650. }
  651. btDict->put(KEY_ANNOUNCE_LIST, std::move(destAnnounceList));
  652. if (!torrentAttrs->metadata.empty()) {
  653. auto infoDict = Dict::g();
  654. infoDict->put(KEY_NAME, torrentAttrs->name);
  655. btDict->put(KEY_INFO, std::move(infoDict));
  656. }
  657. }
  658. namespace {
  659. void gatherProgressBitTorrent(Dict* entryDict,
  660. const std::shared_ptr<RequestGroup>& group,
  661. TorrentAttribute* torrentAttrs,
  662. BtObject* btObject,
  663. const std::vector<std::string>& keys)
  664. {
  665. if (requested_key(keys, KEY_INFO_HASH)) {
  666. entryDict->put(KEY_INFO_HASH, util::toHex(torrentAttrs->infoHash));
  667. }
  668. if (requested_key(keys, KEY_BITTORRENT)) {
  669. auto btDict = Dict::g();
  670. gatherBitTorrentMetadata(btDict.get(), torrentAttrs);
  671. entryDict->put(KEY_BITTORRENT, std::move(btDict));
  672. }
  673. if (requested_key(keys, KEY_NUM_SEEDERS)) {
  674. if (!btObject) {
  675. entryDict->put(KEY_NUM_SEEDERS, VLB_ZERO);
  676. }
  677. else {
  678. auto& peerStorage = btObject->peerStorage;
  679. assert(peerStorage);
  680. auto& peers = peerStorage->getUsedPeers();
  681. entryDict->put(KEY_NUM_SEEDERS,
  682. util::uitos(countSeeder(peers.begin(), peers.end())));
  683. }
  684. }
  685. if (requested_key(keys, KEY_SEEDER)) {
  686. entryDict->put(KEY_SEEDER, group->isSeeder() ? VLB_TRUE : VLB_FALSE);
  687. }
  688. }
  689. } // namespace
  690. namespace {
  691. void gatherPeer(List* peers, const std::shared_ptr<PeerStorage>& ps)
  692. {
  693. auto& usedPeers = ps->getUsedPeers();
  694. for (auto& peer : usedPeers) {
  695. if (!peer->isActive()) {
  696. continue;
  697. }
  698. auto peerEntry = Dict::g();
  699. peerEntry->put(KEY_PEER_ID, util::torrentPercentEncode(peer->getPeerId(),
  700. PEER_ID_LENGTH));
  701. peerEntry->put(KEY_IP, peer->getIPAddress());
  702. if (peer->isIncomingPeer()) {
  703. peerEntry->put(KEY_PORT, VLB_ZERO);
  704. }
  705. else {
  706. peerEntry->put(KEY_PORT, util::uitos(peer->getPort()));
  707. }
  708. peerEntry->put(KEY_BITFIELD,
  709. util::toHex(peer->getBitfield(), peer->getBitfieldLength()));
  710. peerEntry->put(KEY_AM_CHOKING, peer->amChoking() ? VLB_TRUE : VLB_FALSE);
  711. peerEntry->put(KEY_PEER_CHOKING,
  712. peer->peerChoking() ? VLB_TRUE : VLB_FALSE);
  713. peerEntry->put(KEY_DOWNLOAD_SPEED,
  714. util::itos(peer->calculateDownloadSpeed()));
  715. peerEntry->put(KEY_UPLOAD_SPEED, util::itos(peer->calculateUploadSpeed()));
  716. peerEntry->put(KEY_SEEDER, peer->isSeeder() ? VLB_TRUE : VLB_FALSE);
  717. peers->append(std::move(peerEntry));
  718. }
  719. }
  720. } // namespace
  721. #endif // ENABLE_BITTORRENT
  722. namespace {
  723. void gatherProgress(Dict* entryDict, const std::shared_ptr<RequestGroup>& group,
  724. DownloadEngine* e, const std::vector<std::string>& keys)
  725. {
  726. gatherProgressCommon(entryDict, group, keys);
  727. #ifdef ENABLE_BITTORRENT
  728. if (group->getDownloadContext()->hasAttribute(CTX_ATTR_BT)) {
  729. gatherProgressBitTorrent(entryDict, group, bittorrent::getTorrentAttrs(
  730. group->getDownloadContext()),
  731. e->getBtRegistry()->get(group->getGID()), keys);
  732. }
  733. #endif // ENABLE_BITTORRENT
  734. }
  735. } // namespace
  736. void gatherStoppedDownload(Dict* entryDict,
  737. const std::shared_ptr<DownloadResult>& ds,
  738. const std::vector<std::string>& keys)
  739. {
  740. if (requested_key(keys, KEY_GID)) {
  741. entryDict->put(KEY_GID, ds->gid->toHex());
  742. }
  743. if (requested_key(keys, KEY_ERROR_CODE)) {
  744. entryDict->put(KEY_ERROR_CODE, util::itos(static_cast<int>(ds->result)));
  745. }
  746. if (requested_key(keys, KEY_ERROR_MESSAGE)) {
  747. entryDict->put(KEY_ERROR_MESSAGE, ds->resultMessage);
  748. }
  749. if (requested_key(keys, KEY_STATUS)) {
  750. if (ds->result == error_code::REMOVED) {
  751. entryDict->put(KEY_STATUS, VLB_REMOVED);
  752. }
  753. else if (ds->result == error_code::FINISHED) {
  754. entryDict->put(KEY_STATUS, VLB_COMPLETE);
  755. }
  756. else {
  757. entryDict->put(KEY_STATUS, VLB_ERROR);
  758. }
  759. }
  760. if (requested_key(keys, KEY_FOLLOWED_BY)) {
  761. if (!ds->followedBy.empty()) {
  762. auto list = List::g();
  763. // The element is GID.
  764. for (auto gid : ds->followedBy) {
  765. list->append(GroupId::toHex(gid));
  766. }
  767. entryDict->put(KEY_FOLLOWED_BY, std::move(list));
  768. }
  769. }
  770. if (requested_key(keys, KEY_BELONGS_TO)) {
  771. if (ds->belongsTo) {
  772. entryDict->put(KEY_BELONGS_TO, GroupId::toHex(ds->belongsTo));
  773. }
  774. }
  775. if (requested_key(keys, KEY_FILES)) {
  776. auto files = List::g();
  777. createFileEntry(files.get(), std::begin(ds->fileEntries),
  778. std::end(ds->fileEntries), ds->totalLength, ds->pieceLength,
  779. ds->bitfield);
  780. entryDict->put(KEY_FILES, std::move(files));
  781. }
  782. if (requested_key(keys, KEY_TOTAL_LENGTH)) {
  783. entryDict->put(KEY_TOTAL_LENGTH, util::itos(ds->totalLength));
  784. }
  785. if (requested_key(keys, KEY_COMPLETED_LENGTH)) {
  786. entryDict->put(KEY_COMPLETED_LENGTH, util::itos(ds->completedLength));
  787. }
  788. if (requested_key(keys, KEY_UPLOAD_LENGTH)) {
  789. entryDict->put(KEY_UPLOAD_LENGTH, util::itos(ds->uploadLength));
  790. }
  791. if (requested_key(keys, KEY_BITFIELD)) {
  792. if (!ds->bitfield.empty()) {
  793. entryDict->put(KEY_BITFIELD, util::toHex(ds->bitfield));
  794. }
  795. }
  796. if (requested_key(keys, KEY_DOWNLOAD_SPEED)) {
  797. entryDict->put(KEY_DOWNLOAD_SPEED, VLB_ZERO);
  798. }
  799. if (requested_key(keys, KEY_UPLOAD_SPEED)) {
  800. entryDict->put(KEY_UPLOAD_SPEED, VLB_ZERO);
  801. }
  802. if (!ds->infoHash.empty()) {
  803. if (requested_key(keys, KEY_INFO_HASH)) {
  804. entryDict->put(KEY_INFO_HASH, util::toHex(ds->infoHash));
  805. }
  806. if (requested_key(keys, KEY_NUM_SEEDERS)) {
  807. entryDict->put(KEY_NUM_SEEDERS, VLB_ZERO);
  808. }
  809. }
  810. if (requested_key(keys, KEY_PIECE_LENGTH)) {
  811. entryDict->put(KEY_PIECE_LENGTH, util::itos(ds->pieceLength));
  812. }
  813. if (requested_key(keys, KEY_NUM_PIECES)) {
  814. entryDict->put(KEY_NUM_PIECES, util::uitos(ds->numPieces));
  815. }
  816. if (requested_key(keys, KEY_CONNECTIONS)) {
  817. entryDict->put(KEY_CONNECTIONS, VLB_ZERO);
  818. }
  819. if (requested_key(keys, KEY_DIR)) {
  820. entryDict->put(KEY_DIR, ds->dir);
  821. }
  822. }
  823. std::unique_ptr<ValueBase> GetFilesRpcMethod::process(const RpcRequest& req,
  824. DownloadEngine* e)
  825. {
  826. const String* gidParam = checkRequiredParam<String>(req, 0);
  827. a2_gid_t gid = str2Gid(gidParam);
  828. auto files = List::g();
  829. auto group = e->getRequestGroupMan()->findGroup(gid);
  830. if (!group) {
  831. auto dr = e->getRequestGroupMan()->findDownloadResult(gid);
  832. if (!dr) {
  833. throw DL_ABORT_EX(fmt("No file data is available for GID#%s",
  834. GroupId::toHex(gid).c_str()));
  835. }
  836. else {
  837. createFileEntry(files.get(), std::begin(dr->fileEntries),
  838. std::end(dr->fileEntries), dr->totalLength,
  839. dr->pieceLength, dr->bitfield);
  840. }
  841. }
  842. else {
  843. auto& dctx = group->getDownloadContext();
  844. createFileEntry(files.get(),
  845. std::begin(group->getDownloadContext()->getFileEntries()),
  846. std::end(group->getDownloadContext()->getFileEntries()),
  847. dctx->getTotalLength(), dctx->getPieceLength(),
  848. group->getPieceStorage());
  849. }
  850. return std::move(files);
  851. }
  852. std::unique_ptr<ValueBase> GetUrisRpcMethod::process(const RpcRequest& req,
  853. DownloadEngine* e)
  854. {
  855. const String* gidParam = checkRequiredParam<String>(req, 0);
  856. a2_gid_t gid = str2Gid(gidParam);
  857. auto group = e->getRequestGroupMan()->findGroup(gid);
  858. if (!group) {
  859. throw DL_ABORT_EX(fmt("No URI data is available for GID#%s",
  860. GroupId::toHex(gid).c_str()));
  861. }
  862. auto uriList = List::g();
  863. // TODO Current implementation just returns first FileEntry's URIs.
  864. if (!group->getDownloadContext()->getFileEntries().empty()) {
  865. createUriEntry(uriList.get(),
  866. group->getDownloadContext()->getFirstFileEntry());
  867. }
  868. return std::move(uriList);
  869. }
  870. #ifdef ENABLE_BITTORRENT
  871. std::unique_ptr<ValueBase> GetPeersRpcMethod::process(const RpcRequest& req,
  872. DownloadEngine* e)
  873. {
  874. const String* gidParam = checkRequiredParam<String>(req, 0);
  875. a2_gid_t gid = str2Gid(gidParam);
  876. auto group = e->getRequestGroupMan()->findGroup(gid);
  877. if (!group) {
  878. throw DL_ABORT_EX(fmt("No peer data is available for GID#%s",
  879. GroupId::toHex(gid).c_str()));
  880. }
  881. auto peers = List::g();
  882. auto btObject = e->getBtRegistry()->get(group->getGID());
  883. if (btObject) {
  884. assert(btObject->peerStorage);
  885. gatherPeer(peers.get(), btObject->peerStorage);
  886. }
  887. return std::move(peers);
  888. }
  889. #endif // ENABLE_BITTORRENT
  890. std::unique_ptr<ValueBase> TellStatusRpcMethod::process(const RpcRequest& req,
  891. DownloadEngine* e)
  892. {
  893. const String* gidParam = checkRequiredParam<String>(req, 0);
  894. const List* keysParam = checkParam<List>(req, 1);
  895. a2_gid_t gid = str2Gid(gidParam);
  896. std::vector<std::string> keys;
  897. toStringList(std::back_inserter(keys), keysParam);
  898. auto group = e->getRequestGroupMan()->findGroup(gid);
  899. auto entryDict = Dict::g();
  900. if (!group) {
  901. auto ds = e->getRequestGroupMan()->findDownloadResult(gid);
  902. if (!ds) {
  903. throw DL_ABORT_EX(
  904. fmt("No such download for GID#%s", GroupId::toHex(gid).c_str()));
  905. }
  906. gatherStoppedDownload(entryDict.get(), ds, keys);
  907. }
  908. else {
  909. if (requested_key(keys, KEY_STATUS)) {
  910. if (group->getState() == RequestGroup::STATE_ACTIVE) {
  911. entryDict->put(KEY_STATUS, VLB_ACTIVE);
  912. }
  913. else {
  914. if (group->isPauseRequested()) {
  915. entryDict->put(KEY_STATUS, VLB_PAUSED);
  916. }
  917. else {
  918. entryDict->put(KEY_STATUS, VLB_WAITING);
  919. }
  920. }
  921. }
  922. gatherProgress(entryDict.get(), group, e, keys);
  923. }
  924. return std::move(entryDict);
  925. }
  926. std::unique_ptr<ValueBase> TellActiveRpcMethod::process(const RpcRequest& req,
  927. DownloadEngine* e)
  928. {
  929. const List* keysParam = checkParam<List>(req, 0);
  930. std::vector<std::string> keys;
  931. toStringList(std::back_inserter(keys), keysParam);
  932. auto list = List::g();
  933. bool statusReq = requested_key(keys, KEY_STATUS);
  934. for (auto& group : e->getRequestGroupMan()->getRequestGroups()) {
  935. auto entryDict = Dict::g();
  936. if (statusReq) {
  937. entryDict->put(KEY_STATUS, VLB_ACTIVE);
  938. }
  939. gatherProgress(entryDict.get(), group, e, keys);
  940. list->append(std::move(entryDict));
  941. }
  942. return std::move(list);
  943. }
  944. const RequestGroupList& TellWaitingRpcMethod::getItems(DownloadEngine* e) const
  945. {
  946. return e->getRequestGroupMan()->getReservedGroups();
  947. }
  948. void TellWaitingRpcMethod::createEntry(
  949. Dict* entryDict, const std::shared_ptr<RequestGroup>& item,
  950. DownloadEngine* e, const std::vector<std::string>& keys) const
  951. {
  952. if (requested_key(keys, KEY_STATUS)) {
  953. if (item->isPauseRequested()) {
  954. entryDict->put(KEY_STATUS, VLB_PAUSED);
  955. }
  956. else {
  957. entryDict->put(KEY_STATUS, VLB_WAITING);
  958. }
  959. }
  960. gatherProgress(entryDict, item, e, keys);
  961. }
  962. const DownloadResultList&
  963. TellStoppedRpcMethod::getItems(DownloadEngine* e) const
  964. {
  965. return e->getRequestGroupMan()->getDownloadResults();
  966. }
  967. void TellStoppedRpcMethod::createEntry(
  968. Dict* entryDict, const std::shared_ptr<DownloadResult>& item,
  969. DownloadEngine* e, const std::vector<std::string>& keys) const
  970. {
  971. gatherStoppedDownload(entryDict, item, keys);
  972. }
  973. std::unique_ptr<ValueBase>
  974. PurgeDownloadResultRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  975. {
  976. e->getRequestGroupMan()->purgeDownloadResult();
  977. return createOKResponse();
  978. }
  979. std::unique_ptr<ValueBase>
  980. RemoveDownloadResultRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  981. {
  982. const String* gidParam = checkRequiredParam<String>(req, 0);
  983. a2_gid_t gid = str2Gid(gidParam);
  984. if (!e->getRequestGroupMan()->removeDownloadResult(gid)) {
  985. throw DL_ABORT_EX(fmt("Could not remove download result of GID#%s",
  986. GroupId::toHex(gid).c_str()));
  987. }
  988. return createOKResponse();
  989. }
  990. std::unique_ptr<ValueBase> ChangeOptionRpcMethod::process(const RpcRequest& req,
  991. DownloadEngine* e)
  992. {
  993. const String* gidParam = checkRequiredParam<String>(req, 0);
  994. const Dict* optsParam = checkRequiredParam<Dict>(req, 1);
  995. a2_gid_t gid = str2Gid(gidParam);
  996. auto group = e->getRequestGroupMan()->findGroup(gid);
  997. Option option;
  998. if (group) {
  999. if (group->getState() == RequestGroup::STATE_ACTIVE) {
  1000. gatherChangeableOption(&option, optsParam);
  1001. }
  1002. else {
  1003. gatherChangeableOptionForReserved(&option, optsParam);
  1004. }
  1005. changeOption(group, option, e);
  1006. }
  1007. else {
  1008. throw DL_ABORT_EX(
  1009. fmt("Cannot change option for GID#%s", GroupId::toHex(gid).c_str()));
  1010. }
  1011. return createOKResponse();
  1012. }
  1013. std::unique_ptr<ValueBase>
  1014. ChangeGlobalOptionRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1015. {
  1016. const Dict* optsParam = checkRequiredParam<Dict>(req, 0);
  1017. Option option;
  1018. gatherChangeableGlobalOption(&option, optsParam);
  1019. changeGlobalOption(option, e);
  1020. return createOKResponse();
  1021. }
  1022. std::unique_ptr<ValueBase> GetVersionRpcMethod::process(const RpcRequest& req,
  1023. DownloadEngine* e)
  1024. {
  1025. auto result = Dict::g();
  1026. result->put(KEY_VERSION, PACKAGE_VERSION);
  1027. auto featureList = List::g();
  1028. for (int feat = 0; feat < MAX_FEATURE; ++feat) {
  1029. const char* name = strSupportedFeature(feat);
  1030. if (name) {
  1031. featureList->append(name);
  1032. }
  1033. }
  1034. result->put(KEY_ENABLED_FEATURES, std::move(featureList));
  1035. return std::move(result);
  1036. }
  1037. namespace {
  1038. void pushRequestOption(Dict* dict, const std::shared_ptr<Option>& option,
  1039. const std::shared_ptr<OptionParser>& oparser)
  1040. {
  1041. for (size_t i = 1, len = option::countOption(); i < len; ++i) {
  1042. PrefPtr pref = option::i2p(i);
  1043. const OptionHandler* h = oparser->find(pref);
  1044. if (h && h->getInitialOption() && option->defined(pref)) {
  1045. dict->put(pref->k, option->get(pref));
  1046. }
  1047. }
  1048. }
  1049. } // namespace
  1050. std::unique_ptr<ValueBase> GetOptionRpcMethod::process(const RpcRequest& req,
  1051. DownloadEngine* e)
  1052. {
  1053. const String* gidParam = checkRequiredParam<String>(req, 0);
  1054. a2_gid_t gid = str2Gid(gidParam);
  1055. auto group = e->getRequestGroupMan()->findGroup(gid);
  1056. auto result = Dict::g();
  1057. if (!group) {
  1058. auto dr = e->getRequestGroupMan()->findDownloadResult(gid);
  1059. if (!dr) {
  1060. throw DL_ABORT_EX(
  1061. fmt("Cannot get option for GID#%s", GroupId::toHex(gid).c_str()));
  1062. }
  1063. pushRequestOption(result.get(), dr->option, getOptionParser());
  1064. }
  1065. else {
  1066. pushRequestOption(result.get(), group->getOption(), getOptionParser());
  1067. }
  1068. return std::move(result);
  1069. }
  1070. std::unique_ptr<ValueBase>
  1071. GetGlobalOptionRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1072. {
  1073. auto result = Dict::g();
  1074. for (size_t i = 0, len = e->getOption()->getTable().size(); i < len; ++i) {
  1075. PrefPtr pref = option::i2p(i);
  1076. if (pref == PREF_RPC_SECRET || !e->getOption()->defined(pref)) {
  1077. continue;
  1078. }
  1079. const OptionHandler* h = getOptionParser()->find(pref);
  1080. if (h) {
  1081. result->put(pref->k, e->getOption()->get(pref));
  1082. }
  1083. }
  1084. return std::move(result);
  1085. }
  1086. std::unique_ptr<ValueBase>
  1087. ChangePositionRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1088. {
  1089. const String* gidParam = checkRequiredParam<String>(req, 0);
  1090. const Integer* posParam = checkRequiredParam<Integer>(req, 1);
  1091. const String* howParam = checkRequiredParam<String>(req, 2);
  1092. a2_gid_t gid = str2Gid(gidParam);
  1093. int pos = posParam->i();
  1094. const std::string& howStr = howParam->s();
  1095. OffsetMode how;
  1096. if (howStr == "POS_SET") {
  1097. how = OFFSET_MODE_SET;
  1098. }
  1099. else if (howStr == "POS_CUR") {
  1100. how = OFFSET_MODE_CUR;
  1101. }
  1102. else if (howStr == "POS_END") {
  1103. how = OFFSET_MODE_END;
  1104. }
  1105. else {
  1106. throw DL_ABORT_EX("Illegal argument.");
  1107. }
  1108. size_t destPos =
  1109. e->getRequestGroupMan()->changeReservedGroupPosition(gid, pos, how);
  1110. return Integer::g(destPos);
  1111. }
  1112. std::unique_ptr<ValueBase>
  1113. GetSessionInfoRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1114. {
  1115. auto result = Dict::g();
  1116. result->put(KEY_SESSION_ID, util::toHex(e->getSessionId()));
  1117. return std::move(result);
  1118. }
  1119. std::unique_ptr<ValueBase> GetServersRpcMethod::process(const RpcRequest& req,
  1120. DownloadEngine* e)
  1121. {
  1122. const String* gidParam = checkRequiredParam<String>(req, 0);
  1123. a2_gid_t gid = str2Gid(gidParam);
  1124. auto group = e->getRequestGroupMan()->findGroup(gid);
  1125. if (!group || group->getState() != RequestGroup::STATE_ACTIVE) {
  1126. throw DL_ABORT_EX(
  1127. fmt("No active download for GID#%s", GroupId::toHex(gid).c_str()));
  1128. }
  1129. auto result = List::g();
  1130. size_t index = 1;
  1131. for (auto& fe : group->getDownloadContext()->getFileEntries()) {
  1132. auto fileEntry = Dict::g();
  1133. fileEntry->put(KEY_INDEX, util::uitos(index++));
  1134. auto servers = List::g();
  1135. for (auto& req : fe->getInFlightRequests()) {
  1136. auto ps = req->getPeerStat();
  1137. if (ps) {
  1138. auto serverEntry = Dict::g();
  1139. serverEntry->put(KEY_URI, req->getUri());
  1140. serverEntry->put(KEY_CURRENT_URI, req->getCurrentUri());
  1141. serverEntry->put(KEY_DOWNLOAD_SPEED,
  1142. util::itos(ps->calculateDownloadSpeed()));
  1143. servers->append(std::move(serverEntry));
  1144. }
  1145. }
  1146. fileEntry->put(KEY_SERVERS, std::move(servers));
  1147. result->append(std::move(fileEntry));
  1148. }
  1149. return std::move(result);
  1150. }
  1151. std::unique_ptr<ValueBase> ChangeUriRpcMethod::process(const RpcRequest& req,
  1152. DownloadEngine* e)
  1153. {
  1154. const String* gidParam = checkRequiredParam<String>(req, 0);
  1155. const Integer* indexParam = checkRequiredInteger(req, 1, IntegerGE(1));
  1156. const List* delUrisParam = checkRequiredParam<List>(req, 2);
  1157. const List* addUrisParam = checkRequiredParam<List>(req, 3);
  1158. const Integer* posParam = checkParam<Integer>(req, 4);
  1159. a2_gid_t gid = str2Gid(gidParam);
  1160. bool posGiven = checkPosParam(posParam);
  1161. size_t pos = posGiven ? posParam->i() : 0;
  1162. size_t index = indexParam->i() - 1;
  1163. auto group = e->getRequestGroupMan()->findGroup(gid);
  1164. if (!group) {
  1165. throw DL_ABORT_EX(
  1166. fmt("Cannot remove URIs from GID#%s", GroupId::toHex(gid).c_str()));
  1167. }
  1168. auto& files = group->getDownloadContext()->getFileEntries();
  1169. if (files.size() <= index) {
  1170. throw DL_ABORT_EX(fmt("fileIndex is out of range"));
  1171. }
  1172. auto& s = files[index];
  1173. size_t delcount = 0;
  1174. for (auto& elem : *delUrisParam) {
  1175. const String* uri = downcast<String>(elem);
  1176. if (uri && s->removeUri(uri->s())) {
  1177. ++delcount;
  1178. }
  1179. }
  1180. size_t addcount = 0;
  1181. if (posGiven) {
  1182. for (auto& elem : *addUrisParam) {
  1183. const String* uri = downcast<String>(elem);
  1184. if (uri && s->insertUri(uri->s(), pos)) {
  1185. ++addcount;
  1186. ++pos;
  1187. }
  1188. }
  1189. }
  1190. else {
  1191. for (auto& elem : *addUrisParam) {
  1192. const String* uri = downcast<String>(elem);
  1193. if (uri && s->addUri(uri->s())) {
  1194. ++addcount;
  1195. }
  1196. }
  1197. }
  1198. if (addcount && group->getPieceStorage()) {
  1199. std::vector<std::unique_ptr<Command>> commands;
  1200. group->createNextCommand(commands, e);
  1201. e->addCommand(std::move(commands));
  1202. group->getSegmentMan()->recognizeSegmentFor(s);
  1203. }
  1204. auto res = List::g();
  1205. res->append(Integer::g(delcount));
  1206. res->append(Integer::g(addcount));
  1207. return std::move(res);
  1208. }
  1209. namespace {
  1210. std::unique_ptr<ValueBase> goingShutdown(const RpcRequest& req,
  1211. DownloadEngine* e, bool forceHalt)
  1212. {
  1213. // Schedule shutdown after 3seconds to give time to client to
  1214. // receive RPC response.
  1215. e->addRoutineCommand(
  1216. make_unique<TimedHaltCommand>(e->newCUID(), e, 3_s, forceHalt));
  1217. A2_LOG_INFO("Scheduled shutdown in 3 seconds.");
  1218. return createOKResponse();
  1219. }
  1220. } // namespace
  1221. std::unique_ptr<ValueBase> ShutdownRpcMethod::process(const RpcRequest& req,
  1222. DownloadEngine* e)
  1223. {
  1224. return goingShutdown(req, e, false);
  1225. }
  1226. std::unique_ptr<ValueBase>
  1227. ForceShutdownRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1228. {
  1229. return goingShutdown(req, e, true);
  1230. }
  1231. std::unique_ptr<ValueBase>
  1232. GetGlobalStatRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1233. {
  1234. auto& rgman = e->getRequestGroupMan();
  1235. auto ts = rgman->calculateStat();
  1236. auto res = Dict::g();
  1237. res->put(KEY_DOWNLOAD_SPEED, util::itos(ts.downloadSpeed));
  1238. res->put(KEY_UPLOAD_SPEED, util::itos(ts.uploadSpeed));
  1239. res->put(KEY_NUM_WAITING, util::uitos(rgman->getReservedGroups().size()));
  1240. res->put(KEY_NUM_STOPPED, util::uitos(rgman->getDownloadResults().size()));
  1241. res->put(KEY_NUM_STOPPED_TOTAL, util::uitos(rgman->getNumStoppedTotal()));
  1242. res->put(KEY_NUM_ACTIVE, util::uitos(rgman->getRequestGroups().size()));
  1243. return std::move(res);
  1244. }
  1245. std::unique_ptr<ValueBase> SaveSessionRpcMethod::process(const RpcRequest& req,
  1246. DownloadEngine* e)
  1247. {
  1248. const std::string& filename = e->getOption()->get(PREF_SAVE_SESSION);
  1249. if (filename.empty()) {
  1250. throw DL_ABORT_EX("Filename is not given.");
  1251. }
  1252. SessionSerializer sessionSerializer(e->getRequestGroupMan().get());
  1253. if (sessionSerializer.save(filename)) {
  1254. A2_LOG_NOTICE(
  1255. fmt(_("Serialized session to '%s' successfully."), filename.c_str()));
  1256. return createOKResponse();
  1257. }
  1258. throw DL_ABORT_EX(
  1259. fmt("Failed to serialize session to '%s'.", filename.c_str()));
  1260. }
  1261. std::unique_ptr<ValueBase>
  1262. SystemMulticallRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1263. {
  1264. // Should never get here, since SystemMulticallRpcMethod overrides execute().
  1265. assert(false);
  1266. return nullptr;
  1267. }
  1268. RpcResponse SystemMulticallRpcMethod::execute(RpcRequest req, DownloadEngine* e)
  1269. {
  1270. auto authorized = RpcResponse::AUTHORIZED;
  1271. try {
  1272. const List* methodSpecs = checkRequiredParam<List>(req, 0);
  1273. auto list = List::g();
  1274. for (auto& methodSpec : *methodSpecs) {
  1275. Dict* methodDict = downcast<Dict>(methodSpec);
  1276. if (!methodDict) {
  1277. list->append(createErrorResponse(
  1278. DL_ABORT_EX("system.multicall expected struct."), req));
  1279. continue;
  1280. }
  1281. const String* methodName =
  1282. downcast<String>(methodDict->get(KEY_METHOD_NAME));
  1283. if (!methodName) {
  1284. list->append(
  1285. createErrorResponse(DL_ABORT_EX("Missing methodName."), req));
  1286. continue;
  1287. }
  1288. if (methodName->s() == getMethodName()) {
  1289. list->append(createErrorResponse(
  1290. DL_ABORT_EX("Recursive system.multicall forbidden."), req));
  1291. continue;
  1292. }
  1293. // TODO what if params missing?
  1294. auto tempParamsList = methodDict->get(KEY_PARAMS);
  1295. std::unique_ptr<List> paramsList;
  1296. if (downcast<List>(tempParamsList)) {
  1297. paramsList.reset(
  1298. static_cast<List*>(methodDict->popValue(KEY_PARAMS).release()));
  1299. }
  1300. else {
  1301. paramsList = List::g();
  1302. }
  1303. RpcRequest r = {methodName->s(), std::move(paramsList), nullptr,
  1304. req.jsonRpc};
  1305. RpcResponse res = getMethod(methodName->s())->execute(std::move(r), e);
  1306. if (rpc::not_authorized(res)) {
  1307. authorized = RpcResponse::NOTAUTHORIZED;
  1308. }
  1309. if (res.code == 0) {
  1310. auto l = List::g();
  1311. l->append(std::move(res.param));
  1312. list->append(std::move(l));
  1313. }
  1314. else {
  1315. list->append(std::move(res.param));
  1316. }
  1317. }
  1318. return RpcResponse(0, authorized, std::move(list), std::move(req.id));
  1319. }
  1320. catch (RecoverableException& ex) {
  1321. A2_LOG_DEBUG_EX(EX_EXCEPTION_CAUGHT, ex);
  1322. return RpcResponse(1, authorized, createErrorResponse(ex, req),
  1323. std::move(req.id));
  1324. }
  1325. }
  1326. std::unique_ptr<ValueBase>
  1327. SystemListMethodsRpcMethod::process(const RpcRequest& req, DownloadEngine* e)
  1328. {
  1329. auto list = List::g();
  1330. for (auto& s : allMethodNames()) {
  1331. list->append(s);
  1332. }
  1333. return std::move(list);
  1334. }
  1335. RpcResponse SystemListMethodsRpcMethod::execute(RpcRequest req,
  1336. DownloadEngine* e)
  1337. {
  1338. auto r = process(req, e);
  1339. return RpcResponse(0, RpcResponse::AUTHORIZED, std::move(r),
  1340. std::move(req.id));
  1341. }
  1342. std::unique_ptr<ValueBase> NoSuchMethodRpcMethod::process(const RpcRequest& req,
  1343. DownloadEngine* e)
  1344. {
  1345. throw DL_ABORT_EX(fmt("No such method: %s", req.methodName.c_str()));
  1346. }
  1347. } // namespace rpc
  1348. bool pauseRequestGroup(const std::shared_ptr<RequestGroup>& group,
  1349. bool reserved, bool forcePause)
  1350. {
  1351. if ((reserved && !group->isPauseRequested()) ||
  1352. (!reserved && !group->isForceHaltRequested() &&
  1353. ((forcePause && group->isHaltRequested() && group->isPauseRequested()) ||
  1354. (!group->isHaltRequested() && !group->isPauseRequested())))) {
  1355. if (!reserved) {
  1356. // Call setHaltRequested before setPauseRequested because
  1357. // setHaltRequested calls setPauseRequested(false) internally.
  1358. if (forcePause) {
  1359. group->setForceHaltRequested(true, RequestGroup::NONE);
  1360. }
  1361. else {
  1362. group->setHaltRequested(true, RequestGroup::NONE);
  1363. }
  1364. }
  1365. group->setPauseRequested(true);
  1366. return true;
  1367. }
  1368. else {
  1369. return false;
  1370. }
  1371. }
  1372. void changeOption(const std::shared_ptr<RequestGroup>& group,
  1373. const Option& option, DownloadEngine* e)
  1374. {
  1375. const std::shared_ptr<DownloadContext>& dctx = group->getDownloadContext();
  1376. const std::shared_ptr<Option>& grOption = group->getOption();
  1377. grOption->merge(option);
  1378. if (option.defined(PREF_CHECKSUM)) {
  1379. const std::string& checksum = grOption->get(PREF_CHECKSUM);
  1380. auto p = util::divide(std::begin(checksum), std::end(checksum), '=');
  1381. std::string hashType(p.first.first, p.first.second);
  1382. util::lowercase(hashType);
  1383. dctx->setDigest(hashType, util::fromHex(p.second.first, p.second.second));
  1384. }
  1385. if (option.defined(PREF_SELECT_FILE)) {
  1386. auto sgl = util::parseIntSegments(grOption->get(PREF_SELECT_FILE));
  1387. sgl.normalize();
  1388. dctx->setFileFilter(std::move(sgl));
  1389. }
  1390. if (option.defined(PREF_SPLIT)) {
  1391. group->setNumConcurrentCommand(grOption->getAsInt(PREF_SPLIT));
  1392. }
  1393. if (option.defined(PREF_MAX_CONNECTION_PER_SERVER)) {
  1394. int maxConn = grOption->getAsInt(PREF_MAX_CONNECTION_PER_SERVER);
  1395. const std::vector<std::shared_ptr<FileEntry>>& files =
  1396. dctx->getFileEntries();
  1397. for (auto& file : files) {
  1398. (file)->setMaxConnectionPerServer(maxConn);
  1399. }
  1400. }
  1401. if (option.defined(PREF_DIR) || option.defined(PREF_OUT)) {
  1402. if (!group->getMetadataInfo()) {
  1403. assert(dctx->getFileEntries().size() == 1);
  1404. auto& fileEntry = dctx->getFirstFileEntry();
  1405. if (!grOption->blank(PREF_OUT)) {
  1406. fileEntry->setPath(
  1407. util::applyDir(grOption->get(PREF_DIR), grOption->get(PREF_OUT)));
  1408. fileEntry->setSuffixPath(A2STR::NIL);
  1409. }
  1410. else if (fileEntry->getSuffixPath().empty()) {
  1411. fileEntry->setPath(A2STR::NIL);
  1412. }
  1413. else {
  1414. fileEntry->setPath(util::applyDir(grOption->get(PREF_DIR),
  1415. fileEntry->getSuffixPath()));
  1416. }
  1417. }
  1418. else if (group->getMetadataInfo()
  1419. #ifdef ENABLE_BITTORRENT
  1420. && !dctx->hasAttribute(CTX_ATTR_BT)
  1421. #endif // ENABLE_BITTORRENT
  1422. ) {
  1423. // In case of Metalink
  1424. for (auto& fileEntry : dctx->getFileEntries()) {
  1425. // PREF_OUT is not applicable to Metalink. We have always
  1426. // suffixPath set.
  1427. fileEntry->setPath(util::applyDir(grOption->get(PREF_DIR),
  1428. fileEntry->getSuffixPath()));
  1429. }
  1430. }
  1431. }
  1432. #ifdef ENABLE_BITTORRENT
  1433. if (option.defined(PREF_DIR) || option.defined(PREF_INDEX_OUT)) {
  1434. if (dctx->hasAttribute(CTX_ATTR_BT)) {
  1435. std::istringstream indexOutIn(grOption->get(PREF_INDEX_OUT));
  1436. std::vector<std::pair<size_t, std::string>> indexPaths =
  1437. util::createIndexPaths(indexOutIn);
  1438. for (std::vector<std::pair<size_t, std::string>>::const_iterator
  1439. i = indexPaths.begin(),
  1440. eoi = indexPaths.end();
  1441. i != eoi; ++i) {
  1442. dctx->setFilePathWithIndex(
  1443. (*i).first, util::applyDir(grOption->get(PREF_DIR), (*i).second));
  1444. }
  1445. }
  1446. }
  1447. #endif // ENABLE_BITTORRENT
  1448. if (option.defined(PREF_MAX_DOWNLOAD_LIMIT)) {
  1449. group->setMaxDownloadSpeedLimit(
  1450. grOption->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
  1451. }
  1452. if (option.defined(PREF_MAX_UPLOAD_LIMIT)) {
  1453. group->setMaxUploadSpeedLimit(grOption->getAsInt(PREF_MAX_UPLOAD_LIMIT));
  1454. }
  1455. #ifdef ENABLE_BITTORRENT
  1456. auto btObject = e->getBtRegistry()->get(group->getGID());
  1457. if (btObject) {
  1458. if (option.defined(PREF_BT_MAX_PEERS)) {
  1459. btObject->btRuntime->setMaxPeers(grOption->getAsInt(PREF_BT_MAX_PEERS));
  1460. }
  1461. }
  1462. #endif // ENABLE_BITTORRENT
  1463. }
  1464. void changeGlobalOption(const Option& option, DownloadEngine* e)
  1465. {
  1466. e->getOption()->merge(option);
  1467. if (option.defined(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)) {
  1468. e->getRequestGroupMan()->setMaxOverallDownloadSpeedLimit(
  1469. option.getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT));
  1470. }
  1471. if (option.defined(PREF_MAX_OVERALL_UPLOAD_LIMIT)) {
  1472. e->getRequestGroupMan()->setMaxOverallUploadSpeedLimit(
  1473. option.getAsInt(PREF_MAX_OVERALL_UPLOAD_LIMIT));
  1474. }
  1475. if (option.defined(PREF_MAX_CONCURRENT_DOWNLOADS)) {
  1476. e->getRequestGroupMan()->setMaxSimultaneousDownloads(
  1477. option.getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
  1478. e->getRequestGroupMan()->requestQueueCheck();
  1479. }
  1480. if (option.defined(PREF_MAX_DOWNLOAD_RESULT)) {
  1481. e->getRequestGroupMan()->setMaxDownloadResult(
  1482. option.getAsInt(PREF_MAX_DOWNLOAD_RESULT));
  1483. }
  1484. if (option.defined(PREF_LOG_LEVEL)) {
  1485. LogFactory::setLogLevel(option.get(PREF_LOG_LEVEL));
  1486. }
  1487. if (option.defined(PREF_LOG)) {
  1488. LogFactory::setLogFile(option.get(PREF_LOG));
  1489. try {
  1490. LogFactory::reconfigure();
  1491. }
  1492. catch (RecoverableException& e) {
  1493. // TODO no exception handling
  1494. }
  1495. }
  1496. if (option.defined(PREF_BT_MAX_OPEN_FILES)) {
  1497. auto& openedFileCounter = e->getRequestGroupMan()->getOpenedFileCounter();
  1498. openedFileCounter->setMaxOpenFiles(option.getAsInt(PREF_BT_MAX_OPEN_FILES));
  1499. }
  1500. }
  1501. } // namespace aria2