ftp_server_data.c
Go to the documentation of this file.
1 /**
2  * @file ftp_server_data.c
3  * @brief FTP data connection
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 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 2.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL FTP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "ftp/ftp_server.h"
37 #include "ftp/ftp_server_data.h"
39 #include "ftp/ftp_server_misc.h"
40 #include "path.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (FTP_SERVER_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Register data connection events
49  * @param[in] connection Pointer to the client connection
50  * @param[in] eventDesc Socket events to be registered
51  **/
52 
54  SocketEventDesc *eventDesc)
55 {
56  //Check the state of the data connection
57  if(connection->dataChannel.state == FTP_CHANNEL_STATE_LISTEN)
58  {
59  //Wait for data to be available for reading
60  eventDesc->socket = connection->dataChannel.socket;
61  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
62  }
63  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_CONNECT_TLS)
64  {
65 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
66  //Any data pending in the send buffer?
67  if(tlsIsTxReady(connection->dataChannel.tlsContext))
68  {
69  //Wait until there is more room in the send buffer
70  eventDesc->socket = connection->dataChannel.socket;
71  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
72  }
73  else
74  {
75  //Wait for data to be available for reading
76  eventDesc->socket = connection->dataChannel.socket;
77  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
78  }
79 #endif
80  }
81  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_RECEIVE)
82  {
83 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
84  //Any data pending in the receive buffer?
85  if(connection->dataChannel.tlsContext != NULL &&
86  tlsIsRxReady(connection->dataChannel.tlsContext))
87  {
88  //No need to poll the underlying socket for incoming traffic
89  eventDesc->eventFlags = SOCKET_EVENT_RX_READY;
90  }
91  else
92 #endif
93  {
94  //Wait for data to be available for reading
95  eventDesc->socket = connection->dataChannel.socket;
96  eventDesc->eventMask = SOCKET_EVENT_RX_READY;
97  }
98  }
99  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SEND)
100  {
101  //Wait until there is more room in the send buffer
102  eventDesc->socket = connection->dataChannel.socket;
103  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
104  }
105  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_TLS)
106  {
107  //Wait until there is more room in the send buffer
108  eventDesc->socket = connection->dataChannel.socket;
109  eventDesc->eventMask = SOCKET_EVENT_TX_READY;
110  }
111  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_WAIT_ACK)
112  {
113  //Wait for all the data to be transmitted and acknowledged
114  eventDesc->socket = connection->dataChannel.socket;
115  eventDesc->eventMask = SOCKET_EVENT_TX_ACKED;
116  }
117  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_TX)
118  {
119  //Wait for the FIN to be acknowledged
120  eventDesc->socket = connection->dataChannel.socket;
121  eventDesc->eventMask = SOCKET_EVENT_TX_SHUTDOWN;
122  }
123  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_RX)
124  {
125  //Wait for a FIN to be received
126  eventDesc->socket = connection->dataChannel.socket;
127  eventDesc->eventMask = SOCKET_EVENT_RX_SHUTDOWN;
128  }
129 }
130 
131 
132 /**
133  * @brief Data connection event handler
134  * @param[in] connection Pointer to the client connection
135  * @param[in] eventFlags Event to be processed
136  **/
137 
139  uint_t eventFlags)
140 {
141  //Check current state
142  if(connection->dataChannel.state == FTP_CHANNEL_STATE_LISTEN)
143  {
144  //Accept data connection
145  ftpServerAcceptDataChannel(connection);
146  }
147 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
148  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_CONNECT_TLS)
149  {
150  error_t error;
151 
152  //Perform TLS handshake
153  error = ftpServerEstablishSecureChannel(&connection->dataChannel);
154 
155  //Check status code
156  if(error == NO_ERROR)
157  {
158  //Update the state of the data connection
159  if(connection->controlChannel.state == FTP_CHANNEL_STATE_LIST ||
160  connection->controlChannel.state == FTP_CHANNEL_STATE_NLST ||
161  connection->controlChannel.state == FTP_CHANNEL_STATE_RETR)
162  {
163  //Prepare to send data
164  connection->dataChannel.state = FTP_CHANNEL_STATE_SEND;
165  }
166  else if(connection->controlChannel.state == FTP_CHANNEL_STATE_STOR ||
167  connection->controlChannel.state == FTP_CHANNEL_STATE_APPE)
168  {
169  //Prepare to receive data
170  connection->dataChannel.state = FTP_CHANNEL_STATE_RECEIVE;
171  }
172  else
173  {
174  //Data transfer direction is unknown...
175  connection->dataChannel.state = FTP_CHANNEL_STATE_IDLE;
176  }
177  }
178  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
179  {
180  }
181  else
182  {
183  //Close the data connection
184  ftpServerCloseDataChannel(connection);
185 
186  //Release previously allocated resources
187  fsCloseFile(connection->file);
188  connection->file = NULL;
189 
190  //Back to idle state
191  connection->controlChannel.state = FTP_CHANNEL_STATE_IDLE;
192 
193  //Transfer status
194  osStrcpy(connection->response, "451 Transfer aborted\r\n");
195  //Debug message
196  TRACE_DEBUG("FTP server: %s", connection->response);
197 
198  //Number of bytes in the response buffer
199  connection->responseLen = osStrlen(connection->response);
200  connection->responsePos = 0;
201  }
202  }
203 #endif
204  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SEND)
205  {
206  //Send more data to the remote host
207  ftpServerWriteDataChannel(connection);
208  }
209  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_RECEIVE)
210  {
211  //Process incoming data
212  ftpServerReadDataChannel(connection);
213  }
214 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
215  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_TLS)
216  {
217  error_t error;
218 
219  //Gracefully close TLS session
220  error = tlsShutdown(connection->dataChannel.tlsContext);
221 
222  //Check status code
223  if(error != ERROR_WOULD_BLOCK && error != ERROR_TIMEOUT)
224  {
225  //Wait for all the data to be transmitted and acknowledged
226  connection->dataChannel.state = FTP_CHANNEL_STATE_WAIT_ACK;
227  }
228  }
229 #endif
230  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_WAIT_ACK)
231  {
232  //Disable transmission
233  socketShutdown(connection->dataChannel.socket, SOCKET_SD_SEND);
234  //Next state
235  connection->dataChannel.state = FTP_CHANNEL_STATE_SHUTDOWN_TX;
236  }
237  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_TX)
238  {
239  //Disable reception
240  socketShutdown(connection->dataChannel.socket, SOCKET_SD_RECEIVE);
241  //Next state
242  connection->dataChannel.state = FTP_CHANNEL_STATE_SHUTDOWN_RX;
243  }
244  else if(connection->dataChannel.state == FTP_CHANNEL_STATE_SHUTDOWN_RX)
245  {
246  //Close the data connection
247  ftpServerCloseDataChannel(connection);
248 
249  //Back to idle state
250  connection->controlChannel.state = FTP_CHANNEL_STATE_IDLE;
251 
252  //Transfer status
253  osStrcpy(connection->response, "226 Transfer complete\r\n");
254  //Debug message
255  TRACE_DEBUG("FTP server: %s", connection->response);
256 
257  //Number of bytes in the response buffer
258  connection->responseLen = osStrlen(connection->response);
259  connection->responsePos = 0;
260  }
261 }
262 
263 
264 /**
265  * @brief Open data connection
266  * @param[in] connection Pointer to the client connection
267  * @return Error code
268  **/
269 
271 {
272  error_t error;
273  FtpServerContext *context;
274 
275  //Point to the FTP server context
276  context = connection->context;
277 
278  //Release previously allocated resources
279  ftpServerCloseDataChannel(connection);
280 
281  //No port specified?
282  if(!connection->remotePort)
283  return ERROR_FAILURE;
284 
285  //Debug message
286  TRACE_INFO("FTP server: Opening data connection with client %s port %" PRIu16 "...\r\n",
287  ipAddrToString(&connection->remoteIpAddr, NULL), connection->remotePort);
288 
289  //Open data socket
290  connection->dataChannel.socket = socketOpen(SOCKET_TYPE_STREAM,
292  //Failed to open socket?
293  if(!connection->dataChannel.socket)
294  return ERROR_OPEN_FAILED;
295 
296  //Start of exception handling block
297  do
298  {
299  //Force the socket to operate in non-blocking mode
300  error = socketSetTimeout(connection->dataChannel.socket, 0);
301  //Any error to report?
302  if(error)
303  break;
304 
305  //Adjust the size of the TX buffer
306  error = socketSetTxBufferSize(connection->dataChannel.socket,
308  //Any error to report?
309  if(error)
310  break;
311 
312  //Adjust the size of the RX buffer
313  error = socketSetRxBufferSize(connection->dataChannel.socket,
315  //Any error to report?
316  if(error)
317  break;
318 
319  //Associate the socket with the relevant interface
320  error = socketBindToInterface(connection->dataChannel.socket,
321  connection->interface);
322  //Unable to bind the socket to the desired interface?
323  if(error)
324  break;
325 
326  //The server initiates the data connection from port 20
327  error = socketBind(connection->dataChannel.socket, &IP_ADDR_ANY,
328  context->settings.dataPort);
329  //Any error to report?
330  if(error)
331  break;
332 
333  //Establish data connection
334  error = socketConnect(connection->dataChannel.socket,
335  &connection->remoteIpAddr, connection->remotePort);
336  //Any error to report?
337  if(error != NO_ERROR && error != ERROR_TIMEOUT)
338  break;
339 
340  //Connection is being established
341  error = NO_ERROR;
342 
343  //End of exception handling block
344  } while(0);
345 
346  //Any error to report?
347  if(error)
348  {
349  //Clean up side effects
350  ftpServerCloseDataChannel(connection);
351  //Exit immediately
352  return error;
353  }
354 
355  //Successful processing
356  return NO_ERROR;
357 }
358 
359 
360 /**
361  * @brief Accept data connection
362  * @param[in] connection Pointer to the client connection
363  **/
364 
366 {
367  error_t error;
368  Socket *socket;
369  IpAddr clientIpAddr;
370  uint16_t clientPort;
371 
372  //Accept incoming connection
373  socket = socketAccept(connection->dataChannel.socket, &clientIpAddr,
374  &clientPort);
375  //Failure detected?
376  if(socket == NULL)
377  return;
378 
379  //Debug message
380  TRACE_INFO("FTP server: Data connection established with client %s port %" PRIu16 "...\r\n",
381  ipAddrToString(&clientIpAddr, NULL), clientPort);
382 
383  //Close the listening socket
384  socketClose(connection->dataChannel.socket);
385  //Save socket handle
386  connection->dataChannel.socket = socket;
387 
388  //Force the socket to operate in non-blocking mode
389  error = socketSetTimeout(connection->dataChannel.socket, 0);
390  //Any error to report?
391  if(error)
392  {
393  //Clean up side effects
394  socketClose(connection->dataChannel.socket);
395  //Exit immediately
396  return;
397  }
398 
399 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
400  //TLS-secured connection?
401  if(connection->controlChannel.tlsContext != NULL)
402  {
403  //Check data transfer direction
404  if(connection->controlChannel.state == FTP_CHANNEL_STATE_STOR ||
405  connection->controlChannel.state == FTP_CHANNEL_STATE_APPE)
406  {
407  //TLS initialization
408  error = ftpServerOpenSecureChannel(connection->context,
409  &connection->dataChannel, FTP_SERVER_TLS_TX_BUFFER_SIZE,
411  }
412  else
413  {
414  //TLS initialization
415  error = ftpServerOpenSecureChannel(connection->context,
416  &connection->dataChannel, FTP_SERVER_TLS_TX_BUFFER_SIZE,
418  }
419 
420  //Perform TLS handshake
421  connection->dataChannel.state = FTP_CHANNEL_STATE_CONNECT_TLS;
422  }
423  else
424 #endif
425  {
426  //Check current state
427  if(connection->controlChannel.state == FTP_CHANNEL_STATE_LIST ||
428  connection->controlChannel.state == FTP_CHANNEL_STATE_NLST ||
429  connection->controlChannel.state == FTP_CHANNEL_STATE_RETR)
430  {
431  //Prepare to send data
432  connection->dataChannel.state = FTP_CHANNEL_STATE_SEND;
433  }
434  else if(connection->controlChannel.state == FTP_CHANNEL_STATE_STOR ||
435  connection->controlChannel.state == FTP_CHANNEL_STATE_APPE)
436  {
437  //Prepare to receive data
438  connection->dataChannel.state = FTP_CHANNEL_STATE_RECEIVE;
439  }
440  else
441  {
442  //Data transfer direction is unknown...
443  connection->dataChannel.state = FTP_CHANNEL_STATE_IDLE;
444  }
445  }
446 }
447 
448 
449 /**
450  * @brief Write data to the data connection
451  * @param[in] connection Pointer to the client connection
452  **/
453 
455 {
456  error_t error;
457  size_t n;
458 
459  //Any data waiting for transmission?
460  if(connection->bufferLength > 0)
461  {
462  //Transmit data
463  error = ftpServerWriteChannel(&connection->dataChannel,
464  connection->buffer + connection->bufferPos,
465  connection->bufferLength, &n, 0);
466 
467  //Failed to send data?
468  if(error != NO_ERROR && error != ERROR_TIMEOUT)
469  {
470  //Close the data connection
471  ftpServerCloseDataChannel(connection);
472 
473  //Release previously allocated resources
474  if(connection->file != NULL)
475  {
476  fsCloseFile(connection->file);
477  connection->file = NULL;
478  }
479 
480  if(connection->dir != NULL)
481  {
482  fsCloseDir(connection->dir);
483  connection->dir = NULL;
484  }
485 
486  //Back to idle state
487  connection->controlChannel.state = FTP_CHANNEL_STATE_IDLE;
488 
489  //Transfer status
490  osStrcpy(connection->response, "451 Transfer aborted\r\n");
491  //Debug message
492  TRACE_DEBUG("FTP server: %s", connection->response);
493 
494  //Number of bytes in the response buffer
495  connection->responseLen = osStrlen(connection->response);
496  connection->responsePos = 0;
497 
498  //Exit immediately
499  return;
500  }
501 
502  //Advance data pointer
503  connection->bufferPos += n;
504  //Number of bytes still available in the buffer
505  connection->bufferLength -= n;
506  }
507 
508  //Empty transmission buffer?
509  if(connection->bufferLength == 0)
510  {
511  //File transfer in progress?
512  if(connection->controlChannel.state == FTP_CHANNEL_STATE_RETR)
513  {
514  //Read more data
515  error = fsReadFile(connection->file,
516  connection->buffer, FTP_SERVER_BUFFER_SIZE, &n);
517 
518  //End of stream?
519  if(error)
520  {
521  //Close file
522  fsCloseFile(connection->file);
523  connection->file = NULL;
524 
525 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
526  //TLS-secured connection?
527  if(connection->dataChannel.tlsContext != NULL)
528  {
529  //Gracefully close TLS session
530  connection->dataChannel.state = FTP_CHANNEL_STATE_SHUTDOWN_TLS;
531  }
532  else
533 #endif
534  {
535  //Wait for all the data to be transmitted and acknowledged
536  connection->dataChannel.state = FTP_CHANNEL_STATE_WAIT_ACK;
537  }
538 
539  //Exit immediately
540  return;
541  }
542  }
543  //Directory listing in progress?
544  else if(connection->controlChannel.state == FTP_CHANNEL_STATE_LIST ||
545  connection->controlChannel.state == FTP_CHANNEL_STATE_NLST)
546  {
547  uint_t perm;
548  char_t *path;
549  FsDirEntry dirEntry;
550 
551  //Read a new entry from the directory
552  error = fsReadDir(connection->dir, &dirEntry);
553 
554  //End of stream?
555  if(error)
556  {
557  //Close directory
558  fsCloseDir(connection->dir);
559  connection->dir = NULL;
560 
561 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
562  //TLS-secured connection?
563  if(connection->dataChannel.tlsContext != NULL)
564  {
565  //Gracefully close TLS session
566  connection->dataChannel.state = FTP_CHANNEL_STATE_SHUTDOWN_TLS;
567  }
568  else
569 #endif
570  {
571  //Wait for all the data to be transmitted and acknowledged
572  connection->dataChannel.state = FTP_CHANNEL_STATE_WAIT_ACK;
573  }
574 
575  //Exit immediately
576  return;
577  }
578 
579  //Point to the scratch buffer
580  path = connection->buffer;
581 
582  //Get the pathname of the directory being listed
583  osStrcpy(path, connection->path);
584  //Retrieve the full pathname
585  pathCombine(path, dirEntry.name, FTP_SERVER_MAX_PATH_LEN);
586  pathCanonicalize(path);
587 
588  //Get permissions for the specified file
589  perm = ftpServerGetFilePermissions(connection, path);
590 
591  //Enforce access rights
592  if((perm & FTP_FILE_PERM_LIST) != 0)
593  {
594  //LIST or NLST command?
595  if(connection->controlChannel.state == FTP_CHANNEL_STATE_LIST)
596  {
597  //Format the directory entry in UNIX-style format
598  n = ftpServerFormatDirEntry(&dirEntry, perm, connection->buffer);
599  }
600  else
601  {
602  //The server returns a stream of names of files and no other
603  //information (refer to RFC 959, section 4.1.3)
604  osStrcpy(connection->buffer, dirEntry.name);
605 
606  //Check whether the current entry is a directory
607  if((dirEntry.attributes & FS_FILE_ATTR_DIRECTORY) != 0)
608  {
609  osStrcat(connection->buffer, "/");
610  }
611 
612  //Terminate the name with a CRLF sequence
613  osStrcat(connection->buffer, "\r\n");
614  //Calculate the length of the resulting string
615  n = osStrlen(connection->buffer);
616  }
617 
618  //Debug message
619  TRACE_DEBUG("FTP server: %s", connection->buffer);
620  }
621  else
622  {
623  //Insufficient access rights
624  n = 0;
625  }
626  }
627  //Invalid state?
628  else
629  {
630  //The FTP server has encountered a critical error
631  ftpServerCloseConnection(connection);
632  //Exit immediately
633  return;
634  }
635 
636  //Number of bytes in the buffer
637  connection->bufferPos = 0;
638  connection->bufferLength = n;
639  }
640 }
641 
642 
643 /**
644  * @brief Read data from the data connection
645  * @param[in] connection Pointer to the client connection
646  **/
647 
649 {
650  error_t error;
651  bool_t eof;
652  size_t n;
653 
654  //File transfer in progress?
655  if(connection->controlChannel.state == FTP_CHANNEL_STATE_STOR ||
656  connection->controlChannel.state == FTP_CHANNEL_STATE_APPE)
657  {
658  //Receive data
659  error = ftpServerReadChannel(&connection->dataChannel,
660  connection->buffer + connection->bufferPos,
661  FTP_SERVER_BUFFER_SIZE - connection->bufferLength, &n, 0);
662 
663  //Check status code
664  if(error == NO_ERROR || error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
665  {
666  //Successful read operation
667  eof = FALSE;
668 
669  //Advance data pointer
670  connection->bufferPos += n;
671  connection->bufferLength += n;
672  }
673  else
674  {
675  //Cannot read more data
676  eof = TRUE;
677  }
678 
679  //Read data until the buffer is full or the end of the file is reached
680  if(eof || connection->bufferLength >= FTP_SERVER_BUFFER_SIZE)
681  {
682  //Any data to be written?
683  if(connection->bufferLength > 0)
684  {
685  //Write data to the specified file
686  error = fsWriteFile(connection->file,
687  connection->buffer, connection->bufferLength);
688 
689  //Any error to report?
690  if(error)
691  {
692  //Close the data connection
693  ftpServerCloseDataChannel(connection);
694 
695  //Release previously allocated resources
696  fsCloseFile(connection->file);
697  connection->file = NULL;
698 
699  //Back to idle state
700  connection->controlChannel.state = FTP_CHANNEL_STATE_IDLE;
701 
702  //Transfer status
703  osStrcpy(connection->response, "451 Transfer aborted\r\n");
704  //Debug message
705  TRACE_DEBUG("FTP server: %s", connection->response);
706 
707  //Number of bytes in the response buffer
708  connection->responseLen = osStrlen(connection->response);
709  connection->responsePos = 0;
710 
711  //Exit immediately
712  return;
713  }
714  }
715 
716  //Flush reception buffer
717  connection->bufferLength = 0;
718  connection->bufferPos = 0;
719  }
720 
721  //End of stream?
722  if(eof)
723  {
724  //Close file
725  fsCloseFile(connection->file);
726  connection->file = NULL;
727 
728 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
729  //TLS-secured connection?
730  if(connection->dataChannel.tlsContext != NULL)
731  {
732  //Gracefully close TLS session
733  connection->dataChannel.state = FTP_CHANNEL_STATE_SHUTDOWN_TLS;
734  }
735  else
736 #endif
737  {
738  //Wait for all the data to be transmitted and acknowledged
739  connection->dataChannel.state = FTP_CHANNEL_STATE_WAIT_ACK;
740  }
741  }
742  }
743  //Invalid state?
744  else
745  {
746  //The FTP server has encountered a critical error
747  ftpServerCloseConnection(connection);
748  }
749 }
750 
751 
752 /**
753  * @brief Close data connection
754  * @param[in] connection Pointer to the client connection
755  **/
756 
758 {
759  IpAddr clientIpAddr;
760  uint16_t clientPort;
761 
762  //Check whether the data connection is active
763  if(connection->dataChannel.socket != NULL)
764  {
765  //Retrieve the address of the peer to which a socket is connected
766  socketGetRemoteAddr(connection->dataChannel.socket, &clientIpAddr,
767  &clientPort);
768 
769  //Check whether the data connection is established
770  if(clientPort != 0)
771  {
772  //Debug message
773  TRACE_INFO("FTP server: Closing data connection with client %s port %"
774  PRIu16 "...\r\n", ipAddrToString(&clientIpAddr, NULL), clientPort);
775  }
776 
777 #if (FTP_SERVER_TLS_SUPPORT == ENABLED)
778  //Valid TLS context?
779  if(connection->dataChannel.tlsContext != NULL)
780  {
781  //Release TLS context
782  tlsFree(connection->dataChannel.tlsContext);
783  connection->dataChannel.tlsContext = NULL;
784  }
785 #endif
786 
787  //Valid socket?
788  if(connection->dataChannel.socket != NULL)
789  {
790  //Close data connection
791  socketClose(connection->dataChannel.socket);
792  connection->dataChannel.socket = NULL;
793  }
794 
795  //Re initialize data connection
796  connection->passiveMode = FALSE;
797  connection->remotePort = 0;
798 
799  //Mark the connection as closed
800  connection->dataChannel.state = FTP_CHANNEL_STATE_CLOSED;
801  }
802 }
803 
804 #endif
805 
#define FtpServerContext
Definition: ftp_server.h:208
@ FTP_CHANNEL_STATE_RECEIVE
Definition: ftp_server.h:231
Path manipulation helper functions.
error_t socketBind(Socket *socket, const IpAddr *localIpAddr, uint16_t localPort)
Associate a local address with a socket.
Definition: socket.c:1321
int bool_t
Definition: compiler_port.h:61
@ ERROR_WOULD_BLOCK
Definition: error.h:96
IP network address.
Definition: ip.h:90
@ FTP_CHANNEL_STATE_IDLE
Definition: ftp_server.h:229
FTP data connection.
size_t ftpServerFormatDirEntry(const FsDirEntry *dirEntry, uint_t perm, char_t *buffer)
Format a directory entry in UNIX-style format.
error_t ftpServerOpenDataChannel(FtpClientConnection *connection)
Open data connection.
#define TRUE
Definition: os_port.h:50
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2067
#define FTP_SERVER_MAX_PATH_LEN
Definition: ftp_server.h:130
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:804
Transport protocol abstraction layer.
@ FTP_CHANNEL_STATE_SHUTDOWN_TLS
Definition: ftp_server.h:242
#define osStrlen(s)
Definition: os_port.h:168
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
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:1990
Helper functions for FTP server.
Structure describing socket events.
Definition: socket.h:432
error_t socketSetTxBufferSize(Socket *socket, size_t size)
Specify the size of the TCP send buffer.
Definition: socket.c:1201
@ FTP_CHANNEL_STATE_CLOSED
Definition: ftp_server.h:226
error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
Read data from the specified file.
@ ERROR_OPEN_FAILED
Definition: error.h:75
@ FS_FILE_ATTR_DIRECTORY
Definition: fs_port.h:61
const IpAddr IP_ADDR_ANY
Definition: ip.c:53
@ SOCKET_SD_SEND
Definition: socket.h:160
void pathCanonicalize(char_t *path)
Simplify a path.
Definition: path.c:158
@ FTP_CHANNEL_STATE_RETR
Definition: ftp_server.h:238
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2423
#define FALSE
Definition: os_port.h:46
@ FTP_CHANNEL_STATE_WAIT_ACK
Definition: ftp_server.h:243
void ftpServerReadDataChannel(FtpClientConnection *connection)
Read data from the data connection.
error_t socketSetRxBufferSize(Socket *socket, size_t size)
Specify the size of the TCP receive buffer.
Definition: socket.c:1238
@ FTP_CHANNEL_STATE_NLST
Definition: ftp_server.h:237
error_t
Error codes.
Definition: error.h:43
@ FTP_CHANNEL_STATE_LISTEN
Definition: ftp_server.h:228
void ftpServerCloseDataChannel(FtpClientConnection *connection)
Close data connection.
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:65
void fsCloseFile(FsFile *file)
Close a file.
@ SOCKET_EVENT_TX_READY
Definition: socket.h:175
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ FTP_CHANNEL_STATE_SHUTDOWN_TX
Definition: ftp_server.h:244
void ftpServerRegisterDataChannelEvents(FtpClientConnection *connection, SocketEventDesc *eventDesc)
Register data connection events.
error_t fsReadDir(FsDir *dir, FsDirEntry *dirEntry)
Read an entry from the specified directory stream.
#define FTP_SERVER_MAX_TLS_RX_BUFFER_SIZE
Definition: ftp_server.h:165
bool_t tlsIsTxReady(TlsContext *context)
Check whether some data is ready for transmission.
Definition: tls.c:2344
@ SOCKET_EVENT_RX_SHUTDOWN
Definition: socket.h:180
void ftpServerCloseConnection(FtpClientConnection *connection)
Close client connection properly.
error_t ftpServerEstablishSecureChannel(FtpServerChannel *channel)
Establish secure connection.
@ FTP_CHANNEL_STATE_SHUTDOWN_RX
Definition: ftp_server.h:245
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1354
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:2025
#define TRACE_INFO(...)
Definition: debug.h:105
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
@ FTP_CHANNEL_STATE_APPE
Definition: ftp_server.h:240
error_t ftpServerOpenSecureChannel(FtpServerContext *context, FtpServerChannel *channel, size_t txBufferSize, size_t rxBufferSize)
Open secure connection.
uint_t eventFlags
Returned events.
Definition: socket.h:435
#define FTP_SERVER_BUFFER_SIZE
Definition: ftp_server.h:102
#define socketBindToInterface
Definition: net_legacy.h:193
@ FTP_FILE_PERM_LIST
Definition: ftp_server.h:279
Socket * socketAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a socket.
Definition: socket.c:1456
#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:2378
char_t name[FS_MAX_NAME_LEN+1]
Definition: fs_port.h:112
#define TRACE_DEBUG(...)
Definition: debug.h:119
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:55
#define osStrcat(s1, s2)
Definition: os_port.h:222
@ SOCKET_EVENT_TX_ACKED
Definition: socket.h:177
@ FTP_CHANNEL_STATE_LIST
Definition: ftp_server.h:236
@ SOCKET_EVENT_RX_READY
Definition: socket.h:179
uint_t ftpServerGetFilePermissions(FtpClientConnection *connection, const char_t *path)
Get permissions for the specified file or directory.
uint8_t n
@ SOCKET_EVENT_TX_SHUTDOWN
Definition: socket.h:178
Directory entry.
Definition: fs_port.h:108
@ SOCKET_SD_RECEIVE
Definition: socket.h:159
uint32_t attributes
Definition: fs_port.h:109
#define Socket
Definition: socket.h:36
@ FTP_CHANNEL_STATE_SEND
Definition: ftp_server.h:230
error_t fsWriteFile(FsFile *file, void *data, size_t length)
Write data to the specified file.
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 FtpClientConnection
Definition: ftp_server.h:212
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2585
@ FTP_CHANNEL_STATE_STOR
Definition: ftp_server.h:239
error_t ftpServerWriteChannel(FtpServerChannel *channel, const void *data, size_t length, size_t *written, uint_t flags)
Send data using the relevant transport protocol.
void fsCloseDir(FsDir *dir)
Close a directory stream.
Socket * socket
Handle to a socket to monitor.
Definition: socket.h:433
#define FTP_SERVER_MAX_TCP_BUFFER_SIZE
Definition: ftp_server.h:144
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
void ftpServerAcceptDataChannel(FtpClientConnection *connection)
Accept data connection.
#define osStrcpy(s1, s2)
Definition: os_port.h:210
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:107
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:148
void ftpServerProcessDataChannelEvents(FtpClientConnection *connection, uint_t eventFlags)
Data connection event handler.
@ FTP_CHANNEL_STATE_CONNECT_TLS
Definition: ftp_server.h:227
uint_t eventMask
Requested events.
Definition: socket.h:434
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void pathCombine(char_t *path, const char_t *more, size_t maxLen)
Concatenate two paths.
Definition: path.c:394
void ftpServerWriteDataChannel(FtpClientConnection *connection)
Write data to the data connection.