#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/socket.h>
#include <gpxe/tcpip.h>
#include <gpxe/in.h>
#include <gpxe/xfer.h>
#include <gpxe/open.h>
#include <gpxe/uri.h>
#include <gpxe/features.h>
#include <gpxe/ftp.h>
Go to the source code of this file.
Data Structures | |
| struct | ftp_request |
| An FTP request. More... | |
| struct | ftp_control_string |
| An FTP control channel string. More... | |
Enumerations | |
| enum | ftp_state { FTP_CONNECT = 0, FTP_USER, FTP_PASS, FTP_TYPE, FTP_PASV, FTP_RETR, FTP_WAIT, FTP_QUIT, FTP_DONE } |
| FTP states. More... | |
Functions | |
| FEATURE (FEATURE_PROTOCOL,"FTP", DHCP_EB_FEATURE_FTP, 1) | |
| static void | ftp_free (struct refcnt *refcnt) |
| Free FTP request. | |
| static void | ftp_done (struct ftp_request *ftp, int rc) |
| Mark FTP operation as complete. | |
| static const char * | ftp_uri_path (struct ftp_request *ftp) |
| Retrieve FTP pathname. | |
| static const char * | ftp_user (struct ftp_request *ftp) |
| Retrieve FTP user. | |
| static const char * | ftp_password (struct ftp_request *ftp) |
| Retrieve FTP password. | |
| static void | ftp_control_close (struct xfer_interface *control, int rc) |
| Handle control channel being closed. | |
| static void | ftp_parse_value (char **text, uint8_t *value, size_t len) |
| Parse FTP byte sequence value. | |
| static void | ftp_next_state (struct ftp_request *ftp) |
| Move to next state and send the appropriate FTP control string. | |
| static void | ftp_reply (struct ftp_request *ftp) |
| Handle an FTP control channel response. | |
| static int | ftp_control_deliver_raw (struct xfer_interface *control, const void *data, size_t len) |
| Handle new data arriving on FTP control channel. | |
| static void | ftp_data_closed (struct xfer_interface *data, int rc) |
| Handle FTP data channel being closed. | |
| static int | ftp_data_deliver_iob (struct xfer_interface *data, struct io_buffer *iobuf, struct xfer_metadata *meta __unused) |
| Handle data delivery via FTP data channel. | |
| static void | ftp_xfer_closed (struct xfer_interface *xfer, int rc) |
| Close FTP data transfer interface. | |
| static int | ftp_open (struct xfer_interface *xfer, struct uri *uri) |
| Initiate an FTP connection. | |
Variables | |
| static struct ftp_control_string | ftp_strings [] |
| FTP control channel strings. | |
| static struct xfer_interface_operations | ftp_control_operations |
| FTP control channel operations. | |
| static struct xfer_interface_operations | ftp_data_operations |
| FTP data channel operations. | |
| static struct xfer_interface_operations | ftp_xfer_operations |
| FTP data transfer interface operations. | |
| struct uri_opener ftp_uri_opener | __uri_opener |
| FTP URI opener. | |
Definition in file ftp.c.
| enum ftp_state |
FTP states.
These must be sequential, i.e. a successful FTP session must pass through each of these states in order.
Definition at line 31 of file ftp.c.
00031 { 00032 FTP_CONNECT = 0, 00033 FTP_USER, 00034 FTP_PASS, 00035 FTP_TYPE, 00036 FTP_PASV, 00037 FTP_RETR, 00038 FTP_WAIT, 00039 FTP_QUIT, 00040 FTP_DONE, 00041 };
| FEATURE | ( | FEATURE_PROTOCOL | , | |
| "FTP" | , | |||
| DHCP_EB_FEATURE_FTP | , | |||
| 1 | ||||
| ) |
| static void ftp_free | ( | struct refcnt * | refcnt | ) | [static] |
Free FTP request.
| refcnt | Reference counter |
Definition at line 77 of file ftp.c.
References container_of, DBGC, free(), and ftp_request::uri.
Referenced by ftp_open().
00077 { 00078 struct ftp_request *ftp = 00079 container_of ( refcnt, struct ftp_request, refcnt ); 00080 00081 DBGC ( ftp, "FTP %p freed\n", ftp ); 00082 00083 uri_put ( ftp->uri ); 00084 free ( ftp ); 00085 }
| static void ftp_done | ( | struct ftp_request * | ftp, | |
| int | rc | |||
| ) | [static] |
Mark FTP operation as complete.
| ftp | FTP request | |
| rc | Return status code |
Definition at line 93 of file ftp.c.
References ftp_request::control, ftp_request::data, DBGC, strerror(), ftp_request::xfer, and xfer_close().
Referenced by ftp_control_close(), ftp_data_closed(), ftp_open(), ftp_reply(), and ftp_xfer_closed().
00093 { 00094 00095 DBGC ( ftp, "FTP %p completed (%s)\n", ftp, strerror ( rc ) ); 00096 00097 /* Close all data transfer interfaces */ 00098 xfer_nullify ( &ftp->xfer ); 00099 xfer_close ( &ftp->xfer, rc ); 00100 xfer_nullify ( &ftp->control ); 00101 xfer_close ( &ftp->control, rc ); 00102 xfer_nullify ( &ftp->data ); 00103 xfer_close ( &ftp->data, rc ); 00104 }
| static const char* ftp_uri_path | ( | struct ftp_request * | ftp | ) | [static] |
| static const char* ftp_user | ( | struct ftp_request * | ftp | ) | [static] |
| static const char* ftp_password | ( | struct ftp_request * | ftp | ) | [static] |
Retrieve FTP password.
| ftp | FTP request |
| password | FTP password |
Definition at line 151 of file ftp.c.
References uri::password, and ftp_request::uri.
00151 { 00152 static char *ftp_default_password = "etherboot@etherboot.org"; 00153 return ftp->uri->password ? ftp->uri->password : ftp_default_password; 00154 }
| static void ftp_control_close | ( | struct xfer_interface * | control, | |
| int | rc | |||
| ) | [static] |
Handle control channel being closed.
| control | FTP control channel interface | |
| rc | Reason for close |
Definition at line 178 of file ftp.c.
References container_of, DBGC, ftp_done(), and strerror().
00178 { 00179 struct ftp_request *ftp = 00180 container_of ( control, struct ftp_request, control ); 00181 00182 DBGC ( ftp, "FTP %p control connection closed: %s\n", 00183 ftp, strerror ( rc ) ); 00184 00185 /* Complete FTP operation */ 00186 ftp_done ( ftp, rc ); 00187 }
Parse FTP byte sequence value.
| text | Text string | |
| value | Value buffer | |
| len | Length of value buffer |
*text will be updated to point beyond the end of the parsed byte sequence.This function is safe in the presence of malformed data, though the output is undefined.
Definition at line 204 of file ftp.c.
References strtoul().
Referenced by ftp_reply().
00204 { 00205 do { 00206 *(value++) = strtoul ( *text, text, 10 ); 00207 if ( **text ) 00208 (*text)++; 00209 } while ( --len ); 00210 }
| static void ftp_next_state | ( | struct ftp_request * | ftp | ) | [static] |
Move to next state and send the appropriate FTP control string.
| ftp | FTP request |
Definition at line 218 of file ftp.c.
References ftp_request::control, DBGC, FTP_DONE, ftp_control_string::literal, ftp_request::state, ftp_control_string::variable, and xfer_printf().
Referenced by ftp_data_closed(), and ftp_reply().
00218 { 00219 struct ftp_control_string *ftp_string; 00220 const char *literal; 00221 const char *variable; 00222 00223 /* Move to next state */ 00224 if ( ftp->state < FTP_DONE ) 00225 ftp->state++; 00226 00227 /* Send control string if needed */ 00228 ftp_string = &ftp_strings[ftp->state]; 00229 literal = ftp_string->literal; 00230 variable = ( ftp_string->variable ? 00231 ftp_string->variable ( ftp ) : "" ); 00232 if ( literal ) { 00233 DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable ); 00234 xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable ); 00235 } 00236 }
| static void ftp_reply | ( | struct ftp_request * | ftp | ) | [static] |
Handle an FTP control channel response.
| ftp | FTP request |
Definition at line 245 of file ftp.c.
References AF_INET, ftp_request::data, DBGC, EPROTO, ftp_done(), ftp_next_state(), ftp_parse_value(), FTP_PASV, FTP_USER, NULL, ftp_request::passive_text, SOCK_STREAM, ftp_request::state, ftp_request::status_text, and xfer_open_socket().
Referenced by ftp_control_deliver_raw().
00245 { 00246 char status_major = ftp->status_text[0]; 00247 char separator = ftp->status_text[3]; 00248 00249 DBGC ( ftp, "FTP %p received status %s\n", ftp, ftp->status_text ); 00250 00251 /* Ignore malformed lines */ 00252 if ( separator != ' ' ) 00253 return; 00254 00255 /* Ignore "intermediate" responses (1xx codes) */ 00256 if ( status_major == '1' ) 00257 return; 00258 00259 /* Anything other than success (2xx) or, in the case of a 00260 * repsonse to a "USER" command, a password prompt (3xx), is a 00261 * fatal error. 00262 */ 00263 if ( ! ( ( status_major == '2' ) || 00264 ( ( status_major == '3' ) && ( ftp->state == FTP_USER ) ) ) ){ 00265 /* Flag protocol error and close connections */ 00266 ftp_done ( ftp, -EPROTO ); 00267 return; 00268 } 00269 00270 /* Open passive connection when we get "PASV" response */ 00271 if ( ftp->state == FTP_PASV ) { 00272 char *ptr = ftp->passive_text; 00273 union { 00274 struct sockaddr_in sin; 00275 struct sockaddr sa; 00276 } sa; 00277 int rc; 00278 00279 sa.sin.sin_family = AF_INET; 00280 ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_addr, 00281 sizeof ( sa.sin.sin_addr ) ); 00282 ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port, 00283 sizeof ( sa.sin.sin_port ) ); 00284 if ( ( rc = xfer_open_socket ( &ftp->data, SOCK_STREAM, 00285 &sa.sa, NULL ) ) != 0 ) { 00286 DBGC ( ftp, "FTP %p could not open data connection\n", 00287 ftp ); 00288 ftp_done ( ftp, rc ); 00289 return; 00290 } 00291 } 00292 00293 /* Move to next state and send control string */ 00294 ftp_next_state ( ftp ); 00295 00296 }
| static int ftp_control_deliver_raw | ( | struct xfer_interface * | control, | |
| const void * | data, | |||
| size_t | len | |||
| ) | [static] |
Handle new data arriving on FTP control channel.
| control | FTP control channel interface | |
| data | New data | |
| len | Length of new data |
Definition at line 308 of file ftp.c.
References container_of, ftp_reply(), ftp_request::passive_text, ftp_request::recvbuf, ftp_request::recvsize, and ftp_request::status_text.
00309 { 00310 struct ftp_request *ftp = 00311 container_of ( control, struct ftp_request, control ); 00312 char *recvbuf = ftp->recvbuf; 00313 size_t recvsize = ftp->recvsize; 00314 char c; 00315 00316 while ( len-- ) { 00317 c = * ( ( char * ) data++ ); 00318 switch ( c ) { 00319 case '\r' : 00320 case '\n' : 00321 /* End of line: call ftp_reply() to handle 00322 * completed reply. Avoid calling ftp_reply() 00323 * twice if we receive both \r and \n. 00324 */ 00325 if ( recvsize == 0 ) 00326 ftp_reply ( ftp ); 00327 /* Start filling up the status code buffer */ 00328 recvbuf = ftp->status_text; 00329 recvsize = sizeof ( ftp->status_text ) - 1; 00330 break; 00331 case '(' : 00332 /* Start filling up the passive parameter buffer */ 00333 recvbuf = ftp->passive_text; 00334 recvsize = sizeof ( ftp->passive_text ) - 1; 00335 break; 00336 case ')' : 00337 /* Stop filling the passive parameter buffer */ 00338 recvsize = 0; 00339 break; 00340 default : 00341 /* Fill up buffer if applicable */ 00342 if ( recvsize > 0 ) { 00343 *(recvbuf++) = c; 00344 recvsize--; 00345 } 00346 break; 00347 } 00348 } 00349 00350 /* Store for next invocation */ 00351 ftp->recvbuf = recvbuf; 00352 ftp->recvsize = recvsize; 00353 00354 return 0; 00355 }
| static void ftp_data_closed | ( | struct xfer_interface * | data, | |
| int | rc | |||
| ) | [static] |
Handle FTP data channel being closed.
| data | FTP data channel interface | |
| rc | Reason for closure |
If the data channel is closed due to an error, we abort the request.
Definition at line 385 of file ftp.c.
References container_of, DBGC, ftp_done(), ftp_next_state(), and strerror().
00385 { 00386 struct ftp_request *ftp = 00387 container_of ( data, struct ftp_request, data ); 00388 00389 DBGC ( ftp, "FTP %p data connection closed: %s\n", 00390 ftp, strerror ( rc ) ); 00391 00392 /* If there was an error, close control channel and record status */ 00393 if ( rc ) { 00394 ftp_done ( ftp, rc ); 00395 } else { 00396 ftp_next_state ( ftp ); 00397 } 00398 }
| static int ftp_data_deliver_iob | ( | struct xfer_interface * | data, | |
| struct io_buffer * | iobuf, | |||
| struct xfer_metadata *meta | __unused | |||
| ) | [static] |
Handle data delivery via FTP data channel.
| xfer | FTP data channel interface | |
| iobuf | I/O buffer | |
| meta | Data transfer metadata |
| rc | Return status code |
Definition at line 408 of file ftp.c.
References container_of, DBGC, strerror(), ftp_request::xfer, and xfer_deliver_iob().
00410 { 00411 struct ftp_request *ftp = 00412 container_of ( data, struct ftp_request, data ); 00413 int rc; 00414 00415 if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) { 00416 DBGC ( ftp, "FTP %p failed to deliver data: %s\n", 00417 ftp, strerror ( rc ) ); 00418 return rc; 00419 } 00420 00421 return 0; 00422 }
| static void ftp_xfer_closed | ( | struct xfer_interface * | xfer, | |
| int | rc | |||
| ) | [static] |
Close FTP data transfer interface.
| xfer | FTP data transfer interface | |
| rc | Reason for close |
Definition at line 446 of file ftp.c.
References container_of, DBGC, ftp_done(), and strerror().
00446 { 00447 struct ftp_request *ftp = 00448 container_of ( xfer, struct ftp_request, xfer ); 00449 00450 DBGC ( ftp, "FTP %p data transfer interface closed: %s\n", 00451 ftp, strerror ( rc ) ); 00452 00453 ftp_done ( ftp, rc ); 00454 }
| static int ftp_open | ( | struct xfer_interface * | xfer, | |
| struct uri * | uri | |||
| ) | [static] |
Initiate an FTP connection.
| rc | Return status code |
Definition at line 479 of file ftp.c.
References ftp_request::control, ftp_request::data, DBGC, EINVAL, ENOMEM, refcnt::free, ftp_done(), ftp_free(), FTP_PORT, uri::host, htons, memset(), NULL, uri::path, ftp_request::recvbuf, ftp_request::recvsize, ref_put(), ftp_request::refcnt, SOCK_STREAM, sockaddr_tcpip::st_port, ftp_request::status_text, strerror(), ftp_request::uri, uri_port(), ftp_request::xfer, xfer_init(), xfer_open_named_socket(), and zalloc().
00479 { 00480 struct ftp_request *ftp; 00481 struct sockaddr_tcpip server; 00482 int rc; 00483 00484 /* Sanity checks */ 00485 if ( ! uri->path ) 00486 return -EINVAL; 00487 if ( ! uri->host ) 00488 return -EINVAL; 00489 00490 /* Allocate and populate structure */ 00491 ftp = zalloc ( sizeof ( *ftp ) ); 00492 if ( ! ftp ) 00493 return -ENOMEM; 00494 ftp->refcnt.free = ftp_free; 00495 xfer_init ( &ftp->xfer, &ftp_xfer_operations, &ftp->refcnt ); 00496 ftp->uri = uri_get ( uri ); 00497 xfer_init ( &ftp->control, &ftp_control_operations, &ftp->refcnt ); 00498 xfer_init ( &ftp->data, &ftp_data_operations, &ftp->refcnt ); 00499 ftp->recvbuf = ftp->status_text; 00500 ftp->recvsize = sizeof ( ftp->status_text ) - 1; 00501 00502 DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path ); 00503 00504 /* Open control connection */ 00505 memset ( &server, 0, sizeof ( server ) ); 00506 server.st_port = htons ( uri_port ( uri, FTP_PORT ) ); 00507 if ( ( rc = xfer_open_named_socket ( &ftp->control, SOCK_STREAM, 00508 ( struct sockaddr * ) &server, 00509 uri->host, NULL ) ) != 0 ) 00510 goto err; 00511 00512 /* Attach to parent interface, mortalise self, and return */ 00513 xfer_plug_plug ( &ftp->xfer, xfer ); 00514 ref_put ( &ftp->refcnt ); 00515 return 0; 00516 00517 err: 00518 DBGC ( ftp, "FTP %p could not create request: %s\n", 00519 ftp, strerror ( rc ) ); 00520 ftp_done ( ftp, rc ); 00521 ref_put ( &ftp->refcnt ); 00522 return rc; 00523 }
struct ftp_control_string ftp_strings[] [static] |
Initial value:
{
[FTP_CONNECT] = { NULL, NULL },
[FTP_USER] = { "USER ", ftp_user },
[FTP_PASS] = { "PASS ", ftp_password },
[FTP_TYPE] = { "TYPE I", NULL },
[FTP_PASV] = { "PASV", NULL },
[FTP_RETR] = { "RETR ", ftp_uri_path },
[FTP_WAIT] = { NULL, NULL },
[FTP_QUIT] = { "QUIT", NULL },
[FTP_DONE] = { NULL, NULL },
}
struct xfer_interface_operations ftp_control_operations [static] |
Initial value:
{
.close = ftp_control_close,
.vredirect = xfer_vreopen,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = ftp_control_deliver_raw,
}
struct xfer_interface_operations ftp_data_operations [static] |
Initial value:
{
.close = ftp_data_closed,
.vredirect = xfer_vreopen,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = ftp_data_deliver_iob,
.deliver_raw = xfer_deliver_as_iob,
}
struct xfer_interface_operations ftp_xfer_operations [static] |
Initial value:
{
.close = ftp_xfer_closed,
.vredirect = ignore_xfer_vredirect,
.window = unlimited_xfer_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = ignore_xfer_deliver_raw,
}
| struct uri_opener ftp_uri_opener __uri_opener |
1.5.7.1