XmlRpcMethodImpl.cc 44 KB

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