XmlRpcMethodImpl.cc 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  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 "XmlRpcMethodImpl.h"
  36. #include <cassert>
  37. #include <algorithm>
  38. #include "Logger.h"
  39. #include "LogFactory.h"
  40. #include "BDE.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 "RequestGroupMan.h"
  50. #include "StringFormat.h"
  51. #include "XmlRpcRequest.h"
  52. #include "PieceStorage.h"
  53. #include "DownloadContext.h"
  54. #include "DiskAdaptor.h"
  55. #include "FileEntry.h"
  56. #include "BtProgressInfoFile.h"
  57. #include "prefs.h"
  58. #include "message.h"
  59. #include "FeatureConfig.h"
  60. #include "array_fun.h"
  61. #include "XmlRpcMethodFactory.h"
  62. #include "XmlRpcResponse.h"
  63. #include "SegmentMan.h"
  64. #include "TimedHaltCommand.h"
  65. #include "ServerStatMan.h"
  66. #include "FileAllocationEntry.h"
  67. #include "CheckIntegrityEntry.h"
  68. #ifdef ENABLE_BITTORRENT
  69. # include "bittorrent_helper.h"
  70. # include "BtRegistry.h"
  71. # include "PeerStorage.h"
  72. # include "Peer.h"
  73. # include "BtRuntime.h"
  74. # include "BtAnnounce.h"
  75. #endif // ENABLE_BITTORRENT
  76. namespace aria2 {
  77. namespace xmlrpc {
  78. namespace {
  79. const BDE BDE_TRUE = BDE("true");
  80. const BDE BDE_FALSE = BDE("false");
  81. const BDE BDE_OK = BDE("OK");
  82. const BDE BDE_ACTIVE = BDE("active");
  83. const BDE BDE_WAITING = BDE("waiting");
  84. const BDE BDE_PAUSED = BDE("paused");
  85. const BDE BDE_REMOVED = BDE("removed");
  86. const BDE BDE_ERROR = BDE("error");
  87. const BDE BDE_COMPLETE = BDE("complete");
  88. const BDE BDE_USED = BDE("used");
  89. const BDE BDE_ZERO = BDE("0");
  90. const std::string KEY_GID = "gid";
  91. const std::string KEY_ERROR_CODE = "errorCode";
  92. const std::string KEY_STATUS = "status";
  93. const std::string KEY_TOTAL_LENGTH = "totalLength";
  94. const std::string KEY_COMPLETED_LENGTH = "completedLength";
  95. const std::string KEY_DOWNLOAD_SPEED = "downloadSpeed";
  96. const std::string KEY_UPLOAD_SPEED = "uploadSpeed";
  97. const std::string KEY_UPLOAD_LENGTH = "uploadLength";
  98. const std::string KEY_CONNECTIONS = "connections";
  99. const std::string KEY_BITFIELD = "bitfield";
  100. const std::string KEY_PIECE_LENGTH = "pieceLength";
  101. const std::string KEY_NUM_PIECES = "numPieces";
  102. const std::string KEY_FOLLOWED_BY = "followedBy";
  103. const std::string KEY_BELONGS_TO = "belongsTo";
  104. const std::string KEY_INFO_HASH = "infoHash";
  105. const std::string KEY_NUM_SEEDERS = "numSeeders";
  106. const std::string KEY_PEER_ID = "peerId";
  107. const std::string KEY_IP = "ip";
  108. const std::string KEY_PORT = "port";
  109. const std::string KEY_AM_CHOKING = "amChoking";
  110. const std::string KEY_PEER_CHOKING = "peerChoking";
  111. const std::string KEY_SEEDER = "seeder";
  112. const std::string KEY_INDEX = "index";
  113. const std::string KEY_PATH = "path";
  114. const std::string KEY_SELECTED = "selected";
  115. const std::string KEY_LENGTH = "length";
  116. const std::string KEY_URI = "uri";
  117. const std::string KEY_CURRENT_URI = "currentUri";
  118. const std::string KEY_VERSION = "version";
  119. const std::string KEY_ENABLED_FEATURES = "enabledFeatures";
  120. const std::string KEY_METHOD_NAME = "methodName";
  121. const std::string KEY_PARAMS = "params";
  122. const std::string KEY_SESSION_ID = "sessionId";
  123. const std::string KEY_FILES = "files";
  124. const std::string KEY_DIR = "dir";
  125. const std::string KEY_URIS = "uris";
  126. const std::string KEY_BITTORRENT = "bittorrent";
  127. const std::string KEY_INFO = "info";
  128. const std::string KEY_NAME = "name";
  129. const std::string KEY_ANNOUNCE_LIST = "announceList";
  130. const std::string KEY_COMMENT = "comment";
  131. const std::string KEY_CREATION_DATE = "creationDate";
  132. const std::string KEY_MODE = "mode";
  133. const std::string KEY_SERVERS = "servers";
  134. }
  135. static BDE createGIDResponse(gid_t gid)
  136. {
  137. return BDE(util::itos(gid));
  138. }
  139. static BDE addRequestGroup(const SharedHandle<RequestGroup>& group,
  140. DownloadEngine* e,
  141. bool posGiven, int pos)
  142. {
  143. if(posGiven) {
  144. e->getRequestGroupMan()->insertReservedGroup(pos, group);
  145. } else {
  146. e->getRequestGroupMan()->addReservedGroup(group);
  147. }
  148. return createGIDResponse(group->getGID());
  149. }
  150. static
  151. SharedHandle<RequestGroup>
  152. findRequestGroup(const SharedHandle<RequestGroupMan>& rgman, gid_t gid)
  153. {
  154. SharedHandle<RequestGroup> group = rgman->findRequestGroup(gid);
  155. if(group.isNull()) {
  156. group = rgman->findReservedGroup(gid);
  157. }
  158. return group;
  159. }
  160. static bool hasDictParam(const BDE& params, size_t index)
  161. {
  162. return params.size() > index && params[index].isDict();
  163. }
  164. static void getPosParam(const BDE& params, size_t posParamIndex,
  165. bool& posGiven, size_t& pos)
  166. {
  167. if(params.size() > posParamIndex && params[posParamIndex].isInteger()) {
  168. if(params[posParamIndex].i() >= 0) {
  169. pos = params[posParamIndex].i();
  170. posGiven = true;
  171. } else {
  172. throw DL_ABORT_EX("Position must be greater than or equal to 0.");
  173. }
  174. } else {
  175. posGiven = false;
  176. }
  177. }
  178. template<typename OutputIterator>
  179. static void extractUris(OutputIterator out, const BDE& src)
  180. {
  181. for(BDE::List::const_iterator i = src.listBegin(), eoi = src.listEnd();
  182. i != eoi; ++i) {
  183. if((*i).isString()) {
  184. out++ = (*i).s();
  185. }
  186. }
  187. }
  188. BDE AddUriXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  189. {
  190. const BDE& params = req._params;
  191. assert(params.isList());
  192. if(params.empty() || !params[0].isList() || params[0].empty()) {
  193. throw DL_ABORT_EX("URI is not provided.");
  194. }
  195. std::vector<std::string> uris;
  196. extractUris(std::back_inserter(uris), params[0]);
  197. SharedHandle<Option> requestOption(new Option(*e->getOption()));
  198. if(hasDictParam(params, 1)) {
  199. gatherRequestOption(requestOption, params[1]);
  200. }
  201. size_t pos = 0;
  202. bool posGiven = false;
  203. getPosParam(params, 2, posGiven, pos);
  204. std::vector<SharedHandle<RequestGroup> > result;
  205. createRequestGroupForUri(result, requestOption, uris,
  206. /* ignoreForceSeq = */ true,
  207. /* ignoreLocalPath = */ true);
  208. if(!result.empty()) {
  209. return addRequestGroup(result.front(), e, posGiven, pos);
  210. } else {
  211. throw DL_ABORT_EX("No URI to download.");
  212. }
  213. }
  214. #ifdef ENABLE_BITTORRENT
  215. BDE AddTorrentXmlRpcMethod::process
  216. (const XmlRpcRequest& req, DownloadEngine* e)
  217. {
  218. const BDE& params = req._params;
  219. assert(params.isList());
  220. if(params.empty() || !params[0].isString()) {
  221. throw DL_ABORT_EX("Torrent data is not provided.");
  222. }
  223. std::vector<std::string> uris;
  224. if(params.size() > 1 && params[1].isList()) {
  225. extractUris(std::back_inserter(uris), params[1]);
  226. }
  227. SharedHandle<Option> requestOption(new Option(*e->getOption()));
  228. if(hasDictParam(params, 2)) {
  229. gatherRequestOption(requestOption, params[2]);
  230. }
  231. size_t pos = 0;
  232. bool posGiven = false;
  233. getPosParam(params, 3, posGiven, pos);
  234. std::vector<SharedHandle<RequestGroup> > result;
  235. createRequestGroupForBitTorrent(result, requestOption,
  236. uris,
  237. params[0].s());
  238. if(!result.empty()) {
  239. return addRequestGroup(result.front(), e, posGiven, pos);
  240. } else {
  241. throw DL_ABORT_EX("No Torrent to download.");
  242. }
  243. }
  244. #endif // ENABLE_BITTORRENT
  245. #ifdef ENABLE_METALINK
  246. BDE AddMetalinkXmlRpcMethod::process
  247. (const XmlRpcRequest& req, DownloadEngine* e)
  248. {
  249. const BDE& params = req._params;
  250. assert(params.isList());
  251. if(params.empty() || !params[0].isString()) {
  252. throw DL_ABORT_EX("Metalink data is not provided.");
  253. }
  254. SharedHandle<Option> requestOption(new Option(*e->getOption()));
  255. if(hasDictParam(params, 1)) {
  256. gatherRequestOption(requestOption, params[1]);
  257. };
  258. size_t pos = 0;
  259. bool posGiven = false;
  260. getPosParam(params, 2, posGiven, pos);
  261. std::vector<SharedHandle<RequestGroup> > result;
  262. createRequestGroupForMetalink(result, requestOption, params[0].s());
  263. if(!result.empty()) {
  264. if(posGiven) {
  265. e->getRequestGroupMan()->insertReservedGroup(pos, result);
  266. } else {
  267. e->getRequestGroupMan()->addReservedGroup(result);
  268. }
  269. BDE gids = BDE::list();
  270. for(std::vector<SharedHandle<RequestGroup> >::const_iterator i =
  271. result.begin(), eoi = result.end(); i != eoi; ++i) {
  272. gids << BDE(util::itos((*i)->getGID()));
  273. }
  274. return gids;
  275. } else {
  276. throw DL_ABORT_EX("No files to download.");
  277. }
  278. }
  279. #endif // ENABLE_METALINK
  280. static BDE removeDownload
  281. (const XmlRpcRequest& req, DownloadEngine* e, bool forceRemove)
  282. {
  283. const BDE& params = req._params;
  284. assert(params.isList());
  285. if(params.empty() || !params[0].isString()) {
  286. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  287. }
  288. gid_t gid = util::parseLLInt(params[0].s());
  289. SharedHandle<RequestGroup> group =
  290. e->getRequestGroupMan()->findRequestGroup(gid);
  291. if(group.isNull()) {
  292. group = e->getRequestGroupMan()->findReservedGroup(gid);
  293. if(group.isNull()) {
  294. throw DL_ABORT_EX
  295. (StringFormat("Active Download not found for GID#%s",
  296. util::itos(gid).c_str()).str());
  297. }
  298. if(group->isDependencyResolved()) {
  299. e->getRequestGroupMan()->removeReservedGroup(gid);
  300. } else {
  301. throw DL_ABORT_EX
  302. (StringFormat("GID#%s cannot be removed now",
  303. util::itos(gid).c_str()).str());
  304. }
  305. } else {
  306. if(forceRemove) {
  307. group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
  308. } else {
  309. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  310. }
  311. }
  312. return createGIDResponse(gid);
  313. }
  314. BDE RemoveXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  315. {
  316. return removeDownload(req, e, false);
  317. }
  318. BDE ForceRemoveXmlRpcMethod::process
  319. (const XmlRpcRequest& req, DownloadEngine* e)
  320. {
  321. return removeDownload(req, e, true);
  322. }
  323. static bool pauseRequestGroup
  324. (const SharedHandle<RequestGroup>& group, bool reserved, bool forcePause)
  325. {
  326. if((reserved && !group->isPauseRequested()) ||
  327. (!reserved &&
  328. !group->isForceHaltRequested() &&
  329. ((forcePause && group->isHaltRequested() && group->isPauseRequested()) ||
  330. (!group->isHaltRequested() && !group->isPauseRequested())))) {
  331. if(!reserved) {
  332. // Call setHaltRequested before setPauseRequested because
  333. // setHaltRequested calls setPauseRequested(false) internally.
  334. if(forcePause) {
  335. group->setForceHaltRequested(true, RequestGroup::NONE);
  336. } else {
  337. group->setHaltRequested(true, RequestGroup::NONE);
  338. }
  339. }
  340. group->setPauseRequested(true);
  341. return true;
  342. } else {
  343. return false;
  344. }
  345. }
  346. static BDE pauseDownload
  347. (const XmlRpcRequest& req, DownloadEngine* e, bool forcePause)
  348. {
  349. const BDE& params = req._params;
  350. assert(params.isList());
  351. if(params.empty() || !params[0].isString()) {
  352. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  353. }
  354. gid_t gid = util::parseLLInt(params[0].s());
  355. bool reserved = false;
  356. SharedHandle<RequestGroup> group =
  357. e->getRequestGroupMan()->findRequestGroup(gid);
  358. if(group.isNull()) {
  359. reserved = true;
  360. group = e->getRequestGroupMan()->findReservedGroup(gid);
  361. }
  362. if(!group.isNull() && pauseRequestGroup(group, reserved, forcePause)) {
  363. return createGIDResponse(gid);
  364. } else {
  365. throw DL_ABORT_EX
  366. (StringFormat("GID#%s cannot be paused now",
  367. util::itos(gid).c_str()).str());
  368. }
  369. }
  370. BDE PauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  371. {
  372. return pauseDownload(req, e, false);
  373. }
  374. BDE ForcePauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  375. {
  376. return pauseDownload(req, e, true);
  377. }
  378. template<typename InputIterator>
  379. static void pauseRequestGroups
  380. (InputIterator first, InputIterator last, bool reserved, bool forcePause)
  381. {
  382. for(; first != last; ++first) {
  383. pauseRequestGroup(*first, reserved, forcePause);
  384. }
  385. }
  386. static BDE pauseAllDownloads
  387. (const XmlRpcRequest& req, DownloadEngine* e, bool forcePause)
  388. {
  389. const std::deque<SharedHandle<RequestGroup> >& groups =
  390. e->getRequestGroupMan()->getRequestGroups();
  391. pauseRequestGroups(groups.begin(), groups.end(), false, forcePause);
  392. const std::deque<SharedHandle<RequestGroup> >& reservedGroups =
  393. e->getRequestGroupMan()->getReservedGroups();
  394. pauseRequestGroups(reservedGroups.begin(), reservedGroups.end(),
  395. true, forcePause);
  396. return BDE_OK;
  397. }
  398. BDE PauseAllXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  399. {
  400. return pauseAllDownloads(req, e, false);
  401. }
  402. BDE ForcePauseAllXmlRpcMethod::process
  403. (const XmlRpcRequest& req, DownloadEngine* e)
  404. {
  405. return pauseAllDownloads(req, e, true);
  406. }
  407. BDE UnpauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  408. {
  409. const BDE& params = req._params;
  410. assert(params.isList());
  411. if(params.empty() || !params[0].isString()) {
  412. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  413. }
  414. gid_t gid = util::parseLLInt(params[0].s());
  415. SharedHandle<RequestGroup> group =
  416. e->getRequestGroupMan()->findReservedGroup(gid);
  417. if(group.isNull() || !group->isPauseRequested()) {
  418. throw DL_ABORT_EX
  419. (StringFormat("GID#%s cannot be unpaused now",
  420. util::itos(gid).c_str()).str());
  421. } else {
  422. group->setPauseRequested(false);
  423. e->getRequestGroupMan()->requestQueueCheck();
  424. }
  425. return createGIDResponse(gid);
  426. }
  427. BDE UnpauseAllXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  428. {
  429. const std::deque<SharedHandle<RequestGroup> >& groups =
  430. e->getRequestGroupMan()->getReservedGroups();
  431. std::for_each(groups.begin(), groups.end(),
  432. std::bind2nd(mem_fun_sh(&RequestGroup::setPauseRequested),
  433. false));
  434. e->getRequestGroupMan()->requestQueueCheck();
  435. return BDE_OK;
  436. }
  437. static void createUriEntry(BDE& uriList, const SharedHandle<FileEntry>& file)
  438. {
  439. {
  440. const std::deque<std::string>& uris = file->getSpentUris();
  441. for(std::deque<std::string>::const_iterator i = uris.begin(),
  442. eoi = uris.end(); i != eoi; ++i) {
  443. BDE entry = BDE::dict();
  444. entry[KEY_URI] = *i;
  445. entry[KEY_STATUS] = BDE_USED;
  446. uriList << entry;
  447. }
  448. }
  449. {
  450. const std::deque<std::string>& uris = file->getRemainingUris();
  451. for(std::deque<std::string>::const_iterator i = uris.begin(),
  452. eoi = uris.end(); i != eoi; ++i) {
  453. BDE entry = BDE::dict();
  454. entry[KEY_URI] = *i;
  455. entry[KEY_STATUS] = BDE_WAITING;
  456. uriList << entry;
  457. }
  458. }
  459. }
  460. template<typename InputIterator>
  461. static void createFileEntry(BDE& files, InputIterator first, InputIterator last)
  462. {
  463. size_t index = 1;
  464. for(; first != last; ++first, ++index) {
  465. BDE entry = BDE::dict();
  466. entry[KEY_INDEX] = util::uitos(index);
  467. entry[KEY_PATH] = (*first)->getPath();
  468. entry[KEY_SELECTED] = (*first)->isRequested()?BDE_TRUE:BDE_FALSE;
  469. entry[KEY_LENGTH] = util::uitos((*first)->getLength());
  470. BDE uriList = BDE::list();
  471. createUriEntry(uriList, *first);
  472. entry[KEY_URIS] = uriList;
  473. files << entry;
  474. }
  475. }
  476. void gatherProgressCommon
  477. (BDE& entryDict, const SharedHandle<RequestGroup>& group)
  478. {
  479. entryDict[KEY_GID] = util::itos(group->getGID());
  480. // This is "filtered" total length if --select-file is used.
  481. entryDict[KEY_TOTAL_LENGTH] = util::uitos(group->getTotalLength());
  482. // This is "filtered" total length if --select-file is used.
  483. entryDict[KEY_COMPLETED_LENGTH] = util::uitos(group->getCompletedLength());
  484. TransferStat stat = group->calculateStat();
  485. entryDict[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  486. entryDict[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  487. entryDict[KEY_UPLOAD_LENGTH] = util::uitos(stat.getAllTimeUploadLength());
  488. entryDict[KEY_CONNECTIONS] = util::uitos(group->getNumConnection());
  489. SharedHandle<PieceStorage> ps = group->getPieceStorage();
  490. if(!ps.isNull()) {
  491. if(ps->getBitfieldLength() > 0) {
  492. entryDict[KEY_BITFIELD] = util::toHex(ps->getBitfield(),
  493. ps->getBitfieldLength());
  494. }
  495. }
  496. const SharedHandle<DownloadContext>& dctx = group->getDownloadContext();
  497. entryDict[KEY_PIECE_LENGTH] = util::uitos(dctx->getPieceLength());
  498. entryDict[KEY_NUM_PIECES] = util::uitos(dctx->getNumPieces());
  499. if(!group->followedBy().empty()) {
  500. BDE list = BDE::list();
  501. // The element is GID.
  502. for(std::vector<gid_t>::const_iterator i = group->followedBy().begin(),
  503. eoi = group->followedBy().end(); i != eoi; ++i) {
  504. list << util::itos(*i);
  505. }
  506. entryDict[KEY_FOLLOWED_BY] = list;
  507. }
  508. if(group->belongsTo()) {
  509. entryDict[KEY_BELONGS_TO] = util::itos(group->belongsTo());
  510. }
  511. BDE files = BDE::list();
  512. createFileEntry
  513. (files, dctx->getFileEntries().begin(), dctx->getFileEntries().end());
  514. entryDict[KEY_FILES] = files;
  515. entryDict[KEY_DIR] = dctx->getDir();
  516. }
  517. #ifdef ENABLE_BITTORRENT
  518. void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs)
  519. {
  520. if(torrentAttrs.containsKey(bittorrent::COMMENT)) {
  521. btDict[KEY_COMMENT] = torrentAttrs[bittorrent::COMMENT];
  522. }
  523. if(torrentAttrs.containsKey(bittorrent::CREATION_DATE)) {
  524. btDict[KEY_CREATION_DATE] = torrentAttrs[bittorrent::CREATION_DATE];
  525. }
  526. if(torrentAttrs.containsKey(bittorrent::MODE)) {
  527. btDict[KEY_MODE] = torrentAttrs[bittorrent::MODE];
  528. }
  529. // Copy announceList to avoid modification on entyDict to be
  530. // affected original announceList.
  531. // TODO Would it be good to add copy() method in BDE?
  532. const BDE& announceList = torrentAttrs[bittorrent::ANNOUNCE_LIST];
  533. BDE destAnnounceList = BDE::list();
  534. for(BDE::List::const_iterator l = announceList.listBegin(),
  535. eoi = announceList.listEnd(); l != eoi; ++l) {
  536. BDE destAnnounceTier = BDE::list();
  537. for(BDE::List::const_iterator t = (*l).listBegin(),
  538. eoi2 = (*l).listEnd(); t != eoi2; ++t) {
  539. destAnnounceTier << (*t);
  540. }
  541. destAnnounceList << destAnnounceTier;
  542. }
  543. btDict[KEY_ANNOUNCE_LIST] = destAnnounceList;
  544. if(torrentAttrs.containsKey(bittorrent::METADATA)) {
  545. BDE infoDict = BDE::dict();
  546. infoDict[KEY_NAME] = torrentAttrs[bittorrent::NAME];
  547. btDict[KEY_INFO] = infoDict;
  548. }
  549. }
  550. static void gatherProgressBitTorrent
  551. (BDE& entryDict, const BDE& torrentAttrs, const BtObject& btObject)
  552. {
  553. const std::string& infoHash = torrentAttrs[bittorrent::INFO_HASH].s();
  554. entryDict[KEY_INFO_HASH] = util::toHex(infoHash);
  555. BDE btDict = BDE::dict();
  556. gatherBitTorrentMetadata(btDict, torrentAttrs);
  557. entryDict[KEY_BITTORRENT] = btDict;
  558. if(btObject.isNull()) {
  559. entryDict[KEY_NUM_SEEDERS] = BDE_ZERO;
  560. } else {
  561. SharedHandle<PeerStorage> peerStorage = btObject._peerStorage;
  562. assert(!peerStorage.isNull());
  563. std::vector<SharedHandle<Peer> > peers;
  564. peerStorage->getActivePeers(peers);
  565. entryDict[KEY_NUM_SEEDERS] =
  566. util::uitos(countSeeder(peers.begin(), peers.end()));
  567. }
  568. }
  569. static void gatherPeer(BDE& peers, const SharedHandle<PeerStorage>& ps)
  570. {
  571. std::vector<SharedHandle<Peer> > activePeers;
  572. ps->getActivePeers(activePeers);
  573. for(std::vector<SharedHandle<Peer> >::const_iterator i =
  574. activePeers.begin(), eoi = activePeers.end(); i != eoi; ++i) {
  575. BDE peerEntry = BDE::dict();
  576. peerEntry[KEY_PEER_ID] = util::torrentPercentEncode((*i)->getPeerId(),
  577. PEER_ID_LENGTH);
  578. peerEntry[KEY_IP] = (*i)->ipaddr;
  579. if((*i)->isIncomingPeer()) {
  580. peerEntry[KEY_PORT] = std::string("0");
  581. } else {
  582. peerEntry[KEY_PORT] = util::uitos((*i)->port);
  583. }
  584. peerEntry[KEY_BITFIELD] = util::toHex((*i)->getBitfield(),
  585. (*i)->getBitfieldLength());
  586. peerEntry[KEY_AM_CHOKING] = (*i)->amChoking()?BDE_TRUE:BDE_FALSE;
  587. peerEntry[KEY_PEER_CHOKING] = (*i)->peerChoking()?BDE_TRUE:BDE_FALSE;
  588. TransferStat stat = ps->getTransferStatFor(*i);
  589. peerEntry[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  590. peerEntry[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  591. peerEntry[KEY_SEEDER] = (*i)->isSeeder()?BDE_TRUE:BDE_FALSE;
  592. peers << peerEntry;
  593. }
  594. }
  595. #endif // ENABLE_BITTORRENT
  596. static void gatherProgress
  597. (BDE& entryDict, const SharedHandle<RequestGroup>& group, DownloadEngine* e)
  598. {
  599. gatherProgressCommon(entryDict, group);
  600. #ifdef ENABLE_BITTORRENT
  601. if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
  602. const BDE& torrentAttrs =
  603. group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
  604. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  605. gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
  606. }
  607. #endif // ENABLE_BITTORRENT
  608. }
  609. void gatherStoppedDownload
  610. (BDE& entryDict, const SharedHandle<DownloadResult>& ds)
  611. {
  612. entryDict[KEY_GID] = util::itos(ds->gid);
  613. entryDict[KEY_ERROR_CODE] = util::itos(static_cast<int>(ds->result));
  614. if(ds->result == downloadresultcode::IN_PROGRESS) {
  615. entryDict[KEY_STATUS] = BDE_REMOVED;
  616. } else if(ds->result == downloadresultcode::FINISHED) {
  617. entryDict[KEY_STATUS] = BDE_COMPLETE;
  618. } else {
  619. entryDict[KEY_STATUS] = BDE_ERROR;
  620. }
  621. if(!ds->followedBy.empty()) {
  622. BDE list = BDE::list();
  623. // The element is GID.
  624. for(std::vector<gid_t>::const_iterator i = ds->followedBy.begin(),
  625. eoi = ds->followedBy.end(); i != eoi; ++i) {
  626. list << util::itos(*i);
  627. }
  628. entryDict[KEY_FOLLOWED_BY] = list;
  629. }
  630. if(ds->belongsTo) {
  631. entryDict[KEY_BELONGS_TO] = util::itos(ds->belongsTo);
  632. }
  633. BDE files = BDE::list();
  634. createFileEntry(files, ds->fileEntries.begin(), ds->fileEntries.end());
  635. entryDict[KEY_FILES] = files;
  636. entryDict[KEY_TOTAL_LENGTH] = util::uitos(ds->totalLength);
  637. entryDict[KEY_COMPLETED_LENGTH] = util::uitos(ds->completedLength);
  638. entryDict[KEY_UPLOAD_LENGTH] = util::uitos(ds->uploadLength);
  639. if(!ds->bitfieldStr.empty()) {
  640. entryDict[KEY_BITFIELD] = ds->bitfieldStr;
  641. }
  642. entryDict[KEY_DOWNLOAD_SPEED] = BDE_ZERO;
  643. entryDict[KEY_UPLOAD_SPEED] = BDE_ZERO;
  644. if(!ds->infoHashStr.empty()) {
  645. entryDict[KEY_INFO_HASH] = ds->infoHashStr;
  646. entryDict[KEY_NUM_SEEDERS] = BDE_ZERO;
  647. }
  648. entryDict[KEY_PIECE_LENGTH] = util::uitos(ds->pieceLength);
  649. entryDict[KEY_NUM_PIECES] = util::uitos(ds->numPieces);
  650. entryDict[KEY_CONNECTIONS] = BDE_ZERO;
  651. entryDict[KEY_DIR] = ds->dir;
  652. }
  653. BDE GetFilesXmlRpcMethod::process
  654. (const XmlRpcRequest& req, DownloadEngine* e)
  655. {
  656. const BDE& params = req._params;
  657. assert(params.isList());
  658. if(params.empty() || !params[0].isString()) {
  659. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  660. }
  661. gid_t gid = util::parseLLInt(params[0].s());
  662. BDE files = BDE::list();
  663. SharedHandle<RequestGroup> group =
  664. findRequestGroup(e->getRequestGroupMan(), gid);
  665. if(group.isNull()) {
  666. SharedHandle<DownloadResult> dr =
  667. e->getRequestGroupMan()->findDownloadResult(gid);
  668. if(dr.isNull()) {
  669. throw DL_ABORT_EX
  670. (StringFormat("No file data is available for GID#%s",
  671. util::itos(gid).c_str()).str());
  672. } else {
  673. createFileEntry(files, dr->fileEntries.begin(), dr->fileEntries.end());
  674. }
  675. } else {
  676. createFileEntry(files,
  677. group->getDownloadContext()->getFileEntries().begin(),
  678. group->getDownloadContext()->getFileEntries().end());
  679. }
  680. return files;
  681. }
  682. BDE GetUrisXmlRpcMethod::process
  683. (const XmlRpcRequest& req, DownloadEngine* e)
  684. {
  685. const BDE& params = req._params;
  686. assert(params.isList());
  687. if(params.empty() || !params[0].isString()) {
  688. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  689. }
  690. gid_t gid = util::parseLLInt(params[0].s());
  691. SharedHandle<RequestGroup> group =
  692. findRequestGroup(e->getRequestGroupMan(), gid);
  693. if(group.isNull()) {
  694. throw DL_ABORT_EX
  695. (StringFormat("No URI data is available for GID#%s",
  696. util::itos(gid).c_str()).str());
  697. }
  698. BDE uriList = BDE::list();
  699. // TODO Current implementation just returns first FileEntry's URIs.
  700. if(!group->getDownloadContext()->getFileEntries().empty()) {
  701. createUriEntry(uriList, group->getDownloadContext()->getFirstFileEntry());
  702. }
  703. return uriList;
  704. }
  705. #ifdef ENABLE_BITTORRENT
  706. BDE GetPeersXmlRpcMethod::process
  707. (const XmlRpcRequest& req, DownloadEngine* e)
  708. {
  709. const BDE& params = req._params;
  710. assert(params.isList());
  711. if(params.empty() || !params[0].isString()) {
  712. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  713. }
  714. gid_t gid = util::parseLLInt(params[0].s());
  715. SharedHandle<RequestGroup> group =
  716. findRequestGroup(e->getRequestGroupMan(), gid);
  717. if(group.isNull()) {
  718. throw DL_ABORT_EX
  719. (StringFormat("No peer data is available for GID#%s",
  720. util::itos(gid).c_str()).str());
  721. }
  722. BDE peers = BDE::list();
  723. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  724. if(!btObject.isNull()) {
  725. assert(!btObject._peerStorage.isNull());
  726. gatherPeer(peers, btObject._peerStorage);
  727. }
  728. return peers;
  729. }
  730. #endif // ENABLE_BITTORRENT
  731. BDE TellStatusXmlRpcMethod::process
  732. (const XmlRpcRequest& req, DownloadEngine* e)
  733. {
  734. const BDE& params = req._params;
  735. assert(params.isList());
  736. if(params.empty() || !params[0].isString()) {
  737. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  738. }
  739. gid_t gid = util::parseLLInt(params[0].s());
  740. SharedHandle<RequestGroup> group =
  741. e->getRequestGroupMan()->findRequestGroup(gid);
  742. BDE entryDict = BDE::dict();
  743. if(group.isNull()) {
  744. group = e->getRequestGroupMan()->findReservedGroup(gid);
  745. if(group.isNull()) {
  746. SharedHandle<DownloadResult> ds =
  747. e->getRequestGroupMan()->findDownloadResult(gid);
  748. if(ds.isNull()) {
  749. throw DL_ABORT_EX
  750. (StringFormat("No such download for GID#%s",
  751. util::itos(gid).c_str()).str());
  752. }
  753. gatherStoppedDownload(entryDict, ds);
  754. } else {
  755. if(group->isPauseRequested()) {
  756. entryDict[KEY_STATUS] = BDE_PAUSED;
  757. } else {
  758. entryDict[KEY_STATUS] = BDE_WAITING;
  759. }
  760. gatherProgress(entryDict, group, e);
  761. }
  762. } else {
  763. entryDict[KEY_STATUS] = BDE_ACTIVE;
  764. gatherProgress(entryDict, group, e);
  765. }
  766. return entryDict;
  767. }
  768. BDE TellActiveXmlRpcMethod::process
  769. (const XmlRpcRequest& req, DownloadEngine* e)
  770. {
  771. BDE list = BDE::list();
  772. const std::deque<SharedHandle<RequestGroup> >& groups =
  773. e->getRequestGroupMan()->getRequestGroups();
  774. for(std::deque<SharedHandle<RequestGroup> >::const_iterator i =
  775. groups.begin(), eoi = groups.end(); i != eoi; ++i) {
  776. BDE entryDict = BDE::dict();
  777. entryDict[KEY_STATUS] = BDE_ACTIVE;
  778. gatherProgress(entryDict, *i, e);
  779. list << entryDict;
  780. }
  781. return list;
  782. }
  783. const std::deque<SharedHandle<RequestGroup> >&
  784. TellWaitingXmlRpcMethod::getItems(DownloadEngine* e) const
  785. {
  786. return e->getRequestGroupMan()->getReservedGroups();
  787. }
  788. void TellWaitingXmlRpcMethod::createEntry
  789. (BDE& entryDict, const SharedHandle<RequestGroup>& item,
  790. DownloadEngine* e) const
  791. {
  792. if(item->isPauseRequested()) {
  793. entryDict[KEY_STATUS] = BDE_PAUSED;
  794. } else {
  795. entryDict[KEY_STATUS] = BDE_WAITING;
  796. }
  797. gatherProgress(entryDict, item, e);
  798. }
  799. const std::deque<SharedHandle<DownloadResult> >&
  800. TellStoppedXmlRpcMethod::getItems(DownloadEngine* e) const
  801. {
  802. return e->getRequestGroupMan()->getDownloadResults();
  803. }
  804. void TellStoppedXmlRpcMethod::createEntry
  805. (BDE& entryDict, const SharedHandle<DownloadResult>& item,
  806. DownloadEngine* e) const
  807. {
  808. gatherStoppedDownload(entryDict, item);
  809. }
  810. BDE PurgeDownloadResultXmlRpcMethod::process
  811. (const XmlRpcRequest& req, DownloadEngine* e)
  812. {
  813. e->getRequestGroupMan()->purgeDownloadResult();
  814. return BDE_OK;
  815. }
  816. BDE ChangeOptionXmlRpcMethod::process
  817. (const XmlRpcRequest& req, DownloadEngine* e)
  818. {
  819. const BDE& params = req._params;
  820. assert(params.isList());
  821. if(params.empty() || !params[0].isString()) {
  822. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  823. }
  824. gid_t gid = util::parseLLInt(params[0].s());
  825. SharedHandle<RequestGroup> group =
  826. findRequestGroup(e->getRequestGroupMan(), gid);
  827. if(group.isNull()) {
  828. throw DL_ABORT_EX
  829. (StringFormat("Cannot change option for GID#%s",
  830. util::itos(gid).c_str()).str());
  831. }
  832. SharedHandle<Option> option(new Option());
  833. if(params.size() > 1 && params[1].isDict()) {
  834. gatherChangeableOption(option, params[1]);
  835. applyChangeableOption(group->getOption().get(), option.get());
  836. if(option->defined(PREF_MAX_DOWNLOAD_LIMIT)) {
  837. group->setMaxDownloadSpeedLimit
  838. (option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
  839. }
  840. if(option->defined(PREF_MAX_UPLOAD_LIMIT)) {
  841. group->setMaxUploadSpeedLimit(option->getAsInt(PREF_MAX_UPLOAD_LIMIT));
  842. }
  843. #ifdef ENABLE_BITTORRENT
  844. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  845. if(!btObject.isNull()) {
  846. if(option->defined(PREF_BT_MAX_PEERS)) {
  847. btObject._btRuntime->setMaxPeers(option->getAsInt(PREF_BT_MAX_PEERS));
  848. }
  849. }
  850. #endif // ENABLE_BITTORRENT
  851. }
  852. return BDE_OK;
  853. }
  854. BDE ChangeGlobalOptionXmlRpcMethod::process
  855. (const XmlRpcRequest& req, DownloadEngine* e)
  856. {
  857. const BDE& params = req._params;
  858. assert(params.isList());
  859. if(params.empty() || !params[0].isDict()) {
  860. return BDE_OK;
  861. }
  862. SharedHandle<Option> option(new Option());
  863. gatherChangeableGlobalOption(option, params[0]);
  864. applyChangeableGlobalOption(e->getOption(), option.get());
  865. if(option->defined(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)) {
  866. e->getRequestGroupMan()->setMaxOverallDownloadSpeedLimit
  867. (option->getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT));
  868. }
  869. if(option->defined(PREF_MAX_OVERALL_UPLOAD_LIMIT)) {
  870. e->getRequestGroupMan()->setMaxOverallUploadSpeedLimit
  871. (option->getAsInt(PREF_MAX_OVERALL_UPLOAD_LIMIT));
  872. }
  873. if(option->defined(PREF_MAX_CONCURRENT_DOWNLOADS)) {
  874. e->getRequestGroupMan()->setMaxSimultaneousDownloads
  875. (option->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
  876. e->getRequestGroupMan()->requestQueueCheck();
  877. }
  878. return BDE_OK;
  879. }
  880. BDE GetVersionXmlRpcMethod::process
  881. (const XmlRpcRequest& req, DownloadEngine* e)
  882. {
  883. BDE result = BDE::dict();
  884. result[KEY_VERSION] = std::string(PACKAGE_VERSION);
  885. BDE featureList = BDE::list();
  886. const FeatureMap& features = FeatureConfig::getInstance()->getFeatures();
  887. for(FeatureMap::const_iterator i = features.begin(), eoi = features.end();
  888. i != eoi;++i){
  889. if((*i).second) {
  890. featureList << (*i).first;
  891. }
  892. }
  893. result[KEY_ENABLED_FEATURES] = featureList;
  894. return result;
  895. }
  896. template<typename InputIterator>
  897. static void pushRequestOption
  898. (BDE& dict, InputIterator optionFirst, InputIterator optionLast)
  899. {
  900. const std::set<std::string>& requestOptions = listRequestOptions();
  901. for(; optionFirst != optionLast; ++optionFirst) {
  902. if(requestOptions.count((*optionFirst).first)) {
  903. dict[(*optionFirst).first] = (*optionFirst).second;
  904. }
  905. }
  906. }
  907. BDE GetOptionXmlRpcMethod::process
  908. (const XmlRpcRequest& req, DownloadEngine* e)
  909. {
  910. const BDE& params = req._params;
  911. assert(params.isList());
  912. if(params.empty() || !params[0].isString()) {
  913. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  914. }
  915. gid_t gid = util::parseLLInt(params[0].s());
  916. SharedHandle<RequestGroup> group =
  917. findRequestGroup(e->getRequestGroupMan(), gid);
  918. if(group.isNull()) {
  919. throw DL_ABORT_EX
  920. (StringFormat("Cannot get option for GID#%s",
  921. util::itos(gid).c_str()).str());
  922. }
  923. BDE result = BDE::dict();
  924. SharedHandle<Option> option = group->getOption();
  925. pushRequestOption(result, option->begin(), option->end());
  926. return result;
  927. }
  928. BDE GetGlobalOptionXmlRpcMethod::process
  929. (const XmlRpcRequest& req, DownloadEngine* e)
  930. {
  931. BDE result = BDE::dict();
  932. for(std::map<std::string, std::string>::const_iterator i =
  933. e->getOption()->begin(), eoi = e->getOption()->end(); i != eoi; ++i) {
  934. SharedHandle<OptionHandler> h = _optionParser->findByName((*i).first);
  935. if(!h.isNull() && !h->isHidden()) {
  936. result[(*i).first] = (*i).second;
  937. }
  938. }
  939. return result;
  940. }
  941. BDE ChangePositionXmlRpcMethod::process
  942. (const XmlRpcRequest& req, DownloadEngine* e)
  943. {
  944. const BDE& params = req._params;
  945. assert(params.isList());
  946. if(params.size() != 3 ||
  947. !params[0].isString() || !params[1].isInteger() || !params[2].isString()) {
  948. throw DL_ABORT_EX("Illegal argument.");
  949. }
  950. gid_t gid = util::parseLLInt(params[0].s());
  951. int pos = params[1].i();
  952. const std::string& howStr = params[2].s();
  953. RequestGroupMan::HOW how;
  954. if(howStr == "POS_SET") {
  955. how = RequestGroupMan::POS_SET;
  956. } else if(howStr == "POS_CUR") {
  957. how = RequestGroupMan::POS_CUR;
  958. } else if(howStr == "POS_END") {
  959. how = RequestGroupMan::POS_END;
  960. } else {
  961. throw DL_ABORT_EX("Illegal argument.");
  962. }
  963. size_t destPos =
  964. e->getRequestGroupMan()->changeReservedGroupPosition(gid, pos, how);
  965. BDE result(destPos);
  966. return result;
  967. }
  968. BDE GetSessionInfoXmlRpcMethod::process
  969. (const XmlRpcRequest& req, DownloadEngine* e)
  970. {
  971. BDE result = BDE::dict();
  972. result[KEY_SESSION_ID] = util::toHex(e->getSessionId());
  973. return result;
  974. }
  975. BDE GetServersXmlRpcMethod::process
  976. (const XmlRpcRequest& req, DownloadEngine* e)
  977. {
  978. const BDE& params = req._params;
  979. assert(params.isList());
  980. if(params.empty() || !params[0].isString()) {
  981. throw DL_ABORT_EX("Bad request");
  982. }
  983. gid_t gid = util::parseLLInt(params[0].s());
  984. SharedHandle<RequestGroup> group =
  985. e->getRequestGroupMan()->findRequestGroup(gid);
  986. if(group.isNull()) {
  987. throw DL_ABORT_EX(StringFormat("No active download for GID#%s",
  988. util::itos(gid).c_str()).str());
  989. }
  990. const SharedHandle<DownloadContext>& dctx = group->getDownloadContext();
  991. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  992. BDE result = BDE::list();
  993. size_t index = 1;
  994. for(std::vector<SharedHandle<FileEntry> >::const_iterator fi = files.begin(),
  995. eoi = files.end(); fi != eoi; ++fi, ++index) {
  996. BDE fileEntry = BDE::dict();
  997. fileEntry[KEY_INDEX] = util::uitos(index);
  998. BDE servers = BDE::list();
  999. const std::deque<SharedHandle<Request> >& requests =
  1000. (*fi)->getInFlightRequests();
  1001. for(std::deque<SharedHandle<Request> >::const_iterator ri =requests.begin(),
  1002. eoi = requests.end(); ri != eoi; ++ri) {
  1003. SharedHandle<PeerStat> ps = (*ri)->getPeerStat();
  1004. if(!ps.isNull()) {
  1005. BDE serverEntry = BDE::dict();
  1006. serverEntry[KEY_URI] = (*ri)->getUri();
  1007. serverEntry[KEY_CURRENT_URI] = (*ri)->getCurrentUri();
  1008. serverEntry[KEY_DOWNLOAD_SPEED] =
  1009. util::uitos(ps->calculateDownloadSpeed());
  1010. servers << serverEntry;
  1011. }
  1012. }
  1013. fileEntry[KEY_SERVERS] = servers;
  1014. result << fileEntry;
  1015. }
  1016. return result;
  1017. }
  1018. BDE ChangeUriXmlRpcMethod::process
  1019. (const XmlRpcRequest& req, DownloadEngine* e)
  1020. {
  1021. const BDE& params = req._params;
  1022. assert(params.isList());
  1023. if(params.size() < 4 ||
  1024. !params[0].isString() || !params[1].isInteger() ||
  1025. !params[2].isList() || !params[3].isList() ||
  1026. params[1].i() <= 0) {
  1027. throw DL_ABORT_EX("Bad request");
  1028. }
  1029. size_t pos = 0;
  1030. bool posGiven = false;
  1031. getPosParam(params, 4, posGiven, pos);
  1032. gid_t gid = util::parseLLInt(params[0].s());
  1033. size_t index = params[1].i()-1;
  1034. const BDE& deluris = params[2];
  1035. const BDE& adduris = params[3];
  1036. SharedHandle<RequestGroup> group =
  1037. findRequestGroup(e->getRequestGroupMan(), gid);
  1038. if(group.isNull()) {
  1039. throw DL_ABORT_EX
  1040. (StringFormat("Cannot remove URIs from GID#%s",
  1041. util::itos(gid).c_str()).str());
  1042. }
  1043. const SharedHandle<DownloadContext>& dctx = group->getDownloadContext();
  1044. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  1045. if(files.size() <= index) {
  1046. throw DL_ABORT_EX(StringFormat("fileIndex is out of range").str());
  1047. }
  1048. SharedHandle<FileEntry> s = files[index];
  1049. size_t delcount = 0;
  1050. for(BDE::List::const_iterator i = deluris.listBegin(),
  1051. eoi = deluris.listEnd(); i != eoi; ++i) {
  1052. if(s->removeUri((*i).s())) {
  1053. ++delcount;
  1054. }
  1055. }
  1056. size_t addcount = 0;
  1057. if(posGiven) {
  1058. for(BDE::List::const_iterator i = adduris.listBegin(),
  1059. eoi = adduris.listEnd(); i != eoi; ++i) {
  1060. if(s->insertUri((*i).s(), pos)) {
  1061. ++addcount;
  1062. ++pos;
  1063. }
  1064. }
  1065. } else {
  1066. for(BDE::List::const_iterator i = adduris.listBegin(),
  1067. eoi = adduris.listEnd(); i != eoi; ++i) {
  1068. if(s->addUri((*i).s())) {
  1069. ++addcount;
  1070. }
  1071. }
  1072. }
  1073. if(addcount && !group->getPieceStorage().isNull()) {
  1074. std::vector<Command*> commands;
  1075. group->createNextCommand(commands, e);
  1076. e->addCommand(commands);
  1077. group->getSegmentMan()->recognizeSegmentFor(s);
  1078. }
  1079. BDE res = BDE::list();
  1080. res << delcount;
  1081. res << addcount;
  1082. return res;
  1083. }
  1084. static BDE goingShutdown
  1085. (const XmlRpcRequest& req, DownloadEngine* e, bool forceHalt)
  1086. {
  1087. // Schedule shutdown after 3seconds to give time to client to
  1088. // receive XML-RPC response.
  1089. e->addRoutineCommand(new TimedHaltCommand(e->newCUID(), e, 3, forceHalt));
  1090. LogFactory::getInstance()->info("Scheduled shutdown in 3 seconds.");
  1091. return BDE_OK;
  1092. }
  1093. BDE ShutdownXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  1094. {
  1095. return goingShutdown(req, e, false);
  1096. }
  1097. BDE ForceShutdownXmlRpcMethod::process
  1098. (const XmlRpcRequest& req, DownloadEngine* e)
  1099. {
  1100. return goingShutdown(req, e, true);
  1101. }
  1102. BDE SystemMulticallXmlRpcMethod::process
  1103. (const XmlRpcRequest& req, DownloadEngine* e)
  1104. {
  1105. const BDE& params = req._params;
  1106. assert(params.isList());
  1107. if(params.size() != 1) {
  1108. throw DL_ABORT_EX("Illegal argument. One item list is expected.");
  1109. }
  1110. const BDE& methodSpecs = params[0];
  1111. BDE list = BDE::list();
  1112. for(BDE::List::const_iterator i = methodSpecs.listBegin(),
  1113. eoi = methodSpecs.listEnd(); i != eoi; ++i) {
  1114. if(!(*i).isDict()) {
  1115. list << createErrorResponse
  1116. (DL_ABORT_EX("system.multicall expected struct."));
  1117. continue;
  1118. }
  1119. if(!(*i).containsKey(KEY_METHOD_NAME) ||
  1120. !(*i).containsKey(KEY_PARAMS)) {
  1121. list << createErrorResponse
  1122. (DL_ABORT_EX("Missing methodName or params."));
  1123. continue;
  1124. }
  1125. const std::string& methodName = (*i)[KEY_METHOD_NAME].s();
  1126. if(methodName == getMethodName()) {
  1127. list << createErrorResponse
  1128. (DL_ABORT_EX("Recursive system.multicall forbidden."));
  1129. continue;
  1130. }
  1131. SharedHandle<XmlRpcMethod> method = XmlRpcMethodFactory::create(methodName);
  1132. XmlRpcRequest innerReq(methodName, (*i)[KEY_PARAMS]);
  1133. XmlRpcResponse res = method->execute(innerReq, e);
  1134. if(res._code == 0) {
  1135. BDE l = BDE::list();
  1136. l << res._param;
  1137. list << l;
  1138. } else {
  1139. list << res._param;
  1140. }
  1141. }
  1142. return list;
  1143. }
  1144. BDE NoSuchMethodXmlRpcMethod::process
  1145. (const XmlRpcRequest& req, DownloadEngine* e)
  1146. {
  1147. throw DL_ABORT_EX
  1148. (StringFormat("No such method: %s", req._methodName.c_str()).str());
  1149. }
  1150. } // namespace xmlrpc
  1151. } // namespace aria2