XmlRpcMethodImpl.cc 36 KB

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