FtpNegotiationCommand.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - a simple utility for downloading files faster
  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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. /* copyright --> */
  22. #include "FtpNegotiationCommand.h"
  23. #include "FtpDownloadCommand.h"
  24. #include "DlAbortEx.h"
  25. #include "DlRetryEx.h"
  26. #include "message.h"
  27. #include "prefs.h"
  28. FtpNegotiationCommand::FtpNegotiationCommand(int cuid, Request* req, DownloadEngine* e, const Socket* s):
  29. AbstractCommand(cuid, req, e, s),
  30. dataSocket(NULL), serverSocket(NULL), sequence(SEQ_RECV_GREETING)
  31. {
  32. ftp = new FtpConnection(cuid, socket, req, e->option);
  33. setReadCheckSocket(NULL);
  34. setWriteCheckSocket(socket);
  35. }
  36. FtpNegotiationCommand::~FtpNegotiationCommand() {
  37. if(dataSocket != NULL) {
  38. delete dataSocket;
  39. }
  40. if(serverSocket != NULL) {
  41. delete serverSocket;
  42. }
  43. delete ftp;
  44. }
  45. bool FtpNegotiationCommand::executeInternal(Segment segment) {
  46. while(processSequence(segment));
  47. if(sequence == SEQ_RETRY) {
  48. return prepareForRetry(0);
  49. } else if(sequence == SEQ_NEGOTIATION_COMPLETED) {
  50. FtpDownloadCommand* command = new FtpDownloadCommand(cuid, req, e, dataSocket, socket);
  51. e->commands.push(command);
  52. return true;
  53. } else {
  54. e->commands.push(this);
  55. return false;
  56. }
  57. }
  58. bool FtpNegotiationCommand::recvGreeting() {
  59. socket->setBlockingMode();
  60. int status = ftp->receiveResponse();
  61. if(status == 0) {
  62. return false;
  63. }
  64. if(status != 220) {
  65. throw new DlRetryEx(EX_CONNECTION_FAILED);
  66. }
  67. sequence = SEQ_SEND_USER;
  68. setReadCheckSocket(socket);
  69. setWriteCheckSocket(NULL);
  70. return true;
  71. }
  72. bool FtpNegotiationCommand::sendUser() {
  73. ftp->sendUser();
  74. sequence = SEQ_RECV_USER;
  75. return false;
  76. }
  77. bool FtpNegotiationCommand::recvUser() {
  78. int status = ftp->receiveResponse();
  79. switch(status) {
  80. case 0:
  81. return false;
  82. case 230:
  83. sequence = SEQ_SEND_TYPE;
  84. break;
  85. case 331:
  86. sequence = SEQ_SEND_PASS;
  87. break;
  88. default:
  89. throw new DlRetryEx(EX_BAD_STATUS, status);
  90. }
  91. return true;
  92. }
  93. bool FtpNegotiationCommand::sendPass() {
  94. ftp->sendPass();
  95. sequence = SEQ_RECV_PASS;
  96. return false;
  97. }
  98. bool FtpNegotiationCommand::recvPass() {
  99. int status = ftp->receiveResponse();
  100. if(status == 0) {
  101. return false;
  102. }
  103. if(status != 230) {
  104. throw new DlRetryEx(EX_BAD_STATUS, status);
  105. }
  106. sequence = SEQ_SEND_TYPE;
  107. return true;
  108. }
  109. bool FtpNegotiationCommand::sendType() {
  110. ftp->sendType();
  111. sequence = SEQ_RECV_TYPE;
  112. return false;
  113. }
  114. bool FtpNegotiationCommand::recvType() {
  115. int status = ftp->receiveResponse();
  116. if(status == 0) {
  117. return false;
  118. }
  119. if(status != 200) {
  120. throw new DlRetryEx(EX_BAD_STATUS, status);
  121. }
  122. sequence = SEQ_SEND_CWD;
  123. return true;
  124. }
  125. bool FtpNegotiationCommand::sendCwd() {
  126. ftp->sendCwd();
  127. sequence = SEQ_RECV_CWD;
  128. return false;
  129. }
  130. bool FtpNegotiationCommand::recvCwd() {
  131. int status = ftp->receiveResponse();
  132. if(status == 0) {
  133. return false;
  134. }
  135. if(status != 250) {
  136. throw new DlRetryEx(EX_BAD_STATUS, status);
  137. }
  138. sequence = SEQ_SEND_SIZE;
  139. return true;
  140. }
  141. bool FtpNegotiationCommand::sendSize() {
  142. ftp->sendSize();
  143. sequence = SEQ_RECV_SIZE;
  144. return false;
  145. }
  146. bool FtpNegotiationCommand::recvSize() {
  147. long long int size = 0;
  148. int status = ftp->receiveSizeResponse(size);
  149. if(status == 0) {
  150. return false;
  151. }
  152. if(status != 213) {
  153. throw new DlRetryEx(EX_BAD_STATUS, status);
  154. }
  155. if(size == LONG_LONG_MAX || size < 0) {
  156. throw new DlAbortEx(EX_TOO_LARGE_FILE, size);
  157. }
  158. if(!e->segmentMan->downloadStarted) {
  159. e->segmentMan->downloadStarted = true;
  160. e->segmentMan->totalSize = size;
  161. } else if(e->segmentMan->totalSize != size) {
  162. throw new DlAbortEx(EX_SIZE_MISMATCH, e->segmentMan->totalSize, size);
  163. }
  164. if(e->option->get(PREF_FTP_PASV_ENABLED) == V_TRUE) {
  165. sequence = SEQ_SEND_PASV;
  166. } else {
  167. sequence = SEQ_SEND_PORT;
  168. }
  169. return true;
  170. }
  171. bool FtpNegotiationCommand::sendPort() {
  172. serverSocket = ftp->sendPort();
  173. sequence = SEQ_RECV_PORT;
  174. return false;
  175. }
  176. bool FtpNegotiationCommand::recvPort() {
  177. int status = ftp->receiveResponse();
  178. if(status == 0) {
  179. return false;
  180. }
  181. if(status != 200) {
  182. throw new DlRetryEx(EX_BAD_STATUS, status);
  183. }
  184. sequence = SEQ_SEND_REST;
  185. return true;
  186. }
  187. bool FtpNegotiationCommand::sendPasv() {
  188. ftp->sendPasv();
  189. sequence = SEQ_RECV_PASV;
  190. return false;
  191. }
  192. bool FtpNegotiationCommand::recvPasv() {
  193. pair<string, int> dest;
  194. int status = ftp->receivePasvResponse(dest);
  195. if(status == 0) {
  196. return false;
  197. }
  198. if(status != 227) {
  199. throw new DlRetryEx(EX_BAD_STATUS, status);
  200. }
  201. // make a data connection to the server.
  202. dataSocket = new Socket();
  203. logger->info(MSG_CONNECTING_TO_SERVER, cuid,
  204. dest.first.c_str(),
  205. dest.second);
  206. dataSocket->establishConnection(dest.first, dest.second);
  207. setReadCheckSocket(NULL);
  208. setWriteCheckSocket(dataSocket);
  209. sequence = SEQ_SEND_REST_PASV;
  210. return false;
  211. }
  212. bool FtpNegotiationCommand::sendRestPasv(const Segment& segment) {
  213. dataSocket->setBlockingMode();
  214. setReadCheckSocket(socket);
  215. setWriteCheckSocket(NULL);
  216. return sendRest(segment);
  217. }
  218. bool FtpNegotiationCommand::sendRest(const Segment& segment) {
  219. ftp->sendRest(segment);
  220. sequence = SEQ_RECV_REST;
  221. return false;
  222. }
  223. bool FtpNegotiationCommand::recvRest() {
  224. int status = ftp->receiveResponse();
  225. if(status == 0) {
  226. return false;
  227. }
  228. // TODO if we recieve negative response, then we set e->segmentMan->splittable = false, and continue.
  229. if(status != 350) {
  230. throw new DlRetryEx(EX_BAD_STATUS, status);
  231. }
  232. sequence = SEQ_SEND_RETR;
  233. return true;
  234. }
  235. bool FtpNegotiationCommand::sendRetr() {
  236. ftp->sendRetr();
  237. sequence = SEQ_RECV_RETR;
  238. return false;
  239. }
  240. bool FtpNegotiationCommand::recvRetr() {
  241. int status = ftp->receiveResponse();
  242. if(status == 0) {
  243. return false;
  244. }
  245. if(status != 150) {
  246. throw new DlRetryEx(EX_BAD_STATUS, status);
  247. }
  248. if(e->option->get(PREF_FTP_PASV_ENABLED) != V_TRUE) {
  249. assert(serverSocket);
  250. dataSocket = serverSocket->acceptConnection();
  251. }
  252. sequence = SEQ_NEGOTIATION_COMPLETED;
  253. return false;
  254. }
  255. bool FtpNegotiationCommand::processSequence(const Segment& segment) {
  256. bool doNextSequence = true;
  257. switch(sequence) {
  258. case SEQ_RECV_GREETING:
  259. return recvGreeting();
  260. case SEQ_SEND_USER:
  261. return sendUser();
  262. case SEQ_RECV_USER:
  263. return recvUser();
  264. case SEQ_SEND_PASS:
  265. return sendPass();
  266. case SEQ_RECV_PASS:
  267. return recvPass();
  268. case SEQ_SEND_TYPE:
  269. return sendType();
  270. case SEQ_RECV_TYPE:
  271. return recvType();
  272. case SEQ_SEND_CWD:
  273. return sendCwd();
  274. case SEQ_RECV_CWD:
  275. return recvCwd();
  276. case SEQ_SEND_SIZE:
  277. return sendSize();
  278. case SEQ_RECV_SIZE:
  279. return recvSize();
  280. case SEQ_SEND_PORT:
  281. return sendPort();
  282. case SEQ_RECV_PORT:
  283. return recvPort();
  284. case SEQ_SEND_PASV:
  285. return sendPasv();
  286. case SEQ_RECV_PASV:
  287. return recvPasv();
  288. case SEQ_SEND_REST_PASV:
  289. return sendRestPasv(segment);
  290. case SEQ_SEND_REST:
  291. return sendRest(segment);
  292. case SEQ_RECV_REST:
  293. return recvRest();
  294. case SEQ_SEND_RETR:
  295. return sendRetr();
  296. case SEQ_RECV_RETR:
  297. return recvRetr();
  298. default:
  299. abort();
  300. }
  301. return doNextSequence;
  302. }