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