Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ftp_server.c Source File

ftp_server.c

Go to the documentation of this file.
00001 /**
00002  * @file ftp_server.c
00003  * @brief FTP server (File Transfer Protocol)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * File Transfer Protocol (FTP) is a standard network protocol used to
00028  * transfer files from one host to another host over a TCP-based network.
00029  * Refer to the following RFCs for complete details:
00030  * - RFC 959: File Transfer Protocol (FTP)
00031  * - RFC 3659: Extensions to FTP
00032  * - RFC 2428: FTP Extensions for IPv6 and NATs
00033  *
00034  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00035  * @version 1.7.6
00036  **/
00037 
00038 //Switch to the appropriate trace level
00039 #define TRACE_LEVEL FTP_TRACE_LEVEL
00040 
00041 //Dependencies
00042 #include "ftp/ftp_server.h"
00043 #include "ftp/ftp_server_events.h"
00044 #include "ftp/ftp_server_commands.h"
00045 #include "ftp/ftp_server_misc.h"
00046 #include "str.h"
00047 #include "path.h"
00048 #include "error.h"
00049 #include "debug.h"
00050 
00051 //Check TCP/IP stack configuration
00052 #if (FTP_SERVER_SUPPORT == ENABLED)
00053 
00054 
00055 /**
00056  * @brief Initialize settings with default values
00057  * @param[out] settings Structure that contains FTP server settings
00058  **/
00059 
00060 void ftpServerGetDefaultSettings(FtpServerSettings *settings)
00061 {
00062    //The FTP server is not bound to any interface
00063    settings->interface = NULL;
00064 
00065    //FTP command port number
00066    settings->port = FTP_PORT;
00067    //FTP data port number
00068    settings->dataPort = FTP_DATA_PORT;
00069    //Passive port range
00070    settings->passivePortMin = FTP_SERVER_PASSIVE_PORT_MIN;
00071    settings->passivePortMax = FTP_SERVER_PASSIVE_PORT_MAX;
00072    //Set root directory
00073    strcpy(settings->rootDir, "/");
00074    //User verification callback function
00075    settings->checkUserCallback = NULL;
00076    //Password verification callback function
00077    settings->checkPasswordCallback = NULL;
00078    //Callback used to retrieve file permissions
00079    settings->getFilePermCallback = NULL;
00080    //Unknown command callback function
00081    settings->unknownCommandCallback = NULL;
00082 }
00083 
00084 
00085 /**
00086  * @brief FTP server initialization
00087  * @param[in] context Pointer to the FTP server context
00088  * @param[in] settings FTP server specific settings
00089  * @return Error code
00090  **/
00091 
00092 error_t ftpServerInit(FtpServerContext *context, const FtpServerSettings *settings)
00093 {
00094    error_t error;
00095 
00096    //Debug message
00097    TRACE_INFO("Initializing FTP server...\r\n");
00098 
00099    //Ensure the parameters are valid
00100    if(context == NULL || settings == NULL)
00101       return ERROR_INVALID_PARAMETER;
00102 
00103    //Check passive port range
00104    if(settings->passivePortMax <= settings->passivePortMin)
00105       return ERROR_INVALID_PARAMETER;
00106 
00107    //Clear the FTP server context
00108    memset(context, 0, sizeof(FtpServerContext));
00109 
00110    //Save user settings
00111    context->settings = *settings;
00112 
00113    //Clean the root directory path
00114    pathCanonicalize(context->settings.rootDir);
00115    pathRemoveSlash(context->settings.rootDir);
00116 
00117    //Create an event object to poll the state of sockets
00118    if(!osCreateEvent(&context->event))
00119    {
00120       //Failed to create event
00121       return ERROR_OUT_OF_RESOURCES;
00122    }
00123 
00124    //Start of exception handling block
00125    do
00126    {
00127       //Open a TCP socket
00128       context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
00129       //Failed to open socket?
00130       if(!context->socket)
00131       {
00132          //Report an error
00133          error = ERROR_OPEN_FAILED;
00134          //Exit immediately
00135          break;
00136       }
00137 
00138       //Set timeout for blocking functions
00139       error = socketSetTimeout(context->socket, INFINITE_DELAY);
00140       //Any error to report?
00141       if(error)
00142          break;
00143 
00144       //Change the size of the TX buffer
00145       error = socketSetTxBufferSize(context->socket,
00146          FTP_SERVER_CTRL_SOCKET_BUFFER_SIZE);
00147       //Any error to report?
00148       if(error)
00149          break;
00150 
00151       //Change the size of the RX buffer
00152       error = socketSetRxBufferSize(context->socket,
00153          FTP_SERVER_CTRL_SOCKET_BUFFER_SIZE);
00154       //Any error to report?
00155       if(error)
00156          break;
00157 
00158       //Associate the socket with the relevant interface
00159       error = socketBindToInterface(context->socket, settings->interface);
00160       //Unable to bind the socket to the desired interface?
00161       if(error)
00162          break;
00163 
00164       //Bind newly created socket to port 21
00165       error = socketBind(context->socket, &IP_ADDR_ANY, settings->port);
00166       //Failed to bind socket to port 21?
00167       if(error)
00168          break;
00169 
00170       //Place socket in listening state
00171       error = socketListen(context->socket, FTP_SERVER_BACKLOG);
00172       //Any failure to report?
00173       if(error)
00174          break;
00175 
00176       //End of exception handling block
00177    } while(0);
00178 
00179    //Did we encounter an error?
00180    if(error)
00181    {
00182       //Free previously allocated resources
00183       osDeleteEvent(&context->event);
00184       //Close socket
00185       socketClose(context->socket);
00186    }
00187 
00188    //Return status code
00189    return error;
00190 }
00191 
00192 
00193 /**
00194  * @brief Start FTP server
00195  * @param[in] context Pointer to the FTP server context
00196  * @return Error code
00197  **/
00198 
00199 error_t ftpServerStart(FtpServerContext *context)
00200 {
00201    OsTask *task;
00202 
00203    //Debug message
00204    TRACE_INFO("Starting FTP server...\r\n");
00205 
00206    //Make sure the FTP server context is valid
00207    if(context == NULL)
00208       return ERROR_INVALID_PARAMETER;
00209 
00210    //Create the FTP server task
00211    task = osCreateTask("FTP Server", (OsTaskCode) ftpServerTask,
00212       context, FTP_SERVER_STACK_SIZE, FTP_SERVER_PRIORITY);
00213 
00214    //Unable to create the task?
00215    if(task == OS_INVALID_HANDLE)
00216       return ERROR_OUT_OF_RESOURCES;
00217 
00218    //Successful processing
00219    return NO_ERROR;
00220 }
00221 
00222 
00223 /**
00224  * @brief Set home directory
00225  * @param[in] connection Pointer to the client connection
00226  * @param[in] homeDir NULL-terminated string specifying the home directory
00227  * @return Error code
00228  **/
00229 
00230 error_t ftpServerSetHomeDir(FtpClientConnection *connection, const char_t *homeDir)
00231 {
00232    //Ensure the parameters are valid
00233    if(connection == NULL || homeDir == NULL)
00234       return ERROR_INVALID_PARAMETER;
00235 
00236    //Set home directory
00237    pathCombine(connection->homeDir, homeDir, FTP_SERVER_MAX_HOME_DIR_LEN);
00238    //Clean the resulting path
00239    pathCanonicalize(connection->homeDir);
00240    pathRemoveSlash(connection->homeDir);
00241 
00242    //Set current directory
00243    strcpy(connection->currentDir, connection->homeDir);
00244 
00245    //Successful processing
00246    return NO_ERROR;
00247 }
00248 
00249 
00250 /**
00251  * @brief FTP server task
00252  * @param[in] context Pointer to the FTP server context
00253  **/
00254 
00255 void ftpServerTask(FtpServerContext *context)
00256 {
00257    error_t error;
00258    uint_t i;
00259    systime_t time;
00260    FtpClientConnection *connection;
00261 
00262 #if (NET_RTOS_SUPPORT == ENABLED)
00263    //Process events
00264    while(1)
00265    {
00266 #endif
00267       //Clear event descriptor set
00268       memset(context->eventDesc, 0, sizeof(context->eventDesc));
00269 
00270       //Specify the events the application is interested in
00271       for(i = 0; i < FTP_SERVER_MAX_CONNECTIONS; i++)
00272       {
00273          //Point to the structure describing the current connection
00274          connection = context->connection[i];
00275 
00276          //Loop through active connections only
00277          if(connection != NULL)
00278          {
00279             //Ensure the control connection is opened
00280             if(connection->controlSocket != NULL)
00281             {
00282                //Check the state of the control connection
00283                if(connection->responseLength > 0)
00284                {
00285                   //Wait until there is more room in the send buffer
00286                   context->eventDesc[2 * i].socket = connection->controlSocket;
00287                   context->eventDesc[2 * i].eventMask = SOCKET_EVENT_TX_READY;
00288                }
00289                else if(connection->controlState == FTP_CONTROL_STATE_WAIT_ACK)
00290                {
00291                   //Wait for all the data to be transmitted and acknowledged
00292                   context->eventDesc[2 * i].socket = connection->controlSocket;
00293                   context->eventDesc[2 * i].eventMask = SOCKET_EVENT_TX_ACKED;
00294                }
00295                else if(connection->controlState == FTP_CONTROL_STATE_SHUTDOWN_TX)
00296                {
00297                   //Wait for the FIN to be acknowledged
00298                   context->eventDesc[2 * i].socket = connection->controlSocket;
00299                   context->eventDesc[2 * i].eventMask = SOCKET_EVENT_TX_SHUTDOWN;
00300                }
00301                else if(connection->controlState == FTP_CONTROL_STATE_SHUTDOWN_RX)
00302                {
00303                   //Wait for a FIN to be received
00304                   context->eventDesc[2 * i].socket = connection->controlSocket;
00305                   context->eventDesc[2 * i].eventMask = SOCKET_EVENT_RX_SHUTDOWN;
00306                }
00307                else
00308                {
00309                   //Wait for data to be available for reading
00310                   context->eventDesc[2 * i].socket = connection->controlSocket;
00311                   context->eventDesc[2 * i].eventMask = SOCKET_EVENT_RX_READY;
00312                }
00313             }
00314 
00315             //Ensure the data connection is opened
00316             if(connection->dataSocket != NULL)
00317             {
00318                //Check the state of the data connection
00319                if(connection->dataState == FTP_DATA_STATE_LISTEN ||
00320                   connection->dataState == FTP_DATA_STATE_RECEIVE)
00321                {
00322                   //Wait for data to be available for reading
00323                   context->eventDesc[2 * i + 1].socket = connection->dataSocket;
00324                   context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_RX_READY;
00325                }
00326                else if(connection->dataState == FTP_DATA_STATE_SEND)
00327                {
00328                   //Wait until there is more room in the send buffer
00329                   context->eventDesc[2 * i + 1].socket = connection->dataSocket;
00330                   context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_TX_READY;
00331                }
00332 
00333                else if(connection->dataState == FTP_DATA_STATE_WAIT_ACK)
00334                {
00335                   //Wait for all the data to be transmitted and acknowledged
00336                   context->eventDesc[2 * i + 1].socket = connection->dataSocket;
00337                   context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_TX_ACKED;
00338                }
00339                else if(connection->dataState == FTP_DATA_STATE_SHUTDOWN_TX)
00340                {
00341                   //Wait for the FIN to be acknowledged
00342                   context->eventDesc[2 * i + 1].socket = connection->dataSocket;
00343                   context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_TX_SHUTDOWN;
00344                }
00345                else if(connection->dataState == FTP_DATA_STATE_SHUTDOWN_RX)
00346                {
00347                   //Wait for a FIN to be received
00348                   context->eventDesc[2 * i + 1].socket = connection->dataSocket;
00349                   context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_RX_SHUTDOWN;
00350                }
00351             }
00352          }
00353       }
00354 
00355       //Accept connection request events
00356       context->eventDesc[2 * i].socket = context->socket;
00357       context->eventDesc[2 * i].eventMask = SOCKET_EVENT_RX_READY;
00358 
00359       //Wait for one of the set of sockets to become ready to perform I/O
00360       error = socketPoll(context->eventDesc, 2 * FTP_SERVER_MAX_CONNECTIONS + 1,
00361          &context->event, FTP_SERVER_SOCKET_POLLING_TIMEOUT);
00362 
00363       //Get current time
00364       time = osGetSystemTime();
00365 
00366       //Verify status code
00367       if(!error)
00368       {
00369          //Event-driven processing
00370          for(i = 0; i < FTP_SERVER_MAX_CONNECTIONS; i++)
00371          {
00372             //Point to the structure describing the current connection
00373             connection = context->connection[i];
00374 
00375             //Make sure the control connection is still active
00376             if(connection != NULL && connection->controlSocket != NULL)
00377             {
00378                //Check whether the control socket is to ready to perform I/O
00379                if(context->eventDesc[2 * i].eventFlags)
00380                {
00381                   //Update time stamp
00382                   connection->timestamp = time;
00383                   //Control connection event handler
00384                   ftpServerControlEventHandler(context, connection,
00385                      context->eventDesc[2 * i].eventFlags);
00386                }
00387             }
00388 
00389             //The connection may have been closed...
00390             connection = context->connection[i];
00391 
00392             //Make sure the data connection is still active
00393             if(connection != NULL && connection->dataSocket != NULL)
00394             {
00395                //Check whether the data socket to is ready to perform I/O
00396                if(context->eventDesc[2 * i + 1].eventFlags)
00397                {
00398                   //Update time stamp
00399                   connection->timestamp = time;
00400                   //Data connection event handler
00401                   ftpServerDataEventHandler(context, connection,
00402                      context->eventDesc[2 * i + 1].eventFlags);
00403                }
00404             }
00405          }
00406 
00407          //Check the state of the listening socket
00408          if(context->eventDesc[2 * i].eventFlags & SOCKET_EVENT_RX_READY)
00409          {
00410             //Process incoming connection request
00411             connection = ftpServerAcceptControlConnection(context);
00412             //Initialize time stamp
00413             if(connection != NULL)
00414                connection->timestamp = time;
00415          }
00416       }
00417 
00418       //Manage timeouts
00419       for(i = 0; i < FTP_SERVER_MAX_CONNECTIONS; i++)
00420       {
00421          //Point to the structure describing the current connection
00422          connection = context->connection[i];
00423 
00424          //Any client connected?
00425          if(connection != NULL)
00426          {
00427             //Disconnect inactive client after idle timeout
00428             if((time - connection->timestamp) >= FTP_SERVER_TIMEOUT)
00429             {
00430                //Debug message
00431                TRACE_INFO("FTP server: Closing inactive connection...\r\n");
00432                //Close connection with the client
00433                ftpServerCloseConnection(context, connection);
00434             }
00435          }
00436       }
00437 #if (NET_RTOS_SUPPORT == ENABLED)
00438    }
00439 #endif
00440 }
00441 
00442 #endif
00443