ftp.c File Reference

File transfer protocol. More...

#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.


Detailed Description

File transfer protocol.

Definition in file ftp.c.


Enumeration Type Documentation

enum ftp_state

FTP states.

These must be sequential, i.e. a successful FTP session must pass through each of these states in order.

Enumerator:
FTP_CONNECT 
FTP_USER 
FTP_PASS 
FTP_TYPE 
FTP_PASV 
FTP_RETR 
FTP_WAIT 
FTP_QUIT 
FTP_DONE 

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 };


Function Documentation

FEATURE ( FEATURE_PROTOCOL  ,
"FTP"  ,
DHCP_EB_FEATURE_FTP  ,
 
)

static void ftp_free ( struct refcnt refcnt  )  [static]

Free FTP request.

Parameters:
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.

Parameters:
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]

Retrieve FTP pathname.

Parameters:
ftp FTP request
Return values:
path FTP pathname

Definition at line 130 of file ftp.c.

References uri::path, and ftp_request::uri.

00130                                                              {
00131         return ftp->uri->path;
00132 }

static const char* ftp_user ( struct ftp_request ftp  )  [static]

Retrieve FTP user.

Parameters:
ftp FTP request
Return values:
user FTP user

Definition at line 140 of file ftp.c.

References ftp_request::uri, and uri::user.

00140                                                          {
00141         static char *ftp_default_user = "anonymous";
00142         return ftp->uri->user ? ftp->uri->user : ftp_default_user;
00143 }

static const char* ftp_password ( struct ftp_request ftp  )  [static]

Retrieve FTP password.

Parameters:
ftp FTP request
Return values:
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.

Parameters:
control FTP control channel interface
rc Reason for close
When the control channel is closed, the data channel must also be closed, if it is currently open.

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 }

static void ftp_parse_value ( char **  text,
uint8_t value,
size_t  len 
) [static]

Parse FTP byte sequence value.

Parameters:
text Text string
value Value buffer
len Length of value buffer
This parses an FTP byte sequence value (e.g. the "aaa,bbb,ccc,ddd" form for IP addresses in PORT commands) into a byte sequence. *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.

Parameters:
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.

Parameters:
ftp FTP request
This is called once we have received a complete response line.

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.

Parameters:
control FTP control channel interface
data New data
len Length of new data
Data is collected until a complete line is received, at which point its information is passed to ftp_reply().

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.

Parameters:
data FTP data channel interface
rc Reason for closure
When the data channel is closed, the control channel should be left alone; the server will send a completion message via the control channel which we'll pick up.

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.

Parameters:
xfer FTP data channel interface
iobuf I/O buffer
meta Data transfer metadata
Return values:
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.

Parameters:
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.

Parameters:
xfer Data transfer interface
uri Uniform Resource Identifier
Return values:
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 }


Variable Documentation

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 },
}
FTP control channel strings.

Definition at line 157 of file ftp.c.

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,
}
FTP control channel operations.

Definition at line 358 of file ftp.c.

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,
}
FTP data channel operations.

Definition at line 425 of file ftp.c.

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,
}
FTP data transfer interface operations.

Definition at line 457 of file ftp.c.

struct uri_opener ftp_uri_opener __uri_opener

Initial value:

 {
        .scheme = "ftp",
        .open   = ftp_open,
}
FTP URI opener.

Definition at line 526 of file ftp.c.


Generated on Tue Apr 6 20:01:56 2010 for gPXE by  doxygen 1.5.7.1