DownloadEngine.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 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 "DownloadEngine.h"
  36. #include "Socket.h"
  37. #include "NameResolver.h"
  38. #include "StatCalc.h"
  39. #include "RequestGroup.h"
  40. #include "RequestGroupMan.h"
  41. #include "FileAllocationMan.h"
  42. #ifdef ENABLE_MESSAGE_DIGEST
  43. #include "CheckIntegrityMan.h"
  44. #endif // ENABLE_MESSAGE_DIGEST
  45. #include "Util.h"
  46. #include "LogFactory.h"
  47. #include "TimeA2.h"
  48. #include <unistd.h>
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <fcntl.h>
  52. #include <errno.h>
  53. #include <signal.h>
  54. #include <algorithm>
  55. volatile sig_atomic_t globalHaltRequested;
  56. SocketEntry::SocketEntry(const SocketHandle& socket,
  57. Command* command,
  58. TYPE type):
  59. socket(socket), command(command), type(type) {}
  60. bool SocketEntry::operator==(const SocketEntry& entry)
  61. {
  62. return socket == entry.socket &&
  63. command == entry.command &&
  64. type == entry.type;
  65. }
  66. #ifdef ENABLE_ASYNC_DNS
  67. NameResolverEntry::NameResolverEntry(const NameResolverHandle& nameResolver,
  68. Command* command):
  69. nameResolver(nameResolver), command(command) {}
  70. bool NameResolverEntry::operator==(const NameResolverEntry& entry)
  71. {
  72. return nameResolver == entry.nameResolver &&
  73. command == entry.command;
  74. }
  75. #endif // ENABLE_ASYNC_DNS
  76. DownloadEngine::DownloadEngine():logger(LogFactory::getInstance()),
  77. _statCalc(0),
  78. _haltRequested(false),
  79. noWait(false),
  80. _requestGroupMan(0),
  81. _fileAllocationMan(0)
  82. #ifdef ENABLE_MESSAGE_DIGEST
  83. ,
  84. _checkIntegrityMan(0)
  85. #endif // ENABLE_MESSAGE_DIGEST
  86. {}
  87. DownloadEngine::~DownloadEngine() {
  88. cleanQueue();
  89. }
  90. void DownloadEngine::cleanQueue() {
  91. for_each(commands.begin(), commands.end(), Deleter());
  92. commands.clear();
  93. }
  94. void DownloadEngine::executeCommand(Command::STATUS statusFilter)
  95. {
  96. int32_t max = commands.size();
  97. for(int32_t i = 0; i < max; i++) {
  98. Command* com = commands.front();
  99. commands.pop_front();
  100. if(com->statusMatch(statusFilter)) {
  101. if(com->execute()) {
  102. delete com;
  103. } else {
  104. com->transitStatus();
  105. }
  106. } else {
  107. commands.push_back(com);
  108. }
  109. }
  110. }
  111. void DownloadEngine::run() {
  112. Time cp;
  113. cp.setTimeInSec(0);
  114. Commands activeCommands;
  115. while(!commands.empty()) {
  116. if(cp.elapsed(1)) {
  117. cp.reset();
  118. executeCommand(Command::STATUS_ALL);
  119. } else {
  120. executeCommand(Command::STATUS_ACTIVE);
  121. }
  122. afterEachIteration();
  123. if(!commands.empty()) {
  124. waitData();
  125. }
  126. noWait = false;
  127. calculateStatistics();
  128. }
  129. onEndOfRun();
  130. }
  131. void DownloadEngine::shortSleep() const {
  132. struct timeval tv;
  133. tv.tv_sec = 0;
  134. tv.tv_usec = 1000;
  135. fd_set rfds;
  136. FD_ZERO(&rfds);
  137. select(0, &rfds, NULL, NULL, &tv);
  138. }
  139. void DownloadEngine::waitData() {
  140. fd_set rfds;
  141. fd_set wfds;
  142. int32_t retval = 0;
  143. struct timeval tv;
  144. memcpy(&rfds, &rfdset, sizeof(fd_set));
  145. memcpy(&wfds, &wfdset, sizeof(fd_set));
  146. tv.tv_sec = noWait ? 0 : 1;
  147. tv.tv_usec = 0;
  148. retval = select(fdmax+1, &rfds, &wfds, NULL, &tv);
  149. if(retval > 0) {
  150. for(SocketEntries::iterator itr = socketEntries.begin();
  151. itr != socketEntries.end(); ++itr) {
  152. SocketEntry& entry = *itr;
  153. if(FD_ISSET(entry.socket->getSockfd(), &rfds) ||
  154. FD_ISSET(entry.socket->getSockfd(), &wfds)) {
  155. entry.command->setStatusActive();
  156. }
  157. }
  158. #ifdef ENABLE_ASYNC_DNS
  159. for(NameResolverEntries::iterator itr = nameResolverEntries.begin();
  160. itr != nameResolverEntries.end(); ++itr) {
  161. NameResolverEntry& entry = *itr;
  162. entry.nameResolver->process(&rfds, &wfds);
  163. switch(entry.nameResolver->getStatus()) {
  164. case NameResolver::STATUS_SUCCESS:
  165. case NameResolver::STATUS_ERROR:
  166. entry.command->setStatusActive();
  167. break;
  168. default:
  169. break;
  170. }
  171. }
  172. #endif // ENABLE_ASYNC_DNS
  173. }
  174. }
  175. void DownloadEngine::updateFdSet() {
  176. fdmax = 0;
  177. FD_ZERO(&rfdset);
  178. FD_ZERO(&wfdset);
  179. #ifdef ENABLE_ASYNC_DNS
  180. for(NameResolverEntries::iterator itr = nameResolverEntries.begin();
  181. itr != nameResolverEntries.end(); ++itr) {
  182. NameResolverEntry& entry = *itr;
  183. int32_t fd = entry.nameResolver->getFds(&rfdset, &wfdset);
  184. if(fdmax < fd) {
  185. fdmax = fd;
  186. }
  187. }
  188. #endif // ENABLE_ASYNC_DNS
  189. for(SocketEntries::iterator itr = socketEntries.begin();
  190. itr != socketEntries.end(); ++itr) {
  191. SocketEntry& entry = *itr;
  192. int32_t fd = entry.socket->getSockfd();
  193. switch(entry.type) {
  194. case SocketEntry::TYPE_RD:
  195. FD_SET(fd, &rfdset);
  196. break;
  197. case SocketEntry::TYPE_WR:
  198. FD_SET(fd, &wfdset);
  199. break;
  200. }
  201. if(fdmax < fd) {
  202. fdmax = fd;
  203. }
  204. }
  205. }
  206. bool DownloadEngine::addSocket(const SocketEntry& entry) {
  207. SocketEntries::iterator itr =
  208. find(socketEntries.begin(), socketEntries.end(), entry);
  209. if(itr == socketEntries.end()) {
  210. socketEntries.push_back(entry);
  211. updateFdSet();
  212. return true;
  213. } else {
  214. return false;
  215. }
  216. }
  217. bool DownloadEngine::deleteSocket(const SocketEntry& entry) {
  218. SocketEntries::iterator itr =
  219. find(socketEntries.begin(), socketEntries.end(), entry);
  220. if(itr == socketEntries.end()) {
  221. return false;
  222. } else {
  223. socketEntries.erase(itr);
  224. updateFdSet();
  225. return true;
  226. }
  227. }
  228. bool DownloadEngine::addSocketForReadCheck(const SocketHandle& socket,
  229. Command* command) {
  230. SocketEntry entry(socket, command, SocketEntry::TYPE_RD);
  231. return addSocket(entry);
  232. }
  233. bool DownloadEngine::deleteSocketForReadCheck(const SocketHandle& socket,
  234. Command* command) {
  235. SocketEntry entry(socket, command, SocketEntry::TYPE_RD);
  236. return deleteSocket(entry);
  237. }
  238. bool DownloadEngine::addSocketForWriteCheck(const SocketHandle& socket,
  239. Command* command) {
  240. SocketEntry entry(socket, command, SocketEntry::TYPE_WR);
  241. return addSocket(entry);
  242. }
  243. bool DownloadEngine::deleteSocketForWriteCheck(const SocketHandle& socket,
  244. Command* command) {
  245. SocketEntry entry(socket, command, SocketEntry::TYPE_WR);
  246. return deleteSocket(entry);
  247. }
  248. void DownloadEngine::calculateStatistics()
  249. {
  250. if(!_statCalc.isNull()) {
  251. _statCalc->calculateStat(_requestGroupMan, _fileAllocationMan, _checkIntegrityMan);
  252. }
  253. }
  254. void DownloadEngine::onEndOfRun()
  255. {
  256. _requestGroupMan->closeFile();
  257. _requestGroupMan->save();
  258. }
  259. void DownloadEngine::afterEachIteration()
  260. {
  261. if(globalHaltRequested) {
  262. globalHaltRequested = false;
  263. _haltRequested = true;
  264. _requestGroupMan->halt();
  265. }
  266. }
  267. void DownloadEngine::fillCommand()
  268. {
  269. addCommand(_requestGroupMan->getInitialCommands(this));
  270. }
  271. void DownloadEngine::setStatCalc(const StatCalcHandle& statCalc)
  272. {
  273. _statCalc = statCalc;
  274. }
  275. #ifdef ENABLE_ASYNC_DNS
  276. bool DownloadEngine::addNameResolverCheck(const NameResolverHandle& resolver,
  277. Command* command) {
  278. NameResolverEntry entry(resolver, command);
  279. NameResolverEntries::iterator itr = find(nameResolverEntries.begin(),
  280. nameResolverEntries.end(),
  281. entry);
  282. if(itr == nameResolverEntries.end()) {
  283. nameResolverEntries.push_back(entry);
  284. updateFdSet();
  285. return true;
  286. } else {
  287. return false;
  288. }
  289. }
  290. bool DownloadEngine::deleteNameResolverCheck(const NameResolverHandle& resolver,
  291. Command* command) {
  292. NameResolverEntry entry(resolver, command);
  293. NameResolverEntries::iterator itr = find(nameResolverEntries.begin(),
  294. nameResolverEntries.end(),
  295. entry);
  296. if(itr == nameResolverEntries.end()) {
  297. return false;
  298. } else {
  299. nameResolverEntries.erase(itr);
  300. updateFdSet();
  301. return true;
  302. }
  303. }
  304. void DownloadEngine::addCommand(const Commands& commands)
  305. {
  306. this->commands.insert(this->commands.end(), commands.begin(), commands.end());
  307. }
  308. #endif // ENABLE_ASYNC_DNS