Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ftp_server_events.c
00001 /** 00002 * @file ftp_server_events.c 00003 * @brief FTP server (event handlers) 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 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL FTP_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include "ftp/ftp_server.h" 00034 #include "ftp/ftp_server_events.h" 00035 #include "ftp/ftp_server_commands.h" 00036 #include "ftp/ftp_server_misc.h" 00037 #include "str.h" 00038 #include "path.h" 00039 #include "error.h" 00040 #include "debug.h" 00041 00042 //Check TCP/IP stack configuration 00043 #if (FTP_SERVER_SUPPORT == ENABLED) 00044 00045 //Abbreviated months 00046 static const char months[13][4] = 00047 { 00048 " ", 00049 "Jan", 00050 "Feb", 00051 "Mar", 00052 "Apr", 00053 "May", 00054 "Jun", 00055 "Jul", 00056 "Aug", 00057 "Sep", 00058 "Oct", 00059 "Nov", 00060 "Dec" 00061 }; 00062 00063 00064 /** 00065 * @brief Control connection event handler 00066 * @param[in] context Pointer to the FTP server context 00067 * @param[in] connection Pointer to the client connection 00068 * @param[in] eventFlags Event to be processed 00069 **/ 00070 00071 void ftpServerControlEventHandler(FtpServerContext *context, 00072 FtpClientConnection * connection, uint_t eventFlags) 00073 { 00074 error_t error; 00075 size_t n; 00076 00077 //Send buffer is available for writing? 00078 if(eventFlags == SOCKET_EVENT_TX_READY) 00079 { 00080 //Send data back to the client 00081 error = socketSend(connection->controlSocket, connection->response + 00082 connection->responsePos, connection->responseLength, &n, 0); 00083 00084 //Failed to send data? 00085 if(error != NO_ERROR && error != ERROR_TIMEOUT) 00086 { 00087 //Close connection with the client 00088 ftpServerCloseConnection(context, connection); 00089 //Exit immediately 00090 return; 00091 } 00092 00093 //Advance data pointer 00094 connection->responsePos += n; 00095 //Number of bytes still available in the response buffer 00096 connection->responseLength -= n; 00097 } 00098 //Data is pending in the receive buffer? 00099 else if(eventFlags == SOCKET_EVENT_RX_READY) 00100 { 00101 //Read data from the client 00102 error = socketReceive(connection->controlSocket, 00103 connection->command + connection->commandLength, 00104 FTP_SERVER_MAX_LINE_LEN - connection->commandLength, &n, 0); 00105 00106 //Failed to receive data? 00107 if(error == ERROR_END_OF_STREAM) 00108 { 00109 //Gracefully disconnect from the remote host 00110 connection->controlState = FTP_CONTROL_STATE_WAIT_ACK; 00111 //Exit immediately 00112 return; 00113 } 00114 else if(error) 00115 { 00116 //Close connection with the client 00117 ftpServerCloseConnection(context, connection); 00118 //Exit immediately 00119 return; 00120 } 00121 00122 //Number of bytes available in the command buffer 00123 connection->commandLength += n; 00124 //Process incoming command 00125 ftpServerProcessCmd(context, connection); 00126 } 00127 //Data are transmitted and acknowledged? 00128 else if(eventFlags == SOCKET_EVENT_TX_ACKED) 00129 { 00130 //Disable transmission 00131 socketShutdown(connection->controlSocket, SOCKET_SD_SEND); 00132 //Next state 00133 connection->controlState = FTP_CONTROL_STATE_SHUTDOWN_TX; 00134 } 00135 //Transmission is shut down? 00136 else if(eventFlags == SOCKET_EVENT_TX_SHUTDOWN) 00137 { 00138 //Disable reception 00139 socketShutdown(connection->controlSocket, SOCKET_SD_RECEIVE); 00140 //Next state 00141 connection->controlState = FTP_CONTROL_STATE_SHUTDOWN_RX; 00142 } 00143 //Reception is shut down? 00144 else if(eventFlags == SOCKET_EVENT_RX_SHUTDOWN) 00145 { 00146 //Properly close connection 00147 ftpServerCloseConnection(context, connection); 00148 } 00149 } 00150 00151 00152 /** 00153 * @brief Data connection event handler 00154 * @param[in] context Pointer to the FTP server context 00155 * @param[in] connection Pointer to the client connection 00156 * @param[in] eventFlags Event to be processed 00157 **/ 00158 00159 void ftpServerDataEventHandler(FtpServerContext *context, 00160 FtpClientConnection * connection, uint_t eventFlags) 00161 { 00162 //Any connection attempt? 00163 if(connection->dataState == FTP_DATA_STATE_LISTEN) 00164 { 00165 //Accept data connection 00166 ftpServerAcceptDataConnection(connection); 00167 } 00168 //Ready to send data? 00169 else if(connection->dataState == FTP_DATA_STATE_SEND) 00170 { 00171 //Send more data to the remote host 00172 ftpServerSendData(context, connection); 00173 } 00174 //Any data pending in the receive buffer? 00175 else if(connection->dataState == FTP_DATA_STATE_RECEIVE) 00176 { 00177 //Process incoming data 00178 ftpServerReceiveData(context, connection); 00179 } 00180 //Data are transmitted and acknowledged? 00181 else if(connection->dataState == FTP_DATA_STATE_WAIT_ACK) 00182 { 00183 //Disable transmission 00184 socketShutdown(connection->dataSocket, SOCKET_SD_SEND); 00185 //Next state 00186 connection->dataState = FTP_DATA_STATE_SHUTDOWN_TX; 00187 } 00188 //Transmission is shut down? 00189 else if(connection->dataState == FTP_DATA_STATE_SHUTDOWN_TX) 00190 { 00191 //Disable reception 00192 socketShutdown(connection->dataSocket, SOCKET_SD_RECEIVE); 00193 //Next state 00194 connection->dataState = FTP_DATA_STATE_SHUTDOWN_RX; 00195 } 00196 //Reception is shut down? 00197 else if(connection->dataState == FTP_DATA_STATE_SHUTDOWN_RX) 00198 { 00199 //Close the data connection 00200 ftpServerCloseDataConnection(connection); 00201 00202 //Back to idle state 00203 connection->controlState = FTP_CONTROL_STATE_IDLE; 00204 00205 //Transfer status 00206 strcpy(connection->response, "226 Transfer complete\r\n"); 00207 //Debug message 00208 TRACE_DEBUG("FTP server: %s", connection->response); 00209 00210 //Number of bytes in the response buffer 00211 connection->responseLength = strlen(connection->response); 00212 connection->responsePos = 0; 00213 } 00214 } 00215 00216 00217 /** 00218 * @brief Send data on the data connection 00219 * @param[in] context Pointer to the FTP server context 00220 * @param[in] connection Pointer to the client connection 00221 **/ 00222 00223 void ftpServerSendData(FtpServerContext *context, FtpClientConnection *connection) 00224 { 00225 error_t error; 00226 size_t n; 00227 00228 //Any data waiting for transmission? 00229 if(connection->bufferLength > 0) 00230 { 00231 //Send more data 00232 error = socketSend(connection->dataSocket, connection->buffer + 00233 connection->bufferPos, connection->bufferLength, &n, 0); 00234 00235 //Failed to send data? 00236 if(error != NO_ERROR && error != ERROR_TIMEOUT) 00237 { 00238 //Close the data connection 00239 ftpServerCloseDataConnection(connection); 00240 00241 //Release previously allocated resources 00242 if(connection->file != NULL) 00243 { 00244 fsCloseFile(connection->file); 00245 connection->file = NULL; 00246 } 00247 if(connection->dir != NULL) 00248 { 00249 fsCloseDir(connection->dir); 00250 connection->dir = NULL; 00251 } 00252 00253 //Back to idle state 00254 connection->controlState = FTP_CONTROL_STATE_IDLE; 00255 00256 //Transfer status 00257 strcpy(connection->response, "451 Transfer aborted\r\n"); 00258 //Debug message 00259 TRACE_DEBUG("FTP server: %s", connection->response); 00260 00261 //Number of bytes in the response buffer 00262 connection->responseLength = strlen(connection->response); 00263 connection->responsePos = 0; 00264 00265 //Exit immediately 00266 return; 00267 } 00268 00269 //Advance data pointer 00270 connection->bufferPos += n; 00271 //Number of bytes still available in the buffer 00272 connection->bufferLength -= n; 00273 } 00274 00275 //Empty transmission buffer? 00276 if(connection->bufferLength == 0) 00277 { 00278 //File transfer in progress? 00279 if(connection->controlState == FTP_CONTROL_STATE_RETR) 00280 { 00281 //Read more data 00282 error = fsReadFile(connection->file, 00283 connection->buffer, FTP_SERVER_BUFFER_SIZE, &n); 00284 00285 //End of stream? 00286 if(error) 00287 { 00288 //Close file 00289 fsCloseFile(connection->file); 00290 connection->file = NULL; 00291 00292 //Wait for all the data to be transmitted and acknowledged 00293 connection->dataState = FTP_DATA_STATE_WAIT_ACK; 00294 00295 //Exit immediately 00296 return; 00297 } 00298 } 00299 //Directory listing in progress? 00300 else if(connection->controlState == FTP_CONTROL_STATE_LIST) 00301 { 00302 uint_t perm; 00303 time_t currentTime; 00304 time_t modified; 00305 char_t *path; 00306 FsDirEntry dirEntry; 00307 00308 //Read a new entry in the directory 00309 error = fsReadDir(connection->dir, &dirEntry); 00310 00311 //End of stream? 00312 if(error) 00313 { 00314 //Close directory 00315 fsCloseDir(connection->dir); 00316 connection->dir = NULL; 00317 00318 //Wait for all the data to be transmitted and acknowledged 00319 connection->dataState = FTP_DATA_STATE_WAIT_ACK; 00320 00321 //Exit immediately 00322 return; 00323 } 00324 00325 //Point to the scratch buffer 00326 path = connection->buffer; 00327 00328 //Get the pathname of the directory being listed 00329 strcpy(path, connection->path); 00330 //Retrieve the full pathname 00331 pathCombine(path, dirEntry.name, FTP_SERVER_MAX_PATH_LEN); 00332 pathCanonicalize(path); 00333 00334 //Get permissions for the specified file 00335 perm = ftpServerGetFilePermissions(context, connection, path); 00336 00337 //Enforce access rights 00338 if(perm & FTP_FILE_PERM_LIST) 00339 { 00340 //Format links, owner, group and size fields 00341 n = sprintf(connection->buffer, "---------- 1 owner group %10" PRIu32, 00342 dirEntry.size); 00343 00344 //Check whether the current entry is a directory 00345 if(dirEntry.attributes & FS_FILE_ATTR_DIRECTORY) 00346 connection->buffer[0] = 'd'; 00347 00348 //Read access permitted? 00349 if(perm & FTP_FILE_PERM_READ) 00350 { 00351 connection->buffer[1] = 'r'; 00352 connection->buffer[4] = 'r'; 00353 connection->buffer[7] = 'r'; 00354 } 00355 00356 //Write access permitted? 00357 if(perm & FTP_FILE_PERM_WRITE) 00358 { 00359 //Make sure the file is not marked as read-only 00360 if(!(dirEntry.attributes & FS_FILE_ATTR_READ_ONLY)) 00361 { 00362 connection->buffer[2] = 'w'; 00363 connection->buffer[5] = 'w'; 00364 connection->buffer[8] = 'w'; 00365 } 00366 } 00367 00368 //Get current time 00369 currentTime = getCurrentUnixTime(); 00370 //Get modification time 00371 modified = convertDateToUnixTime(&dirEntry.modified); 00372 00373 //Check whether the modification time is within the previous 180 days 00374 if(currentTime > modified && currentTime < (modified + FTP_SERVER_180_DAYS)) 00375 { 00376 //The format of the date/time field is Mmm dd hh:mm 00377 n += sprintf(connection->buffer + n, " %s %02" PRIu8 " %02" PRIu8 ":%02" PRIu8, 00378 months[MIN(dirEntry.modified.month, 12)], dirEntry.modified.day, 00379 dirEntry.modified.hours, dirEntry.modified.minutes); 00380 } 00381 else 00382 { 00383 //The format of the date/time field is Mmm dd yyyy 00384 n += sprintf(connection->buffer + n, " %s %02" PRIu8 " %04" PRIu16, 00385 months[MIN(dirEntry.modified.month, 12)], dirEntry.modified.day, 00386 dirEntry.modified.year); 00387 } 00388 00389 //Append filename 00390 n += sprintf(connection->buffer + n, " %s\r\n", dirEntry.name); 00391 //Debug message 00392 TRACE_DEBUG("FTP server: %s", connection->buffer); 00393 } 00394 else 00395 { 00396 //Insufficient access rights 00397 n = 0; 00398 } 00399 } 00400 //Invalid state? 00401 else 00402 { 00403 //The FTP server has encountered a critical error 00404 ftpServerCloseConnection(context, connection); 00405 //Exit immediately 00406 return; 00407 } 00408 00409 //Number of bytes in the buffer 00410 connection->bufferPos = 0; 00411 connection->bufferLength = n; 00412 } 00413 } 00414 00415 00416 /** 00417 * @brief Receive data on the data connection 00418 * @param[in] context Pointer to the FTP server context 00419 * @param[in] connection Pointer to the client connection 00420 **/ 00421 00422 void ftpServerReceiveData(FtpServerContext *context, FtpClientConnection *connection) 00423 { 00424 error_t error; 00425 bool_t eof; 00426 size_t n; 00427 00428 //File transfer in progress? 00429 if(connection->controlState == FTP_CONTROL_STATE_STOR || 00430 connection->controlState == FTP_CONTROL_STATE_APPE) 00431 { 00432 //Read incoming data 00433 error = socketReceive(connection->dataSocket, 00434 connection->buffer + connection->bufferPos, 00435 FTP_SERVER_BUFFER_SIZE - connection->bufferLength, &n, 0); 00436 00437 //Any error to report? 00438 if(error) 00439 { 00440 //Cannot read more data 00441 eof = TRUE; 00442 } 00443 else 00444 { 00445 //Successful read operation 00446 eof = FALSE; 00447 00448 //Advance data pointer 00449 connection->bufferPos += n; 00450 connection->bufferLength += n; 00451 } 00452 00453 //Read data until the buffer is full or the end of the file is reached 00454 if(eof || connection->bufferLength >= FTP_SERVER_BUFFER_SIZE) 00455 { 00456 //Any data to be written? 00457 if(connection->bufferLength > 0) 00458 { 00459 //Write data to the specified file 00460 error = fsWriteFile(connection->file, 00461 connection->buffer, connection->bufferLength); 00462 00463 //Any error to report? 00464 if(error) 00465 { 00466 //Close the data connection 00467 ftpServerCloseDataConnection(connection); 00468 00469 //Release previously allocated resources 00470 fsCloseFile(connection->file); 00471 connection->file = NULL; 00472 00473 //Back to idle state 00474 connection->controlState = FTP_CONTROL_STATE_IDLE; 00475 00476 //Transfer status 00477 strcpy(connection->response, "451 Transfer aborted\r\n"); 00478 //Debug message 00479 TRACE_DEBUG("FTP server: %s", connection->response); 00480 00481 //Number of bytes in the response buffer 00482 connection->responseLength = strlen(connection->response); 00483 connection->responsePos = 0; 00484 00485 //Exit immediately 00486 return; 00487 } 00488 } 00489 00490 //Flush reception buffer 00491 connection->bufferLength = 0; 00492 connection->bufferPos = 0; 00493 } 00494 00495 //End of stream? 00496 if(eof) 00497 { 00498 //Close file 00499 fsCloseFile(connection->file); 00500 connection->file = NULL; 00501 00502 //Graceful shutdown sequence 00503 connection->dataState = FTP_DATA_STATE_WAIT_ACK; 00504 } 00505 } 00506 //Invalid state? 00507 else 00508 { 00509 //The FTP server has encountered a critical error 00510 ftpServerCloseConnection(context, connection); 00511 } 00512 } 00513 00514 #endif 00515
Generated on Tue Jul 12 2022 17:10:13 by
1.7.2