Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

ftp.c 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. #include <stddef.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <vsprintf.h>
  5. #include <assert.h>
  6. #include <errno.h>
  7. #include <gpxe/async.h>
  8. #include <gpxe/ftp.h>
  9. /** @file
  10. *
  11. * File transfer protocol
  12. *
  13. */
  14. /*****************************************************************************
  15. *
  16. * FTP control channel
  17. *
  18. */
  19. /** An FTP control channel string */
  20. struct ftp_string {
  21. /** String format */
  22. const char *format;
  23. /** Offset to string data
  24. *
  25. * This is the offset within the struct ftp_request to the
  26. * pointer to the string data. Use ftp_string_data() to get a
  27. * pointer to the actual data.
  28. */
  29. off_t data_offset;
  30. };
  31. /** FTP control channel strings */
  32. static const struct ftp_string ftp_strings[] = {
  33. [FTP_CONNECT] = { "", 0 },
  34. [FTP_USER] = { "USER anonymous\r\n", 0 },
  35. [FTP_PASS] = { "PASS etherboot@etherboot.org\r\n", 0 },
  36. [FTP_TYPE] = { "TYPE I\r\n", 0 },
  37. [FTP_PASV] = { "PASV\r\n", 0 },
  38. [FTP_RETR] = { "RETR %s\r\n",
  39. offsetof ( struct ftp_request, filename ) },
  40. [FTP_QUIT] = { "QUIT\r\n", 0 },
  41. [FTP_DONE] = { "", 0 },
  42. };
  43. /**
  44. * Get data associated with an FTP control channel string
  45. *
  46. * @v ftp FTP request
  47. * @v data_offset Data offset field from ftp_string structure
  48. * @ret data Pointer to data
  49. */
  50. static inline const void * ftp_string_data ( struct ftp_request *ftp,
  51. off_t data_offset ) {
  52. return * ( ( void ** ) ( ( ( void * ) ftp ) + data_offset ) );
  53. }
  54. /**
  55. * Get FTP request from control TCP application
  56. *
  57. * @v app TCP application
  58. * @ret ftp FTP request
  59. */
  60. static inline struct ftp_request * tcp_to_ftp ( struct tcp_application *app ) {
  61. return container_of ( app, struct ftp_request, tcp );
  62. }
  63. /**
  64. * Mark FTP operation as complete
  65. *
  66. * @v ftp FTP request
  67. * @v rc Return status code
  68. */
  69. static void ftp_done ( struct ftp_request *ftp, int rc ) {
  70. DBG ( "FTP %p completed with status %d\n", ftp, rc );
  71. /* Close both TCP connections */
  72. tcp_close ( &ftp->tcp );
  73. tcp_close ( &ftp->tcp_data );
  74. /* Mark asynchronous operation as complete */
  75. async_done ( &ftp->aop, rc );
  76. }
  77. /**
  78. * Parse FTP byte sequence value
  79. *
  80. * @v text Text string
  81. * @v value Value buffer
  82. * @v len Length of value buffer
  83. *
  84. * This parses an FTP byte sequence value (e.g. the "aaa,bbb,ccc,ddd"
  85. * form for IP addresses in PORT commands) into a byte sequence. @c
  86. * *text will be updated to point beyond the end of the parsed byte
  87. * sequence.
  88. *
  89. * This function is safe in the presence of malformed data, though the
  90. * output is undefined.
  91. */
  92. static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
  93. do {
  94. *(value++) = strtoul ( *text, text, 10 );
  95. if ( **text )
  96. (*text)++;
  97. } while ( --len );
  98. }
  99. /**
  100. * Handle an FTP control channel response
  101. *
  102. * @v ftp FTP request
  103. *
  104. * This is called once we have received a complete response line.
  105. */
  106. static void ftp_reply ( struct ftp_request *ftp ) {
  107. char status_major = ftp->status_text[0];
  108. DBG ( "FTP %p received status %s\n", ftp, ftp->status_text );
  109. /* Ignore "intermediate" responses (1xx codes) */
  110. if ( status_major == '1' )
  111. return;
  112. /* Anything other than success (2xx) or, in the case of a
  113. * repsonse to a "USER" command, a password prompt (3xx), is a
  114. * fatal error.
  115. */
  116. if ( ! ( ( status_major == '2' ) ||
  117. ( ( status_major == '3' ) && ( ftp->state == FTP_USER ) ) ) ){
  118. /* Flag protocol error and close connections */
  119. ftp_done ( ftp, -EPROTO );
  120. }
  121. /* Open passive connection when we get "PASV" response */
  122. if ( ftp->state == FTP_PASV ) {
  123. char *ptr = ftp->passive_text;
  124. union {
  125. struct sockaddr_in sin;
  126. struct sockaddr_tcpip st;
  127. } sa;
  128. int rc;
  129. sa.sin.sin_family = AF_INET;
  130. ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_addr,
  131. sizeof ( sa.sin.sin_addr ) );
  132. ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port,
  133. sizeof ( sa.sin.sin_port ) );
  134. if ( ( rc = tcp_connect ( &ftp->tcp_data, &sa.st, 0 ) ) != 0 ){
  135. DBG ( "FTP %p could not create data connection\n",
  136. ftp );
  137. ftp_done ( ftp, rc );
  138. return;
  139. }
  140. }
  141. /* Move to next state */
  142. if ( ftp->state < FTP_DONE )
  143. ftp->state++;
  144. ftp->already_sent = 0;
  145. if ( ftp->state < FTP_DONE ) {
  146. DBG ( "FTP %p sending ", ftp );
  147. DBG ( ftp_strings[ftp->state].format, ftp_string_data ( ftp,
  148. ftp_strings[ftp->state].data_offset ) );
  149. }
  150. return;
  151. }
  152. /**
  153. * Handle new data arriving on FTP control channel
  154. *
  155. * @v app TCP application
  156. * @v data New data
  157. * @v len Length of new data
  158. *
  159. * Data is collected until a complete line is received, at which point
  160. * its information is passed to ftp_reply().
  161. */
  162. static void ftp_newdata ( struct tcp_application *app,
  163. void *data, size_t len ) {
  164. struct ftp_request *ftp = tcp_to_ftp ( app );
  165. char *recvbuf = ftp->recvbuf;
  166. size_t recvsize = ftp->recvsize;
  167. char c;
  168. while ( len-- ) {
  169. c = * ( ( char * ) data++ );
  170. switch ( c ) {
  171. case '\r' :
  172. case '\n' :
  173. /* End of line: call ftp_reply() to handle
  174. * completed reply. Avoid calling ftp_reply()
  175. * twice if we receive both \r and \n.
  176. */
  177. if ( recvsize == 0 )
  178. ftp_reply ( ftp );
  179. /* Start filling up the status code buffer */
  180. recvbuf = ftp->status_text;
  181. recvsize = sizeof ( ftp->status_text ) - 1;
  182. break;
  183. case '(' :
  184. /* Start filling up the passive parameter buffer */
  185. recvbuf = ftp->passive_text;
  186. recvsize = sizeof ( ftp->passive_text ) - 1;
  187. break;
  188. case ')' :
  189. /* Stop filling the passive parameter buffer */
  190. recvsize = 0;
  191. break;
  192. default :
  193. /* Fill up buffer if applicable */
  194. if ( recvsize > 0 ) {
  195. *(recvbuf++) = c;
  196. recvsize--;
  197. }
  198. break;
  199. }
  200. }
  201. /* Store for next invocation */
  202. ftp->recvbuf = recvbuf;
  203. ftp->recvsize = recvsize;
  204. }
  205. /**
  206. * Handle acknowledgement of data sent on FTP control channel
  207. *
  208. * @v app TCP application
  209. */
  210. static void ftp_acked ( struct tcp_application *app, size_t len ) {
  211. struct ftp_request *ftp = tcp_to_ftp ( app );
  212. /* Mark off ACKed portion of the currently-transmitted data */
  213. ftp->already_sent += len;
  214. }
  215. /**
  216. * Construct data to send on FTP control channel
  217. *
  218. * @v app TCP application
  219. * @v buf Temporary data buffer
  220. * @v len Length of temporary data buffer
  221. */
  222. static void ftp_senddata ( struct tcp_application *app,
  223. void *buf, size_t len ) {
  224. struct ftp_request *ftp = tcp_to_ftp ( app );
  225. const struct ftp_string *string;
  226. /* Send the as-yet-unACKed portion of the string for the
  227. * current state.
  228. */
  229. string = &ftp_strings[ftp->state];
  230. len = snprintf ( buf, len, string->format,
  231. ftp_string_data ( ftp, string->data_offset ) );
  232. tcp_send ( app, buf + ftp->already_sent, len - ftp->already_sent );
  233. }
  234. /**
  235. * Handle control channel being closed
  236. *
  237. * @v app TCP application
  238. *
  239. * When the control channel is closed, the data channel must also be
  240. * closed, if it is currently open.
  241. */
  242. static void ftp_closed ( struct tcp_application *app, int status ) {
  243. struct ftp_request *ftp = tcp_to_ftp ( app );
  244. DBG ( "FTP %p control connection closed (status %d)\n", ftp, status );
  245. /* Complete FTP operation */
  246. ftp_done ( ftp, status );
  247. }
  248. /** FTP control channel operations */
  249. static struct tcp_operations ftp_tcp_operations = {
  250. .closed = ftp_closed,
  251. .acked = ftp_acked,
  252. .newdata = ftp_newdata,
  253. .senddata = ftp_senddata,
  254. };
  255. /*****************************************************************************
  256. *
  257. * FTP data channel
  258. *
  259. */
  260. /**
  261. * Get FTP request from data TCP application
  262. *
  263. * @v app TCP application
  264. * @ret ftp FTP request
  265. */
  266. static inline struct ftp_request *
  267. tcp_to_ftp_data ( struct tcp_application *app ) {
  268. return container_of ( app, struct ftp_request, tcp_data );
  269. }
  270. /**
  271. * Handle data channel being closed
  272. *
  273. * @v app TCP application
  274. *
  275. * When the data channel is closed, the control channel should be left
  276. * alone; the server will send a completion message via the control
  277. * channel which we'll pick up.
  278. *
  279. * If the data channel is closed due to an error, we abort the request.
  280. */
  281. static void ftp_data_closed ( struct tcp_application *app, int status ) {
  282. struct ftp_request *ftp = tcp_to_ftp_data ( app );
  283. DBG ( "FTP %p data connection closed (status %d)\n", ftp, status );
  284. /* If there was an error, close control channel and record status */
  285. if ( status )
  286. ftp_done ( ftp, status );
  287. }
  288. /**
  289. * Handle new data arriving on the FTP data channel
  290. *
  291. * @v app TCP application
  292. * @v data New data
  293. * @v len Length of new data
  294. *
  295. * Data is handed off to the callback registered in the FTP request.
  296. */
  297. static void ftp_data_newdata ( struct tcp_application *app,
  298. void *data, size_t len ) {
  299. struct ftp_request *ftp = tcp_to_ftp_data ( app );
  300. ftp->callback ( data, len );
  301. }
  302. /** FTP data channel operations */
  303. static struct tcp_operations ftp_data_tcp_operations = {
  304. .closed = ftp_data_closed,
  305. .newdata = ftp_data_newdata,
  306. };
  307. /*****************************************************************************
  308. *
  309. * API
  310. *
  311. */
  312. /**
  313. * Initiate an FTP connection
  314. *
  315. * @v ftp FTP request
  316. */
  317. struct async_operation * ftp_get ( struct ftp_request *ftp ) {
  318. int rc;
  319. DBG ( "FTP %p fetching %s\n", ftp, ftp->filename );
  320. ftp->tcp.tcp_op = &ftp_tcp_operations;
  321. ftp->tcp_data.tcp_op = &ftp_data_tcp_operations;
  322. ftp->recvbuf = ftp->status_text;
  323. ftp->recvsize = sizeof ( ftp->status_text ) - 1;
  324. if ( ( rc = tcp_connect ( &ftp->tcp, &ftp->server, 0 ) ) != 0 )
  325. ftp_done ( ftp, rc );
  326. return &ftp->aop;
  327. }