Name

FTP Server API — describe FTP server API, callback and configuration

FTP Server API

The FTP server provides a single entry point:

    #include <ftpserver.h>

     __externC int cyg_ftpserver_start( cyg_ftpserver *server );

This function starts an FTP server running using parameters defined in the server argument. It should be called from a thread with a stack with at least CYGNUM_NET_FTPSERVER_STACK_SIZE bytes available. Under normal circumstances this function will not return, so the application should create a thread dedicated to the server. There are examples of this in the test programs.

The server argument contains a number of fields that the user may set to control the behaviour of the FTP server.

const char *address
This is a string giving the IP address on which the server will listen. If not set this will default to listening on all network interface, which is usually what is wanted. This option is only useful if a target has more than one network interface and the FTP server should only listen on one of them.
int port
This defines the port number on which the server will listen. Leaving this value unset, zero, will cause the server to choose the default FTP port of 21.
const char *greeting
This is the string that the server will use in its initial response to a client connection. Leaving this NULL will cause the server to use a default message: "Welcome to eCosPro FTP service.".
const char *root
This string defines a filesystem pathname to the root directory of the FTP server. Files will only be transferred to and from this directory or any subdirectories. A NULL pointer here will cause the server to use "/" as the root.
int data_port
This defines the first port at which the server will create passive data connections. It will try successive ports from this value until a free port is found, limited to the following 20 ports. Leaving this value NULL will cause the server to start from port 5000.

The normal idiom for use of the FTP server is to define the cyg_ftpserver structure statically and to then call cyg_ftpserver_start() with a pointer to that. The following is a somewhat contrived example:

#include <ftpserver.h>

//==========================================================================

static cyg_ftpserver ftp_server =
{
    .port       = 2121,                            // Listen on port 2121
    .root       = "/fatfs/ftp",                    // FTP to/from here
    .greeting   = "Welcome to Fubar FTP service.", // Welcome string
    .data_port  = 40000                            // Move data ports to 40000+
};

//==========================================================================

static void ftpd(CYG_ADDRWORD p)
{
    init_all_network_interfaces();

    cyg_ftpserver_start( &ftp_server );
}

//==========================================================================

#define STACK_SIZE CYGNUM_NET_FTPSERVER_STACK_SIZE
static char stack[STACK_SIZE] CYGBLD_ATTRIB_ALIGN_MAX;
static cyg_thread thread_data;
static cyg_handle_t thread_handle;

void start_ftpd_thread(void)
{
    cyg_thread_create(10,              // Priority
                    ftpd,              // entry
                    0,                 // entry parameter
                    "FTP test",        // Name
                    &stack[0],         // Stack
                    STACK_SIZE,        // Size
                    &thread_handle,    // Handle
                    &thread_data       // Thread data structure
                    );
  cyg_thread_resume(thread_handle);  /* Start it */
}

The defaults for the configuration parameters are such that leaving them all zero or NULL will cause the server to configure itself on the standard port serving files to/from the root of the filesystem.

Callback Interface

The default server operates to and from a directory in a filesystem, in the same way that most FTP servers operate. However, not all embedded systems have filesystem support. To allow such systems to provide an FTP service, all file access operations go through a set of callback functions in the cyg_ftpserver structure. The user can define these to redirect file I/O operations to other devices such as memory buffers or flash memory regions.

The callback interface defines a type, ftpserver_cookie that is passed to the callback functions. It is a word or pointer sized value and is typically used by the callback functions to contain a data structure pointer, or an index into a table that uniquely identifies an open file.

The callbacks for a notional example interface are defined as follows:

int example_open( const char *path, cyg_bool write, ftpserver_cookie *cookie );

Called to open a file for data transfer. The path is a fully rooted path formed from the root field of the server configuration plus the client supplied path. The write argument is true if the file is to be opened for writing and false if for reading. If successful the function may store a private value to *cookie.

If the file is opened successfully this function should return FTPSERVER_OK. If the file cannot be opened for reading it should return FTPSERVER_NO_FILE. If the file cannot be written to or created it should return FTPSERVER_NOT_ALLOWED.

int example_write( ftpserver_cookie cookie, const cyg_uint8 *buf, cyg_uint32 size );

Called to write data to the file. The cookie argument is the value stored by the open callback. Arguments buf and size define the data to be written.

If the data is successfully written this function should return FTPSERVER_OK. If any error occurs it should return FTPSERVER_WRITE_FAIL.

int example_read( ftpserver_cookie cookie, cyg_uint8 *buf, cyg_uint32 *size );

Called to read data from the file. The cookie argument is the value stored by the open callback. Arguments buf and *size define a buffer into which the data should be stored, *size should be updated with the amount of data written to the buffer. If no more data is available, *size should be set to zero.

If the function is successful it should return FTPSERVER_OK. If any error occurs it should return FTPSERVER_READ_FAIL.

int example_close( ftpserver_cookie cookie );

Called to close the file for further data transfer. The cookie argument is the value stored by the open callback. After this call the cookie value will not be used in further calls.

This function should return FTPSERVER_OK under all circumstance, there are no error conditions of interest to the FTP server.

int example_auth( const char *user, const char *passwd );

This function is called to authenticate a user ID and password supplied by the client. The FTP server will only request a password, by returning a 331 response, if a user supplied authentication function is installed.

If the user and password are accepted, this function should return FTPSERVER_LOGIN_OK; it should return FTPSERVER_BADUSER if they do not.

int example_delete( const char *path );

Called to delete a file. The path is a fully rooted path formed from the root field of the server configuration plus the client supplied path.

If the file is deleted successfully this function should return FTPSERVER_OPDONE. If the file cannot be deleted or is not found, FTPSERVER_NO_FILE should be returned.

Extending the previous example, the cyg_ftpserver might look like this:

static cyg_ftpserver ftp_server =
{
    .port       = 2121,                            // Listen on port 2121
    .root       = "/fatfs/ftp",                    // FTP to/from here
    .greeting   = "Welcome to Fubar FTP service.", // Welcome string
    .data_port  = 40000,                           // Move data ports to 40000+

    .open       = example_open,
    .read       = example_read,
    .write      = example_write,
    .close      = example_close,
    .auth       = example_auth,
    .delete     = example_delete,

};

Configuration Options

The FTP server package contains a number of configuration options:

CYGNUM_NET_FTPSERVER_BUFFER_SIZE
This option defines the size of the buffer used for data transfers. Buffer size is a tradeoff between memory use and transfer speed. The default should be a reasonable compromise between these two.
CYGNUM_NET_FTPSERVER_USER_SIZE
This option defines the size of the buffer used for storing the user name supplied by the client.
CYGNUM_NET_FTPSERVER_PASSWD_SIZE
This option defines the size of the buffer used for storing the password supplied by the client. The default reflects the habit of using a user's email address as a password for anonymous FTP.
CYGNUM_NET_FTPSERVER_CONTROL_TIMEOUT
This option defines the timeout applied to control streams. If after this number of seconds the client has not interacted with the server, the connection is closed down. Since the server only allows a single client at a time, any client that fails to close a control stream down will block it for others.
CYGNUM_NET_FTPSERVER_DATA_TIMEOUT
This option defines the timeout applied to data streams. If after this number of seconds the client has not transferred data to or from the server, the connection is closed down. Clients are expected to use a data connection immediately after it is created so this timeout can be considerably smaller than the control timeout.