ftp_server_control.c
Go to the documentation of this file.
1 /**
2  * @file ftp_server_control.c
3  * @brief FTP control connection
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 1.9.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL FTP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ftp/ftp_server.h"
37 #include "ftp/ftp_server_control.h"
39 #include "ftp/ftp_server_misc.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (FTP_SERVER_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Register control connection events
48  * @param[in] connection Pointer to the client connection
49  * @param[in] eventDesc Event to be registered
50  **/
51 
53  SocketEventDesc *eventDesc)
54 {
55  //Check the state of the control connection
56  if(connection->controlChannel.state == FTP_CHANNEL_STATE_CONNECT_TLS)
57  {
58 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
59  //Any data pending in the send buffer?
60  if(tlsIsTxReady(connection->controlChannel.tlsContext))
61  {
62  //Wait until there is more room in the send buffer
63  eventDesc->socket = connection->controlChannel.socket;
64  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
65  }
66  else
67  {
68  //Wait for data to be available for reading
69  eventDesc->socket = connection->controlChannel.socket;
70  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
71  }
72 #endif
73  }
74  else if(connection->responseLen > 0)
75  {
76  //Wait until there is more room in the send buffer
77  eventDesc->socket = connection->controlChannel.socket;
78  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
79  }
80  else if(connection->controlChannel.state == FTP_CHANNEL_STATE_AUTH_TLS_2)
81  {
82 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
83  //Any data pending in the send buffer?
84  if(tlsIsTxReady(connection->controlChannel.tlsContext))
85  {
86  //Wait until there is more room in the send buffer
87  eventDesc->socket = connection->controlChannel.socket;
88  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
89  }
90  else
91  {
92  //Wait for data to be available for reading
93  eventDesc->socket = connection->controlChannel.socket;
94  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
95  }
96 #endif
97  }
98  else if(connection->controlChannel.state == FTP_CHANNEL_STATE_WAIT_ACK)
99  {
100  //Wait for all the data to be transmitted and acknowledged
101  eventDesc->socket = connection->controlChannel.socket;
102  eventDesc->eventMask = SOCKET_EVENT_TX_ACKED;
103  }
104  else if(connection->controlChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_TX)
105  {
106  //Wait for the FIN to be acknowledged
107  eventDesc->socket = connection->controlChannel.socket;
108  eventDesc->eventMask = SOCKET_EVENT_TX_SHUTDOWN;
109  }
110  else if(connection->controlChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_RX)
111  {
112  //Wait for a FIN to be received
113  eventDesc->socket = connection->controlChannel.socket;
114  eventDesc->eventMask = SOCKET_EVENT_RX_SHUTDOWN;
115  }
116  else
117  {
118 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
119  if(connection->controlChannel.tlsContext != NULL &&
120  tlsIsRxReady(connection->controlChannel.tlsContext))
121  {
122  //No need to poll the underlying socket for incoming traffic
123  eventDesc->eventFlags = SOCKET_EVENT_RX_READY;
124  }
125  else
126 #endif
127  {
128  //Wait for data to be available for reading
129  eventDesc->socket = connection->controlChannel.socket;
130  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
131  }
132  }
133 }
134 
135 
136 /**
137  * @brief Control connection event handler
138  * @param[in] connection Pointer to the client connection
139  * @param[in] eventFlags Event to be processed
140  **/
141 
143  uint_t eventFlags)
144 {
145  error_t error;
146  size_t n;
147  FtpServerContext *context;
148 
149  //Point to the FTP server context
150  context = connection->context;
151 
152 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
153  //TLS session establishment in progress?
154  if(connection->controlChannel.state == FTP_CHANNEL_STATE_CONNECT_TLS ||
155  connection->controlChannel.state == FTP_CHANNEL_STATE_AUTH_TLS_2)
156  {
157  //Perform TLS handshake
158  error = ftpServerEstablishSecureChannel(&connection->controlChannel);
159 
160  //Check status code
161  if(error == NO_ERROR)
162  {
163  //Update the state of the control connection
164  connection->controlChannel.state = FTP_CHANNEL_STATE_IDLE;
165  }
166  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
167  {
168  }
169  else
170  {
171  //Close connection with the client
172  ftpServerCloseConnection(connection);
173  }
174  }
175  else
176 #endif
177  {
178  //Check event flags
179  if(eventFlags == SOCKET_EVENT_TX_READY)
180  {
181  //Transmit data
182  error = ftpServerWriteChannel(&connection->controlChannel,
183  connection->response + connection->responsePos,
184  connection->responseLen, &n, 0);
185 
186  //Check status code
187  if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
188  {
189  //Advance data pointer
190  connection->responsePos += n;
191  //Number of bytes still available in the response buffer
192  connection->responseLen -= n;
193 
194  //Check whether the AUTH response has been transmitted
195  if(connection->responseLen == 0 &&
196  connection->controlChannel.state == FTP_CHANNEL_STATE_AUTH_TLS_1)
197  {
198  //TLS initialization
199  error = ftpServerOpenSecureChannel(context,
200  &connection->controlChannel, FTP_SERVER_TLS_TX_BUFFER_SIZE,
202 
203  //Check status code
204  if(!error)
205  {
206  //Perform TLS handshake
207  connection->controlChannel.state = FTP_CHANNEL_STATE_AUTH_TLS_2;
208  }
209  else
210  {
211  //Close connection with the client
212  ftpServerCloseConnection(connection);
213  }
214  }
215  }
216  else
217  {
218  //Close connection with the client
219  ftpServerCloseConnection(connection);
220  }
221  }
222  else if(eventFlags == SOCKET_EVENT_RX_READY)
223  {
224  //Receive data
225  error = ftpServerReadChannel(&connection->controlChannel,
226  connection->command + connection->commandLen,
227  FTP_SERVER_MAX_LINE_LEN - connection->commandLen, &n, 0);
228 
229  //Check status code
230  if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
231  {
232  //Number of bytes available in the command buffer
233  connection->commandLen += n;
234  //Process incoming command
235  ftpServerProcessCommand(connection);
236  }
237  else if(error == ERROR_END_OF_STREAM)
238  {
239  //Gracefully disconnect from the remote host
240  connection->controlChannel.state = FTP_CHANNEL_STATE_WAIT_ACK;
241  }
242  else
243  {
244  //Close connection with the client
245  ftpServerCloseConnection(connection);
246  }
247  }
248  else if(eventFlags == SOCKET_EVENT_TX_ACKED)
249  {
250  //Disable transmission
251  socketShutdown(connection->controlChannel.socket, SOCKET_SD_SEND);
252  //Next state
253  connection->controlChannel.state = FTP_CHANNEL_STATE_SHUTDOWN_TX;
254  }
255  else if(eventFlags == SOCKET_EVENT_TX_SHUTDOWN)
256  {
257  //Disable reception
258  socketShutdown(connection->controlChannel.socket, SOCKET_SD_RECEIVE);
259  //Next state
260  connection->controlChannel.state = FTP_CHANNEL_STATE_SHUTDOWN_RX;
261  }
262  else if(eventFlags == SOCKET_EVENT_RX_SHUTDOWN)
263  {
264  //Properly close connection
265  ftpServerCloseConnection(connection);
266  }
267  }
268 }
269 
270 
271 /**
272  * @brief Accept control connection
273  * @param[in] context Pointer to the FTP server context
274  **/
275 
277 {
278  error_t error;
279  uint_t i;
280  Socket *socket;
281  IpAddr clientIpAddr;
282  uint16_t clientPort;
283  FtpClientConnection *connection;
284 
285  //Accept incoming connection
286  socket = socketAccept(context->socket, &clientIpAddr, &clientPort);
287 
288  //Make sure the socket handle is valid
289  if(socket != NULL)
290  {
291  //Force the socket to operate in non-blocking mode
293 
294  //Initialize pointer
295  connection = NULL;
296 
297  //Loop through the connection table
298  for(i = 0; i < context->settings.maxConnections; i++)
299  {
300  //Check the state of the current connection
301  if(context->connections[i].controlChannel.state == FTP_CHANNEL_STATE_CLOSED &&
302  context->connections[i].dataChannel.state == FTP_CHANNEL_STATE_CLOSED)
303  {
304  //The current entry is free
305  connection = &context->connections[i];
306  break;
307  }
308  }
309 
310  //If the connection table runs out of space, then the client's connection
311  //request is rejected
312  if(connection != NULL)
313  {
314  //Clear the structure describing the connection
315  memset(connection, 0, sizeof(FtpClientConnection));
316 
317  //Attach FTP server context
318  connection->context = context;
319  //Underlying network interface
320  connection->interface = socketGetInterface(socket);
321  //Save socket handle
322  connection->controlChannel.socket = socket;
323  //Initialize time stamp
324  connection->timestamp = osGetSystemTime();
325  //Set home directory
326  strcpy(connection->homeDir, context->settings.rootDir);
327  //Set current directory
328  strcpy(connection->currentDir, context->settings.rootDir);
329  //Format greeting message
330  strcpy(connection->response, "220 Service ready for new user\r\n");
331 
332  //Any registered callback?
333  if(context->settings.connectCallback != NULL)
334  {
335  //Invoke user callback function
336  error = context->settings.connectCallback(connection, &clientIpAddr,
337  clientPort);
338  }
339  else
340  {
341  //No callback function defined
342  error = NO_ERROR;
343  }
344 
345  //Check status code
346  if(!error)
347  {
348  //Debug message
349  TRACE_INFO("FTP Server: Control connection established with client %s port %"
350  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
351 
352  //Debug message
353  TRACE_DEBUG("FTP server: %s", connection->response);
354 
355  //Number of bytes in the response buffer
356  connection->responseLen = strlen(connection->response);
357  connection->responsePos = 0;
358 
359  //Implicit TLS mode supported by the server?
360  if((context->settings.mode & FTP_SERVER_MODE_IMPLICIT_TLS) != 0)
361  {
362  //TLS initialization
363  error = ftpServerOpenSecureChannel(context,
364  &connection->controlChannel, FTP_SERVER_TLS_TX_BUFFER_SIZE,
366 
367  //Check status code
368  if(!error)
369  {
370  //Perform TLS handshake
371  connection->controlChannel.state = FTP_CHANNEL_STATE_CONNECT_TLS;
372  }
373  else
374  {
375  //Close connection with the client
376  ftpServerCloseConnection(connection);
377  }
378  }
379  else
380  {
381  //Enter default state
382  connection->controlChannel.state = FTP_CHANNEL_STATE_IDLE;
383  }
384  }
385  else
386  {
387  //The connection attempt has been refused
388  memset(connection, 0, sizeof(FtpClientConnection));
389  }
390  }
391  else
392  {
393  //The connection table runs out of space
394  error = ERROR_OUT_OF_RESOURCES;
395  }
396 
397  //Check status code
398  if(error)
399  {
400  //Debug message
401  TRACE_INFO("FTP Server: Connection refused with client %s port %"
402  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
403 
404  //The FTP server cannot accept the incoming connection request
406  }
407  }
408 }
409 
410 
411 /**
412  * @brief Close control connection
413  * @param[in] connection Pointer to the client connection
414  **/
415 
417 {
418  IpAddr clientIpAddr;
419  uint16_t clientPort;
420  FtpServerContext *context;
421 
422  //Point to the FTP server context
423  context = connection->context;
424 
425  //Check whether the control connection is active
426  if(connection->controlChannel.socket != NULL)
427  {
428  //Retrieve the address of the peer to which a socket is connected
429  socketGetRemoteAddr(connection->controlChannel.socket, &clientIpAddr,
430  &clientPort);
431 
432  //Debug message
433  TRACE_INFO("FTP server: Closing control connection with client %s port %"
434  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
435 
436  //Any registered callback?
437  if(context->settings.disconnectCallback != NULL)
438  {
439  //Invoke user callback function
440  context->settings.disconnectCallback(connection, &clientIpAddr,
441  clientPort);
442  }
443 
444 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
445  //Valid TLS context?
446  if(connection->controlChannel.tlsContext != NULL)
447  {
448  //Release TLS context
449  tlsFree(connection->controlChannel.tlsContext);
450  connection->controlChannel.tlsContext = NULL;
451  }
452 #endif
453 
454  //Valid socket?
455  if(connection->controlChannel.socket != NULL)
456  {
457  //Close control connection
458  socketClose(connection->controlChannel.socket);
459  connection->controlChannel.socket = NULL;
460  }
461 
462  //Mark the connection as closed
463  connection->controlChannel.state = FTP_CHANNEL_STATE_CLOSED;
464  }
465 }
466 
467 #endif
#define FtpServerContext
Definition: ftp_server.h:203
FTP server (command processing)
IP network address.
Definition: ip.h:71
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:822
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:726
Transport protocol abstraction layer.
error_t socketGetRemoteAddr(Socket *socket, IpAddr *remoteIpAddr, uint16_t *remotePort)
Retrieve the address of the peer to which a socket is connected.
Definition: socket.c:755
Helper functions for FTP server.
Structure describing socket events.
Definition: socket.h:307
error_t
Error codes.
Definition: error.h:42
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:108
void ftpServerAcceptControlChannel(FtpServerContext *context)
Accept control connection.
bool_t tlsIsTxReady(TlsContext *context)
Check whether some data is ready for transmission.
Definition: tls.c:2034
void ftpServerCloseConnection(FtpClientConnection *connection)
Close client connection properly.
error_t ftpServerEstablishSecureChannel(FtpServerChannel *channel)
Establish secure connection.
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:785
#define TRACE_INFO(...)
Definition: debug.h:94
error_t ftpServerOpenSecureChannel(FtpServerContext *context, FtpServerChannel *channel, size_t txBufferSize, size_t rxBufferSize)
Open secure connection.
uint_t eventFlags
Returned events.
Definition: socket.h:311
Socket * socketAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a socket.
Definition: socket.c:481
#define FTP_SERVER_TLS_TX_BUFFER_SIZE
Definition: ftp_server.h:151
bool_t tlsIsRxReady(TlsContext *context)
Check whether some data is available in the receive buffer.
Definition: tls.c:2067
#define TRACE_DEBUG(...)
Definition: debug.h:106
uint8_t n
void ftpServerProcessCommand(FtpClientConnection *connection)
FTP command processing.
#define Socket
Definition: socket.h:36
NetInterface * socketGetInterface(Socket *socket)
Retrieve the underlying interface.
Definition: socket.c:332
void ftpServerCloseControlChannel(FtpClientConnection *connection)
Close control connection.
void ftpServerRegisterControlChannelEvents(FtpClientConnection *connection, SocketEventDesc *eventDesc)
Register control connection events.
error_t ftpServerReadChannel(FtpServerChannel *channel, void *data, size_t size, size_t *received, uint_t flags)
Receive data using the relevant transport protocol.
FTP server (File Transfer Protocol)
#define FTP_SERVER_MIN_TLS_RX_BUFFER_SIZE
Definition: ftp_server.h:158
#define FTP_SERVER_MAX_LINE_LEN
Definition: ftp_server.h:95
#define FtpClientConnection
Definition: ftp_server.h:207
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2272
error_t ftpServerWriteChannel(FtpServerChannel *channel, const void *data, size_t length, size_t *written, uint_t flags)
Send data using the relevant transport protocol.
Socket * socket
Handle to a socket to monitor.
Definition: socket.h:309
unsigned int uint_t
Definition: compiler_port.h:45
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:219
FTP control connection.
uint_t eventMask
Requested events.
Definition: socket.h:310
Success.
Definition: error.h:44
Debugging facilities.
systime_t osGetSystemTime(void)
Retrieve system time.
void ftpServerProcessControlChannelEvents(FtpClientConnection *connection, uint_t eventFlags)
Control connection event handler.