Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:13 by
