Webserver+3d print
cyclone_tcp/ftp/ftp_server.c@0:8918a71cdbe9, 2017-02-04 (annotated)
- Committer:
- Sergunb
- Date:
- Sat Feb 04 18:15:49 2017 +0000
- Revision:
- 0:8918a71cdbe9
nothing else
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Sergunb | 0:8918a71cdbe9 | 1 | /** |
Sergunb | 0:8918a71cdbe9 | 2 | * @file ftp_server.c |
Sergunb | 0:8918a71cdbe9 | 3 | * @brief FTP server (File Transfer Protocol) |
Sergunb | 0:8918a71cdbe9 | 4 | * |
Sergunb | 0:8918a71cdbe9 | 5 | * @section License |
Sergunb | 0:8918a71cdbe9 | 6 | * |
Sergunb | 0:8918a71cdbe9 | 7 | * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. |
Sergunb | 0:8918a71cdbe9 | 8 | * |
Sergunb | 0:8918a71cdbe9 | 9 | * This file is part of CycloneTCP Open. |
Sergunb | 0:8918a71cdbe9 | 10 | * |
Sergunb | 0:8918a71cdbe9 | 11 | * This program is free software; you can redistribute it and/or |
Sergunb | 0:8918a71cdbe9 | 12 | * modify it under the terms of the GNU General Public License |
Sergunb | 0:8918a71cdbe9 | 13 | * as published by the Free Software Foundation; either version 2 |
Sergunb | 0:8918a71cdbe9 | 14 | * of the License, or (at your option) any later version. |
Sergunb | 0:8918a71cdbe9 | 15 | * |
Sergunb | 0:8918a71cdbe9 | 16 | * This program is distributed in the hope that it will be useful, |
Sergunb | 0:8918a71cdbe9 | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
Sergunb | 0:8918a71cdbe9 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
Sergunb | 0:8918a71cdbe9 | 19 | * GNU General Public License for more details. |
Sergunb | 0:8918a71cdbe9 | 20 | * |
Sergunb | 0:8918a71cdbe9 | 21 | * You should have received a copy of the GNU General Public License |
Sergunb | 0:8918a71cdbe9 | 22 | * along with this program; if not, write to the Free Software Foundation, |
Sergunb | 0:8918a71cdbe9 | 23 | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
Sergunb | 0:8918a71cdbe9 | 24 | * |
Sergunb | 0:8918a71cdbe9 | 25 | * @section Description |
Sergunb | 0:8918a71cdbe9 | 26 | * |
Sergunb | 0:8918a71cdbe9 | 27 | * File Transfer Protocol (FTP) is a standard network protocol used to |
Sergunb | 0:8918a71cdbe9 | 28 | * transfer files from one host to another host over a TCP-based network. |
Sergunb | 0:8918a71cdbe9 | 29 | * Refer to the following RFCs for complete details: |
Sergunb | 0:8918a71cdbe9 | 30 | * - RFC 959: File Transfer Protocol (FTP) |
Sergunb | 0:8918a71cdbe9 | 31 | * - RFC 3659: Extensions to FTP |
Sergunb | 0:8918a71cdbe9 | 32 | * - RFC 2428: FTP Extensions for IPv6 and NATs |
Sergunb | 0:8918a71cdbe9 | 33 | * |
Sergunb | 0:8918a71cdbe9 | 34 | * @author Oryx Embedded SARL (www.oryx-embedded.com) |
Sergunb | 0:8918a71cdbe9 | 35 | * @version 1.7.6 |
Sergunb | 0:8918a71cdbe9 | 36 | **/ |
Sergunb | 0:8918a71cdbe9 | 37 | |
Sergunb | 0:8918a71cdbe9 | 38 | //Switch to the appropriate trace level |
Sergunb | 0:8918a71cdbe9 | 39 | #define TRACE_LEVEL FTP_TRACE_LEVEL |
Sergunb | 0:8918a71cdbe9 | 40 | |
Sergunb | 0:8918a71cdbe9 | 41 | //Dependencies |
Sergunb | 0:8918a71cdbe9 | 42 | #include "ftp/ftp_server.h" |
Sergunb | 0:8918a71cdbe9 | 43 | #include "ftp/ftp_server_events.h" |
Sergunb | 0:8918a71cdbe9 | 44 | #include "ftp/ftp_server_commands.h" |
Sergunb | 0:8918a71cdbe9 | 45 | #include "ftp/ftp_server_misc.h" |
Sergunb | 0:8918a71cdbe9 | 46 | #include "str.h" |
Sergunb | 0:8918a71cdbe9 | 47 | #include "path.h" |
Sergunb | 0:8918a71cdbe9 | 48 | #include "error.h" |
Sergunb | 0:8918a71cdbe9 | 49 | #include "debug.h" |
Sergunb | 0:8918a71cdbe9 | 50 | |
Sergunb | 0:8918a71cdbe9 | 51 | //Check TCP/IP stack configuration |
Sergunb | 0:8918a71cdbe9 | 52 | #if (FTP_SERVER_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 53 | |
Sergunb | 0:8918a71cdbe9 | 54 | |
Sergunb | 0:8918a71cdbe9 | 55 | /** |
Sergunb | 0:8918a71cdbe9 | 56 | * @brief Initialize settings with default values |
Sergunb | 0:8918a71cdbe9 | 57 | * @param[out] settings Structure that contains FTP server settings |
Sergunb | 0:8918a71cdbe9 | 58 | **/ |
Sergunb | 0:8918a71cdbe9 | 59 | |
Sergunb | 0:8918a71cdbe9 | 60 | void ftpServerGetDefaultSettings(FtpServerSettings *settings) |
Sergunb | 0:8918a71cdbe9 | 61 | { |
Sergunb | 0:8918a71cdbe9 | 62 | //The FTP server is not bound to any interface |
Sergunb | 0:8918a71cdbe9 | 63 | settings->interface = NULL; |
Sergunb | 0:8918a71cdbe9 | 64 | |
Sergunb | 0:8918a71cdbe9 | 65 | //FTP command port number |
Sergunb | 0:8918a71cdbe9 | 66 | settings->port = FTP_PORT; |
Sergunb | 0:8918a71cdbe9 | 67 | //FTP data port number |
Sergunb | 0:8918a71cdbe9 | 68 | settings->dataPort = FTP_DATA_PORT; |
Sergunb | 0:8918a71cdbe9 | 69 | //Passive port range |
Sergunb | 0:8918a71cdbe9 | 70 | settings->passivePortMin = FTP_SERVER_PASSIVE_PORT_MIN; |
Sergunb | 0:8918a71cdbe9 | 71 | settings->passivePortMax = FTP_SERVER_PASSIVE_PORT_MAX; |
Sergunb | 0:8918a71cdbe9 | 72 | //Set root directory |
Sergunb | 0:8918a71cdbe9 | 73 | strcpy(settings->rootDir, "/"); |
Sergunb | 0:8918a71cdbe9 | 74 | //User verification callback function |
Sergunb | 0:8918a71cdbe9 | 75 | settings->checkUserCallback = NULL; |
Sergunb | 0:8918a71cdbe9 | 76 | //Password verification callback function |
Sergunb | 0:8918a71cdbe9 | 77 | settings->checkPasswordCallback = NULL; |
Sergunb | 0:8918a71cdbe9 | 78 | //Callback used to retrieve file permissions |
Sergunb | 0:8918a71cdbe9 | 79 | settings->getFilePermCallback = NULL; |
Sergunb | 0:8918a71cdbe9 | 80 | //Unknown command callback function |
Sergunb | 0:8918a71cdbe9 | 81 | settings->unknownCommandCallback = NULL; |
Sergunb | 0:8918a71cdbe9 | 82 | } |
Sergunb | 0:8918a71cdbe9 | 83 | |
Sergunb | 0:8918a71cdbe9 | 84 | |
Sergunb | 0:8918a71cdbe9 | 85 | /** |
Sergunb | 0:8918a71cdbe9 | 86 | * @brief FTP server initialization |
Sergunb | 0:8918a71cdbe9 | 87 | * @param[in] context Pointer to the FTP server context |
Sergunb | 0:8918a71cdbe9 | 88 | * @param[in] settings FTP server specific settings |
Sergunb | 0:8918a71cdbe9 | 89 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 90 | **/ |
Sergunb | 0:8918a71cdbe9 | 91 | |
Sergunb | 0:8918a71cdbe9 | 92 | error_t ftpServerInit(FtpServerContext *context, const FtpServerSettings *settings) |
Sergunb | 0:8918a71cdbe9 | 93 | { |
Sergunb | 0:8918a71cdbe9 | 94 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 95 | |
Sergunb | 0:8918a71cdbe9 | 96 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 97 | TRACE_INFO("Initializing FTP server...\r\n"); |
Sergunb | 0:8918a71cdbe9 | 98 | |
Sergunb | 0:8918a71cdbe9 | 99 | //Ensure the parameters are valid |
Sergunb | 0:8918a71cdbe9 | 100 | if(context == NULL || settings == NULL) |
Sergunb | 0:8918a71cdbe9 | 101 | return ERROR_INVALID_PARAMETER; |
Sergunb | 0:8918a71cdbe9 | 102 | |
Sergunb | 0:8918a71cdbe9 | 103 | //Check passive port range |
Sergunb | 0:8918a71cdbe9 | 104 | if(settings->passivePortMax <= settings->passivePortMin) |
Sergunb | 0:8918a71cdbe9 | 105 | return ERROR_INVALID_PARAMETER; |
Sergunb | 0:8918a71cdbe9 | 106 | |
Sergunb | 0:8918a71cdbe9 | 107 | //Clear the FTP server context |
Sergunb | 0:8918a71cdbe9 | 108 | memset(context, 0, sizeof(FtpServerContext)); |
Sergunb | 0:8918a71cdbe9 | 109 | |
Sergunb | 0:8918a71cdbe9 | 110 | //Save user settings |
Sergunb | 0:8918a71cdbe9 | 111 | context->settings = *settings; |
Sergunb | 0:8918a71cdbe9 | 112 | |
Sergunb | 0:8918a71cdbe9 | 113 | //Clean the root directory path |
Sergunb | 0:8918a71cdbe9 | 114 | pathCanonicalize(context->settings.rootDir); |
Sergunb | 0:8918a71cdbe9 | 115 | pathRemoveSlash(context->settings.rootDir); |
Sergunb | 0:8918a71cdbe9 | 116 | |
Sergunb | 0:8918a71cdbe9 | 117 | //Create an event object to poll the state of sockets |
Sergunb | 0:8918a71cdbe9 | 118 | if(!osCreateEvent(&context->event)) |
Sergunb | 0:8918a71cdbe9 | 119 | { |
Sergunb | 0:8918a71cdbe9 | 120 | //Failed to create event |
Sergunb | 0:8918a71cdbe9 | 121 | return ERROR_OUT_OF_RESOURCES; |
Sergunb | 0:8918a71cdbe9 | 122 | } |
Sergunb | 0:8918a71cdbe9 | 123 | |
Sergunb | 0:8918a71cdbe9 | 124 | //Start of exception handling block |
Sergunb | 0:8918a71cdbe9 | 125 | do |
Sergunb | 0:8918a71cdbe9 | 126 | { |
Sergunb | 0:8918a71cdbe9 | 127 | //Open a TCP socket |
Sergunb | 0:8918a71cdbe9 | 128 | context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); |
Sergunb | 0:8918a71cdbe9 | 129 | //Failed to open socket? |
Sergunb | 0:8918a71cdbe9 | 130 | if(!context->socket) |
Sergunb | 0:8918a71cdbe9 | 131 | { |
Sergunb | 0:8918a71cdbe9 | 132 | //Report an error |
Sergunb | 0:8918a71cdbe9 | 133 | error = ERROR_OPEN_FAILED; |
Sergunb | 0:8918a71cdbe9 | 134 | //Exit immediately |
Sergunb | 0:8918a71cdbe9 | 135 | break; |
Sergunb | 0:8918a71cdbe9 | 136 | } |
Sergunb | 0:8918a71cdbe9 | 137 | |
Sergunb | 0:8918a71cdbe9 | 138 | //Set timeout for blocking functions |
Sergunb | 0:8918a71cdbe9 | 139 | error = socketSetTimeout(context->socket, INFINITE_DELAY); |
Sergunb | 0:8918a71cdbe9 | 140 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 141 | if(error) |
Sergunb | 0:8918a71cdbe9 | 142 | break; |
Sergunb | 0:8918a71cdbe9 | 143 | |
Sergunb | 0:8918a71cdbe9 | 144 | //Change the size of the TX buffer |
Sergunb | 0:8918a71cdbe9 | 145 | error = socketSetTxBufferSize(context->socket, |
Sergunb | 0:8918a71cdbe9 | 146 | FTP_SERVER_CTRL_SOCKET_BUFFER_SIZE); |
Sergunb | 0:8918a71cdbe9 | 147 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 148 | if(error) |
Sergunb | 0:8918a71cdbe9 | 149 | break; |
Sergunb | 0:8918a71cdbe9 | 150 | |
Sergunb | 0:8918a71cdbe9 | 151 | //Change the size of the RX buffer |
Sergunb | 0:8918a71cdbe9 | 152 | error = socketSetRxBufferSize(context->socket, |
Sergunb | 0:8918a71cdbe9 | 153 | FTP_SERVER_CTRL_SOCKET_BUFFER_SIZE); |
Sergunb | 0:8918a71cdbe9 | 154 | //Any error to report? |
Sergunb | 0:8918a71cdbe9 | 155 | if(error) |
Sergunb | 0:8918a71cdbe9 | 156 | break; |
Sergunb | 0:8918a71cdbe9 | 157 | |
Sergunb | 0:8918a71cdbe9 | 158 | //Associate the socket with the relevant interface |
Sergunb | 0:8918a71cdbe9 | 159 | error = socketBindToInterface(context->socket, settings->interface); |
Sergunb | 0:8918a71cdbe9 | 160 | //Unable to bind the socket to the desired interface? |
Sergunb | 0:8918a71cdbe9 | 161 | if(error) |
Sergunb | 0:8918a71cdbe9 | 162 | break; |
Sergunb | 0:8918a71cdbe9 | 163 | |
Sergunb | 0:8918a71cdbe9 | 164 | //Bind newly created socket to port 21 |
Sergunb | 0:8918a71cdbe9 | 165 | error = socketBind(context->socket, &IP_ADDR_ANY, settings->port); |
Sergunb | 0:8918a71cdbe9 | 166 | //Failed to bind socket to port 21? |
Sergunb | 0:8918a71cdbe9 | 167 | if(error) |
Sergunb | 0:8918a71cdbe9 | 168 | break; |
Sergunb | 0:8918a71cdbe9 | 169 | |
Sergunb | 0:8918a71cdbe9 | 170 | //Place socket in listening state |
Sergunb | 0:8918a71cdbe9 | 171 | error = socketListen(context->socket, FTP_SERVER_BACKLOG); |
Sergunb | 0:8918a71cdbe9 | 172 | //Any failure to report? |
Sergunb | 0:8918a71cdbe9 | 173 | if(error) |
Sergunb | 0:8918a71cdbe9 | 174 | break; |
Sergunb | 0:8918a71cdbe9 | 175 | |
Sergunb | 0:8918a71cdbe9 | 176 | //End of exception handling block |
Sergunb | 0:8918a71cdbe9 | 177 | } while(0); |
Sergunb | 0:8918a71cdbe9 | 178 | |
Sergunb | 0:8918a71cdbe9 | 179 | //Did we encounter an error? |
Sergunb | 0:8918a71cdbe9 | 180 | if(error) |
Sergunb | 0:8918a71cdbe9 | 181 | { |
Sergunb | 0:8918a71cdbe9 | 182 | //Free previously allocated resources |
Sergunb | 0:8918a71cdbe9 | 183 | osDeleteEvent(&context->event); |
Sergunb | 0:8918a71cdbe9 | 184 | //Close socket |
Sergunb | 0:8918a71cdbe9 | 185 | socketClose(context->socket); |
Sergunb | 0:8918a71cdbe9 | 186 | } |
Sergunb | 0:8918a71cdbe9 | 187 | |
Sergunb | 0:8918a71cdbe9 | 188 | //Return status code |
Sergunb | 0:8918a71cdbe9 | 189 | return error; |
Sergunb | 0:8918a71cdbe9 | 190 | } |
Sergunb | 0:8918a71cdbe9 | 191 | |
Sergunb | 0:8918a71cdbe9 | 192 | |
Sergunb | 0:8918a71cdbe9 | 193 | /** |
Sergunb | 0:8918a71cdbe9 | 194 | * @brief Start FTP server |
Sergunb | 0:8918a71cdbe9 | 195 | * @param[in] context Pointer to the FTP server context |
Sergunb | 0:8918a71cdbe9 | 196 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 197 | **/ |
Sergunb | 0:8918a71cdbe9 | 198 | |
Sergunb | 0:8918a71cdbe9 | 199 | error_t ftpServerStart(FtpServerContext *context) |
Sergunb | 0:8918a71cdbe9 | 200 | { |
Sergunb | 0:8918a71cdbe9 | 201 | OsTask *task; |
Sergunb | 0:8918a71cdbe9 | 202 | |
Sergunb | 0:8918a71cdbe9 | 203 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 204 | TRACE_INFO("Starting FTP server...\r\n"); |
Sergunb | 0:8918a71cdbe9 | 205 | |
Sergunb | 0:8918a71cdbe9 | 206 | //Make sure the FTP server context is valid |
Sergunb | 0:8918a71cdbe9 | 207 | if(context == NULL) |
Sergunb | 0:8918a71cdbe9 | 208 | return ERROR_INVALID_PARAMETER; |
Sergunb | 0:8918a71cdbe9 | 209 | |
Sergunb | 0:8918a71cdbe9 | 210 | //Create the FTP server task |
Sergunb | 0:8918a71cdbe9 | 211 | task = osCreateTask("FTP Server", (OsTaskCode) ftpServerTask, |
Sergunb | 0:8918a71cdbe9 | 212 | context, FTP_SERVER_STACK_SIZE, FTP_SERVER_PRIORITY); |
Sergunb | 0:8918a71cdbe9 | 213 | |
Sergunb | 0:8918a71cdbe9 | 214 | //Unable to create the task? |
Sergunb | 0:8918a71cdbe9 | 215 | if(task == OS_INVALID_HANDLE) |
Sergunb | 0:8918a71cdbe9 | 216 | return ERROR_OUT_OF_RESOURCES; |
Sergunb | 0:8918a71cdbe9 | 217 | |
Sergunb | 0:8918a71cdbe9 | 218 | //Successful processing |
Sergunb | 0:8918a71cdbe9 | 219 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 220 | } |
Sergunb | 0:8918a71cdbe9 | 221 | |
Sergunb | 0:8918a71cdbe9 | 222 | |
Sergunb | 0:8918a71cdbe9 | 223 | /** |
Sergunb | 0:8918a71cdbe9 | 224 | * @brief Set home directory |
Sergunb | 0:8918a71cdbe9 | 225 | * @param[in] connection Pointer to the client connection |
Sergunb | 0:8918a71cdbe9 | 226 | * @param[in] homeDir NULL-terminated string specifying the home directory |
Sergunb | 0:8918a71cdbe9 | 227 | * @return Error code |
Sergunb | 0:8918a71cdbe9 | 228 | **/ |
Sergunb | 0:8918a71cdbe9 | 229 | |
Sergunb | 0:8918a71cdbe9 | 230 | error_t ftpServerSetHomeDir(FtpClientConnection *connection, const char_t *homeDir) |
Sergunb | 0:8918a71cdbe9 | 231 | { |
Sergunb | 0:8918a71cdbe9 | 232 | //Ensure the parameters are valid |
Sergunb | 0:8918a71cdbe9 | 233 | if(connection == NULL || homeDir == NULL) |
Sergunb | 0:8918a71cdbe9 | 234 | return ERROR_INVALID_PARAMETER; |
Sergunb | 0:8918a71cdbe9 | 235 | |
Sergunb | 0:8918a71cdbe9 | 236 | //Set home directory |
Sergunb | 0:8918a71cdbe9 | 237 | pathCombine(connection->homeDir, homeDir, FTP_SERVER_MAX_HOME_DIR_LEN); |
Sergunb | 0:8918a71cdbe9 | 238 | //Clean the resulting path |
Sergunb | 0:8918a71cdbe9 | 239 | pathCanonicalize(connection->homeDir); |
Sergunb | 0:8918a71cdbe9 | 240 | pathRemoveSlash(connection->homeDir); |
Sergunb | 0:8918a71cdbe9 | 241 | |
Sergunb | 0:8918a71cdbe9 | 242 | //Set current directory |
Sergunb | 0:8918a71cdbe9 | 243 | strcpy(connection->currentDir, connection->homeDir); |
Sergunb | 0:8918a71cdbe9 | 244 | |
Sergunb | 0:8918a71cdbe9 | 245 | //Successful processing |
Sergunb | 0:8918a71cdbe9 | 246 | return NO_ERROR; |
Sergunb | 0:8918a71cdbe9 | 247 | } |
Sergunb | 0:8918a71cdbe9 | 248 | |
Sergunb | 0:8918a71cdbe9 | 249 | |
Sergunb | 0:8918a71cdbe9 | 250 | /** |
Sergunb | 0:8918a71cdbe9 | 251 | * @brief FTP server task |
Sergunb | 0:8918a71cdbe9 | 252 | * @param[in] context Pointer to the FTP server context |
Sergunb | 0:8918a71cdbe9 | 253 | **/ |
Sergunb | 0:8918a71cdbe9 | 254 | |
Sergunb | 0:8918a71cdbe9 | 255 | void ftpServerTask(FtpServerContext *context) |
Sergunb | 0:8918a71cdbe9 | 256 | { |
Sergunb | 0:8918a71cdbe9 | 257 | error_t error; |
Sergunb | 0:8918a71cdbe9 | 258 | uint_t i; |
Sergunb | 0:8918a71cdbe9 | 259 | systime_t time; |
Sergunb | 0:8918a71cdbe9 | 260 | FtpClientConnection *connection; |
Sergunb | 0:8918a71cdbe9 | 261 | |
Sergunb | 0:8918a71cdbe9 | 262 | #if (NET_RTOS_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 263 | //Process events |
Sergunb | 0:8918a71cdbe9 | 264 | while(1) |
Sergunb | 0:8918a71cdbe9 | 265 | { |
Sergunb | 0:8918a71cdbe9 | 266 | #endif |
Sergunb | 0:8918a71cdbe9 | 267 | //Clear event descriptor set |
Sergunb | 0:8918a71cdbe9 | 268 | memset(context->eventDesc, 0, sizeof(context->eventDesc)); |
Sergunb | 0:8918a71cdbe9 | 269 | |
Sergunb | 0:8918a71cdbe9 | 270 | //Specify the events the application is interested in |
Sergunb | 0:8918a71cdbe9 | 271 | for(i = 0; i < FTP_SERVER_MAX_CONNECTIONS; i++) |
Sergunb | 0:8918a71cdbe9 | 272 | { |
Sergunb | 0:8918a71cdbe9 | 273 | //Point to the structure describing the current connection |
Sergunb | 0:8918a71cdbe9 | 274 | connection = context->connection[i]; |
Sergunb | 0:8918a71cdbe9 | 275 | |
Sergunb | 0:8918a71cdbe9 | 276 | //Loop through active connections only |
Sergunb | 0:8918a71cdbe9 | 277 | if(connection != NULL) |
Sergunb | 0:8918a71cdbe9 | 278 | { |
Sergunb | 0:8918a71cdbe9 | 279 | //Ensure the control connection is opened |
Sergunb | 0:8918a71cdbe9 | 280 | if(connection->controlSocket != NULL) |
Sergunb | 0:8918a71cdbe9 | 281 | { |
Sergunb | 0:8918a71cdbe9 | 282 | //Check the state of the control connection |
Sergunb | 0:8918a71cdbe9 | 283 | if(connection->responseLength > 0) |
Sergunb | 0:8918a71cdbe9 | 284 | { |
Sergunb | 0:8918a71cdbe9 | 285 | //Wait until there is more room in the send buffer |
Sergunb | 0:8918a71cdbe9 | 286 | context->eventDesc[2 * i].socket = connection->controlSocket; |
Sergunb | 0:8918a71cdbe9 | 287 | context->eventDesc[2 * i].eventMask = SOCKET_EVENT_TX_READY; |
Sergunb | 0:8918a71cdbe9 | 288 | } |
Sergunb | 0:8918a71cdbe9 | 289 | else if(connection->controlState == FTP_CONTROL_STATE_WAIT_ACK) |
Sergunb | 0:8918a71cdbe9 | 290 | { |
Sergunb | 0:8918a71cdbe9 | 291 | //Wait for all the data to be transmitted and acknowledged |
Sergunb | 0:8918a71cdbe9 | 292 | context->eventDesc[2 * i].socket = connection->controlSocket; |
Sergunb | 0:8918a71cdbe9 | 293 | context->eventDesc[2 * i].eventMask = SOCKET_EVENT_TX_ACKED; |
Sergunb | 0:8918a71cdbe9 | 294 | } |
Sergunb | 0:8918a71cdbe9 | 295 | else if(connection->controlState == FTP_CONTROL_STATE_SHUTDOWN_TX) |
Sergunb | 0:8918a71cdbe9 | 296 | { |
Sergunb | 0:8918a71cdbe9 | 297 | //Wait for the FIN to be acknowledged |
Sergunb | 0:8918a71cdbe9 | 298 | context->eventDesc[2 * i].socket = connection->controlSocket; |
Sergunb | 0:8918a71cdbe9 | 299 | context->eventDesc[2 * i].eventMask = SOCKET_EVENT_TX_SHUTDOWN; |
Sergunb | 0:8918a71cdbe9 | 300 | } |
Sergunb | 0:8918a71cdbe9 | 301 | else if(connection->controlState == FTP_CONTROL_STATE_SHUTDOWN_RX) |
Sergunb | 0:8918a71cdbe9 | 302 | { |
Sergunb | 0:8918a71cdbe9 | 303 | //Wait for a FIN to be received |
Sergunb | 0:8918a71cdbe9 | 304 | context->eventDesc[2 * i].socket = connection->controlSocket; |
Sergunb | 0:8918a71cdbe9 | 305 | context->eventDesc[2 * i].eventMask = SOCKET_EVENT_RX_SHUTDOWN; |
Sergunb | 0:8918a71cdbe9 | 306 | } |
Sergunb | 0:8918a71cdbe9 | 307 | else |
Sergunb | 0:8918a71cdbe9 | 308 | { |
Sergunb | 0:8918a71cdbe9 | 309 | //Wait for data to be available for reading |
Sergunb | 0:8918a71cdbe9 | 310 | context->eventDesc[2 * i].socket = connection->controlSocket; |
Sergunb | 0:8918a71cdbe9 | 311 | context->eventDesc[2 * i].eventMask = SOCKET_EVENT_RX_READY; |
Sergunb | 0:8918a71cdbe9 | 312 | } |
Sergunb | 0:8918a71cdbe9 | 313 | } |
Sergunb | 0:8918a71cdbe9 | 314 | |
Sergunb | 0:8918a71cdbe9 | 315 | //Ensure the data connection is opened |
Sergunb | 0:8918a71cdbe9 | 316 | if(connection->dataSocket != NULL) |
Sergunb | 0:8918a71cdbe9 | 317 | { |
Sergunb | 0:8918a71cdbe9 | 318 | //Check the state of the data connection |
Sergunb | 0:8918a71cdbe9 | 319 | if(connection->dataState == FTP_DATA_STATE_LISTEN || |
Sergunb | 0:8918a71cdbe9 | 320 | connection->dataState == FTP_DATA_STATE_RECEIVE) |
Sergunb | 0:8918a71cdbe9 | 321 | { |
Sergunb | 0:8918a71cdbe9 | 322 | //Wait for data to be available for reading |
Sergunb | 0:8918a71cdbe9 | 323 | context->eventDesc[2 * i + 1].socket = connection->dataSocket; |
Sergunb | 0:8918a71cdbe9 | 324 | context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_RX_READY; |
Sergunb | 0:8918a71cdbe9 | 325 | } |
Sergunb | 0:8918a71cdbe9 | 326 | else if(connection->dataState == FTP_DATA_STATE_SEND) |
Sergunb | 0:8918a71cdbe9 | 327 | { |
Sergunb | 0:8918a71cdbe9 | 328 | //Wait until there is more room in the send buffer |
Sergunb | 0:8918a71cdbe9 | 329 | context->eventDesc[2 * i + 1].socket = connection->dataSocket; |
Sergunb | 0:8918a71cdbe9 | 330 | context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_TX_READY; |
Sergunb | 0:8918a71cdbe9 | 331 | } |
Sergunb | 0:8918a71cdbe9 | 332 | |
Sergunb | 0:8918a71cdbe9 | 333 | else if(connection->dataState == FTP_DATA_STATE_WAIT_ACK) |
Sergunb | 0:8918a71cdbe9 | 334 | { |
Sergunb | 0:8918a71cdbe9 | 335 | //Wait for all the data to be transmitted and acknowledged |
Sergunb | 0:8918a71cdbe9 | 336 | context->eventDesc[2 * i + 1].socket = connection->dataSocket; |
Sergunb | 0:8918a71cdbe9 | 337 | context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_TX_ACKED; |
Sergunb | 0:8918a71cdbe9 | 338 | } |
Sergunb | 0:8918a71cdbe9 | 339 | else if(connection->dataState == FTP_DATA_STATE_SHUTDOWN_TX) |
Sergunb | 0:8918a71cdbe9 | 340 | { |
Sergunb | 0:8918a71cdbe9 | 341 | //Wait for the FIN to be acknowledged |
Sergunb | 0:8918a71cdbe9 | 342 | context->eventDesc[2 * i + 1].socket = connection->dataSocket; |
Sergunb | 0:8918a71cdbe9 | 343 | context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_TX_SHUTDOWN; |
Sergunb | 0:8918a71cdbe9 | 344 | } |
Sergunb | 0:8918a71cdbe9 | 345 | else if(connection->dataState == FTP_DATA_STATE_SHUTDOWN_RX) |
Sergunb | 0:8918a71cdbe9 | 346 | { |
Sergunb | 0:8918a71cdbe9 | 347 | //Wait for a FIN to be received |
Sergunb | 0:8918a71cdbe9 | 348 | context->eventDesc[2 * i + 1].socket = connection->dataSocket; |
Sergunb | 0:8918a71cdbe9 | 349 | context->eventDesc[2 * i + 1].eventMask = SOCKET_EVENT_RX_SHUTDOWN; |
Sergunb | 0:8918a71cdbe9 | 350 | } |
Sergunb | 0:8918a71cdbe9 | 351 | } |
Sergunb | 0:8918a71cdbe9 | 352 | } |
Sergunb | 0:8918a71cdbe9 | 353 | } |
Sergunb | 0:8918a71cdbe9 | 354 | |
Sergunb | 0:8918a71cdbe9 | 355 | //Accept connection request events |
Sergunb | 0:8918a71cdbe9 | 356 | context->eventDesc[2 * i].socket = context->socket; |
Sergunb | 0:8918a71cdbe9 | 357 | context->eventDesc[2 * i].eventMask = SOCKET_EVENT_RX_READY; |
Sergunb | 0:8918a71cdbe9 | 358 | |
Sergunb | 0:8918a71cdbe9 | 359 | //Wait for one of the set of sockets to become ready to perform I/O |
Sergunb | 0:8918a71cdbe9 | 360 | error = socketPoll(context->eventDesc, 2 * FTP_SERVER_MAX_CONNECTIONS + 1, |
Sergunb | 0:8918a71cdbe9 | 361 | &context->event, FTP_SERVER_SOCKET_POLLING_TIMEOUT); |
Sergunb | 0:8918a71cdbe9 | 362 | |
Sergunb | 0:8918a71cdbe9 | 363 | //Get current time |
Sergunb | 0:8918a71cdbe9 | 364 | time = osGetSystemTime(); |
Sergunb | 0:8918a71cdbe9 | 365 | |
Sergunb | 0:8918a71cdbe9 | 366 | //Verify status code |
Sergunb | 0:8918a71cdbe9 | 367 | if(!error) |
Sergunb | 0:8918a71cdbe9 | 368 | { |
Sergunb | 0:8918a71cdbe9 | 369 | //Event-driven processing |
Sergunb | 0:8918a71cdbe9 | 370 | for(i = 0; i < FTP_SERVER_MAX_CONNECTIONS; i++) |
Sergunb | 0:8918a71cdbe9 | 371 | { |
Sergunb | 0:8918a71cdbe9 | 372 | //Point to the structure describing the current connection |
Sergunb | 0:8918a71cdbe9 | 373 | connection = context->connection[i]; |
Sergunb | 0:8918a71cdbe9 | 374 | |
Sergunb | 0:8918a71cdbe9 | 375 | //Make sure the control connection is still active |
Sergunb | 0:8918a71cdbe9 | 376 | if(connection != NULL && connection->controlSocket != NULL) |
Sergunb | 0:8918a71cdbe9 | 377 | { |
Sergunb | 0:8918a71cdbe9 | 378 | //Check whether the control socket is to ready to perform I/O |
Sergunb | 0:8918a71cdbe9 | 379 | if(context->eventDesc[2 * i].eventFlags) |
Sergunb | 0:8918a71cdbe9 | 380 | { |
Sergunb | 0:8918a71cdbe9 | 381 | //Update time stamp |
Sergunb | 0:8918a71cdbe9 | 382 | connection->timestamp = time; |
Sergunb | 0:8918a71cdbe9 | 383 | //Control connection event handler |
Sergunb | 0:8918a71cdbe9 | 384 | ftpServerControlEventHandler(context, connection, |
Sergunb | 0:8918a71cdbe9 | 385 | context->eventDesc[2 * i].eventFlags); |
Sergunb | 0:8918a71cdbe9 | 386 | } |
Sergunb | 0:8918a71cdbe9 | 387 | } |
Sergunb | 0:8918a71cdbe9 | 388 | |
Sergunb | 0:8918a71cdbe9 | 389 | //The connection may have been closed... |
Sergunb | 0:8918a71cdbe9 | 390 | connection = context->connection[i]; |
Sergunb | 0:8918a71cdbe9 | 391 | |
Sergunb | 0:8918a71cdbe9 | 392 | //Make sure the data connection is still active |
Sergunb | 0:8918a71cdbe9 | 393 | if(connection != NULL && connection->dataSocket != NULL) |
Sergunb | 0:8918a71cdbe9 | 394 | { |
Sergunb | 0:8918a71cdbe9 | 395 | //Check whether the data socket to is ready to perform I/O |
Sergunb | 0:8918a71cdbe9 | 396 | if(context->eventDesc[2 * i + 1].eventFlags) |
Sergunb | 0:8918a71cdbe9 | 397 | { |
Sergunb | 0:8918a71cdbe9 | 398 | //Update time stamp |
Sergunb | 0:8918a71cdbe9 | 399 | connection->timestamp = time; |
Sergunb | 0:8918a71cdbe9 | 400 | //Data connection event handler |
Sergunb | 0:8918a71cdbe9 | 401 | ftpServerDataEventHandler(context, connection, |
Sergunb | 0:8918a71cdbe9 | 402 | context->eventDesc[2 * i + 1].eventFlags); |
Sergunb | 0:8918a71cdbe9 | 403 | } |
Sergunb | 0:8918a71cdbe9 | 404 | } |
Sergunb | 0:8918a71cdbe9 | 405 | } |
Sergunb | 0:8918a71cdbe9 | 406 | |
Sergunb | 0:8918a71cdbe9 | 407 | //Check the state of the listening socket |
Sergunb | 0:8918a71cdbe9 | 408 | if(context->eventDesc[2 * i].eventFlags & SOCKET_EVENT_RX_READY) |
Sergunb | 0:8918a71cdbe9 | 409 | { |
Sergunb | 0:8918a71cdbe9 | 410 | //Process incoming connection request |
Sergunb | 0:8918a71cdbe9 | 411 | connection = ftpServerAcceptControlConnection(context); |
Sergunb | 0:8918a71cdbe9 | 412 | //Initialize time stamp |
Sergunb | 0:8918a71cdbe9 | 413 | if(connection != NULL) |
Sergunb | 0:8918a71cdbe9 | 414 | connection->timestamp = time; |
Sergunb | 0:8918a71cdbe9 | 415 | } |
Sergunb | 0:8918a71cdbe9 | 416 | } |
Sergunb | 0:8918a71cdbe9 | 417 | |
Sergunb | 0:8918a71cdbe9 | 418 | //Manage timeouts |
Sergunb | 0:8918a71cdbe9 | 419 | for(i = 0; i < FTP_SERVER_MAX_CONNECTIONS; i++) |
Sergunb | 0:8918a71cdbe9 | 420 | { |
Sergunb | 0:8918a71cdbe9 | 421 | //Point to the structure describing the current connection |
Sergunb | 0:8918a71cdbe9 | 422 | connection = context->connection[i]; |
Sergunb | 0:8918a71cdbe9 | 423 | |
Sergunb | 0:8918a71cdbe9 | 424 | //Any client connected? |
Sergunb | 0:8918a71cdbe9 | 425 | if(connection != NULL) |
Sergunb | 0:8918a71cdbe9 | 426 | { |
Sergunb | 0:8918a71cdbe9 | 427 | //Disconnect inactive client after idle timeout |
Sergunb | 0:8918a71cdbe9 | 428 | if((time - connection->timestamp) >= FTP_SERVER_TIMEOUT) |
Sergunb | 0:8918a71cdbe9 | 429 | { |
Sergunb | 0:8918a71cdbe9 | 430 | //Debug message |
Sergunb | 0:8918a71cdbe9 | 431 | TRACE_INFO("FTP server: Closing inactive connection...\r\n"); |
Sergunb | 0:8918a71cdbe9 | 432 | //Close connection with the client |
Sergunb | 0:8918a71cdbe9 | 433 | ftpServerCloseConnection(context, connection); |
Sergunb | 0:8918a71cdbe9 | 434 | } |
Sergunb | 0:8918a71cdbe9 | 435 | } |
Sergunb | 0:8918a71cdbe9 | 436 | } |
Sergunb | 0:8918a71cdbe9 | 437 | #if (NET_RTOS_SUPPORT == ENABLED) |
Sergunb | 0:8918a71cdbe9 | 438 | } |
Sergunb | 0:8918a71cdbe9 | 439 | #endif |
Sergunb | 0:8918a71cdbe9 | 440 | } |
Sergunb | 0:8918a71cdbe9 | 441 | |
Sergunb | 0:8918a71cdbe9 | 442 | #endif |
Sergunb | 0:8918a71cdbe9 | 443 |