ftp_client.c
Go to the documentation of this file.
1 /**
2  * @file ftp_client.c
3  * @brief FTP client (File Transfer Protocol)
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  * @section Description
28  *
29  * File Transfer Protocol (FTP) is a standard network protocol used to
30  * transfer files from one host to another host over a TCP-based network.
31  * Refer to the following RFCs for complete details:
32  * - RFC 959: File Transfer Protocol (FTP)
33  * - RFC 2428: FTP Extensions for IPv6 and NATs
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 2.5.0
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL FTP_TRACE_LEVEL
41 
42 //Dependencies
43 #include "core/net.h"
44 #include "ftp/ftp_client.h"
46 #include "ftp/ftp_client_misc.h"
47 #include "str.h"
48 #include "debug.h"
49 
50 //Check TCP/IP stack configuration
51 #if (FTP_CLIENT_SUPPORT == ENABLED)
52 
53 
54 /**
55  * @brief Initialize FTP client context
56  * @param[in] context Pointer to the FTP client context
57  * @return Error code
58  **/
59 
61 {
62 #if (FTP_CLIENT_TLS_SUPPORT == ENABLED)
63  error_t error;
64 #endif
65 
66  //Make sure the FTP client context is valid
67  if(context == NULL)
69 
70  //Clear FTP client context
71  osMemset(context, 0, sizeof(FtpClientContext));
72 
73 #if (FTP_CLIENT_TLS_SUPPORT == ENABLED)
74  //Initialize TLS session state
75  error = tlsInitSessionState(&context->tlsSession);
76  //Any error to report?
77  if(error)
78  return error;
79 #endif
80 
81  //Initialize FTP client state
82  context->state = FTP_CLIENT_STATE_DISCONNECTED;
83  //Default timeout
84  context->timeout = FTP_CLIENT_DEFAULT_TIMEOUT;
85 
86  //Successful initialization
87  return NO_ERROR;
88 }
89 
90 
91 #if (FTP_CLIENT_TLS_SUPPORT == ENABLED)
92 
93 /**
94  * @brief Register TLS initialization callback function
95  * @param[in] context Pointer to the FTP client context
96  * @param[in] callback TLS initialization callback function
97  * @return Error code
98  **/
99 
101  FtpClientTlsInitCallback callback)
102 {
103  //Check parameters
104  if(context == NULL || callback == NULL)
106 
107  //Save callback function
108  context->tlsInitCallback = callback;
109 
110  //Successful processing
111  return NO_ERROR;
112 }
113 
114 #endif
115 
116 
117 /**
118  * @brief Set communication timeout
119  * @param[in] context Pointer to the FTP client context
120  * @param[in] timeout Timeout value, in milliseconds
121  * @return Error code
122  **/
123 
125 {
126  //Make sure the FTP client context is valid
127  if(context == NULL)
129 
130  //Save timeout value
131  context->timeout = timeout;
132 
133  //Successful processing
134  return NO_ERROR;
135 }
136 
137 
138 /**
139  * @brief Bind the FTP client to a particular network interface
140  * @param[in] context Pointer to the FTP client context
141  * @param[in] interface Network interface to be used
142  * @return Error code
143  **/
144 
146  NetInterface *interface)
147 {
148  //Make sure the FTP client context is valid
149  if(context == NULL)
151 
152  //Explicitly associate the FTP client with the specified interface
153  context->interface = interface;
154 
155  //Successful processing
156  return NO_ERROR;
157 }
158 
159 
160 /**
161  * @brief Establish a connection with the specified FTP server
162  * @param[in] context Pointer to the FTP client context
163  * @param[in] serverIpAddr IP address of the FTP server to connect to
164  * @param[in] serverPort Port number
165  * @param[in] mode FTP connection mode
166  * @return Error code
167  **/
168 
170  const IpAddr *serverIpAddr, uint16_t serverPort, uint_t mode)
171 {
172  error_t error;
173 
174  //Check parameters
175  if(context == NULL || serverIpAddr == NULL)
177 
178  //Initialize status code
179  error = NO_ERROR;
180 
181  //Establish connection with the FTP server
182  while(!error)
183  {
184  //Check current state
185  if(context->state == FTP_CLIENT_STATE_DISCONNECTED)
186  {
187  //Save the IP address of the FTP server
188  context->serverIpAddr = *serverIpAddr;
189 
190  //Use passive mode?
191  context->passiveMode = (mode & FTP_MODE_PASSIVE) ? TRUE : FALSE;
192 
193  //Open control socket
194  error = ftpClientOpenChannel(context, &context->controlChannel,
196 
197  //Check status code
198  if(!error)
199  {
200  //Establish TCP connection
202  }
203  }
204  else if(context->state == FTP_CLIENT_STATE_CONNECTING_TCP)
205  {
206  //Establish TCP connection
207  error = socketConnect(context->controlChannel.socket, serverIpAddr,
208  serverPort);
209 
210  //Check status code
211  if(!error)
212  {
213  //Implicit FTPS?
214  if((mode & FTP_MODE_IMPLICIT_TLS) != 0)
215  {
216  //TLS initialization
217  error = ftpClientOpenSecureChannel(context,
218  &context->controlChannel, FTP_CLIENT_TLS_TX_BUFFER_SIZE,
220 
221  //Check status code
222  if(!error)
223  {
224  //Perform TLS handshake
226  }
227  }
228  else
229  {
230  //Flush buffer
231  context->bufferPos = 0;
232  context->commandLen = 0;
233  context->replyLen = 0;
234 
235  //Wait for the connection greeting reply
237  }
238  }
239  }
240  else if(context->state == FTP_CLIENT_STATE_CONNECTING_TLS)
241  {
242  //Perform TLS handshake
243  error = ftpClientEstablishSecureChannel(&context->controlChannel);
244 
245  //Check status code
246  if(!error)
247  {
248  //Implicit FTPS?
249  if((mode & FTP_MODE_IMPLICIT_TLS) != 0)
250  {
251  //Flush buffer
252  context->bufferPos = 0;
253  context->commandLen = 0;
254  context->replyLen = 0;
255 
256  //Wait for the connection greeting reply
258  }
259  else
260  {
261  //The FTP client is connected
263  }
264  }
265  }
266  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
267  {
268  //Wait for the connection greeting reply
269  error = ftpClientSendCommand(context);
270 
271  //Check status code
272  if(!error)
273  {
274  //Check FTP response code
275  if(FTP_REPLY_CODE_2YZ(context->replyCode))
276  {
277  //Explicit FTPS?
278  if((mode & FTP_MODE_EXPLICIT_TLS) != 0)
279  {
280  //Format AUTH TLS command
281  error = ftpClientFormatCommand(context, "AUTH TLS", NULL);
282 
283  //Check status code
284  if(!error)
285  {
286  //Send AUTH TLS command and wait for the server's response
288  }
289  }
290  else
291  {
292  //The FTP client is connected
294  }
295  }
296  else
297  {
298  //Report an error
300  }
301  }
302  }
303  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2)
304  {
305  //Send AUTH TLS command and wait for the server's response
306  error = ftpClientSendCommand(context);
307 
308  //Check status code
309  if(!error)
310  {
311  //Check FTP response code
312  if(FTP_REPLY_CODE_2YZ(context->replyCode))
313  {
314  //TLS initialization
315  error = ftpClientOpenSecureChannel(context,
316  &context->controlChannel, FTP_CLIENT_TLS_TX_BUFFER_SIZE,
318 
319  //Check status code
320  if(!error)
321  {
322  //Perform TLS handshake
324  }
325  }
326  else
327  {
328  //Report an error
330  }
331  }
332  }
333  else if(context->state == FTP_CLIENT_STATE_CONNECTED)
334  {
335  //The FTP client is connected
336  break;
337  }
338  else
339  {
340  //Invalid state
341  error = ERROR_WRONG_STATE;
342  }
343  }
344 
345  //Check status code
346  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
347  {
348  //Check whether the timeout has elapsed
349  error = ftpClientCheckTimeout(context);
350  }
351 
352  //Failed to establish connection with the FTP server?
353  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
354  {
355  //Clean up side effects
356  ftpClientCloseChannel(&context->controlChannel);
357  //Update FTP client state
359  }
360 
361  //Return status code
362  return error;
363 }
364 
365 
366 /**
367  * @brief Login to the FTP server using the provided user name and password
368  * @param[in] context Pointer to the FTP client context
369  * @param[in] username NULL-terminated string containing the user name
370  * @param[in] password NULL-terminated string containing the user's password
371  * @return Error code
372  **/
373 
374 error_t ftpClientLogin(FtpClientContext *context, const char_t *username,
375  const char_t *password)
376 {
377  //The USER, PASS and ACCT commands specify access control identifiers
378  return ftpClientLoginEx(context, username, password, "");
379 }
380 
381 
382 /**
383  * @brief Login to the FTP server using user name, password and account
384  * @param[in] context Pointer to the FTP client context
385  * @param[in] username NULL-terminated string containing the user name
386  * @param[in] password NULL-terminated string containing the user's password
387  * @param[in] account NULL-terminated string containing the user's account
388  * @return Error code
389  **/
390 
392  const char_t *password, const char_t *account)
393 {
394  error_t error;
395 
396  //Check parameters
397  if(context == NULL || username == NULL || password == NULL || account == NULL)
399 
400  //Initialize status code
401  error = NO_ERROR;
402 
403  //Execute FTP command sequence
404  while(!error)
405  {
406  //Check current state
407  if(context->state == FTP_CLIENT_STATE_CONNECTED)
408  {
409  //Format USER command
410  error = ftpClientFormatCommand(context, "USER", username);
411 
412  //Check status code
413  if(!error)
414  {
415  //Send USER command and wait for the server's response
417  }
418  }
419  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
420  {
421  //Send USER command and wait for the server's response
422  error = ftpClientSendCommand(context);
423 
424  //Check status code
425  if(!error)
426  {
427  //Check FTP response code
428  if(FTP_REPLY_CODE_2YZ(context->replyCode))
429  {
430  //Update FTP client state
432  //Successful user identification
433  break;
434  }
435  else if(FTP_REPLY_CODE_3YZ(context->replyCode))
436  {
437  //Format PASS command
438  error = ftpClientFormatCommand(context, "PASS", password);
439 
440  //Check status code
441  if(!error)
442  {
443  //Send PASS command and wait for the server's response
445  }
446  }
447  else
448  {
449  //Update FTP client state
451  //Report an error
453  }
454  }
455  }
456  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2)
457  {
458  //Send PASS command and wait for the server's response
459  error = ftpClientSendCommand(context);
460 
461  //Check status code
462  if(!error)
463  {
464  //Check FTP response code
465  if(FTP_REPLY_CODE_2YZ(context->replyCode))
466  {
467  //Update FTP client state
469  //Successful user identification
470  break;
471  }
472  else if(FTP_REPLY_CODE_3YZ(context->replyCode))
473  {
474  //Format ACCT command
475  error = ftpClientFormatCommand(context, "ACCT", account);
476 
477  //Check status code
478  if(!error)
479  {
480  //Send ACCT command and wait for the server's response
482  }
483  }
484  else
485  {
486  //Update FTP client state
488  //Report an error
490  }
491  }
492  }
493  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_3)
494  {
495  //Send ACCT command and wait for the server's response
496  error = ftpClientSendCommand(context);
497 
498  //Check status code
499  if(!error)
500  {
501  //Check FTP response code
502  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
503  {
504  //Report an error
506  }
507 
508  //Update FTP client state
510  //We are done
511  break;
512  }
513  }
514  else
515  {
516  //Invalid state
517  error = ERROR_WRONG_STATE;
518  }
519  }
520 
521  //Check status code
522  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
523  {
524  //Check whether the timeout has elapsed
525  error = ftpClientCheckTimeout(context);
526  }
527 
528  //Return status code
529  return error;
530 }
531 
532 
533 /**
534  * @brief Get current working directory
535  * @param[in] context Pointer to the FTP client context
536  * @param[out] path Output buffer where to store the current directory
537  * @param[in] maxLen Maximum number of characters the buffer can hold
538  * @return Error code
539  **/
540 
542  size_t maxLen)
543 {
544  error_t error;
545 
546  //Check parameters
547  if(context == NULL || path == NULL)
549 
550  //Initialize status code
551  error = NO_ERROR;
552 
553  //Execute FTP command
554  while(!error)
555  {
556  //Check current state
557  if(context->state == FTP_CLIENT_STATE_CONNECTED)
558  {
559  //Format PWD command
560  error = ftpClientFormatCommand(context, "PWD", NULL);
561 
562  //Check status code
563  if(!error)
564  {
565  //Send PWD command and wait for the server's response
567  }
568  }
569  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
570  {
571  //Send PWD command and wait for the server's response
572  error = ftpClientSendCommand(context);
573 
574  //Check status code
575  if(!error)
576  {
577  //Check FTP response code
578  if(FTP_REPLY_CODE_2YZ(context->replyCode))
579  {
580  //Parse server's response
581  error = ftpClientParsePwdReply(context, path, maxLen);
582  }
583  else
584  {
585  //Report an error
587  }
588 
589  //Update FTP client state
591  //We are done
592  break;
593  }
594  }
595  else
596  {
597  //Invalid state
598  error = ERROR_WRONG_STATE;
599  }
600  }
601 
602  //Check status code
603  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
604  {
605  //Check whether the timeout has elapsed
606  error = ftpClientCheckTimeout(context);
607  }
608 
609  //Return status code
610  return error;
611 }
612 
613 
614 /**
615  * @brief Change working directory
616  * @param[in] context Pointer to the FTP client context
617  * @param[in] path New current working directory
618  * @return Error code
619  **/
620 
622  const char_t *path)
623 {
624  error_t error;
625 
626  //Check parameters
627  if(context == NULL || path == NULL)
629 
630  //Initialize status code
631  error = NO_ERROR;
632 
633  //Execute FTP command
634  while(!error)
635  {
636  //Check current state
637  if(context->state == FTP_CLIENT_STATE_CONNECTED)
638  {
639  //Format CWD command
640  error = ftpClientFormatCommand(context, "CWD", path);
641 
642  //Check status code
643  if(!error)
644  {
645  //Send CWD command and wait for the server's response
647  }
648  }
649  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
650  {
651  //Send CWD command and wait for the server's response
652  error = ftpClientSendCommand(context);
653 
654  //Check status code
655  if(!error)
656  {
657  //Check FTP response code
658  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
659  {
660  //Report an error
662  }
663 
664  //Update FTP client state
666  //We are done
667  break;
668  }
669  }
670  else
671  {
672  //Invalid state
673  error = ERROR_WRONG_STATE;
674  }
675  }
676 
677  //Check status code
678  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
679  {
680  //Check whether the timeout has elapsed
681  error = ftpClientCheckTimeout(context);
682  }
683 
684  //Return status code
685  return error;
686 }
687 
688 
689 /**
690  * @brief Change to parent directory
691  * @param[in] context Pointer to the FTP client context
692  * @return Error code
693  **/
694 
696 {
697  error_t error;
698 
699  //Make sure the FTP client context is valid
700  if(context == NULL)
702 
703  //Initialize status code
704  error = NO_ERROR;
705 
706  //Execute FTP command
707  while(!error)
708  {
709  //Check current state
710  if(context->state == FTP_CLIENT_STATE_CONNECTED)
711  {
712  //Format CDUP command
713  error = ftpClientFormatCommand(context, "CDUP", NULL);
714 
715  //Check status code
716  if(!error)
717  {
718  //Send CDUP command and wait for the server's response
720  }
721  }
722  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
723  {
724  //Send CDUP command and wait for the server's response
725  error = ftpClientSendCommand(context);
726 
727  //Check status code
728  if(!error)
729  {
730  //Check FTP response code
731  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
732  {
733  //Report an error
735  }
736 
737  //Update FTP client state
739  //We are done
740  break;
741  }
742  }
743  else
744  {
745  //Invalid state
746  error = ERROR_WRONG_STATE;
747  }
748  }
749 
750  //Check status code
751  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
752  {
753  //Check whether the timeout has elapsed
754  error = ftpClientCheckTimeout(context);
755  }
756 
757  //Return status code
758  return error;
759 }
760 
761 
762 /**
763  * @brief Open a directory
764  * @param[in] context Pointer to the FTP client context
765  * @param[in] path Path to the directory to be be opened
766  * @return Directory handle
767  **/
768 
770 {
771  error_t error;
772 
773  //Check parameters
774  if(context == NULL || path == NULL)
776 
777  //Initialize status code
778  error = NO_ERROR;
779 
780  //Execute FTP command sequence
781  while(!error)
782  {
783  //Check current state
784  if(context->state == FTP_CLIENT_STATE_CONNECTED)
785  {
786  //The data transfer is over the data connection in type ASCII or
787  //type EBCDIC (refer to RFC 959, section 4.1.3)
788  error = ftpClientFormatCommand(context, "TYPE", "A");
789 
790  //Check status code
791  if(!error)
792  {
793  //Send TYPE command and wait for the server's response
795  }
796  }
797  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
798  {
799  //Send TYPE command and wait for the server's response
800  error = ftpClientSendCommand(context);
801 
802  //Check status code
803  if(!error)
804  {
805  //Check FTP response code
806  if(FTP_REPLY_CODE_2YZ(context->replyCode))
807  {
808  //Update FTP client state
810  }
811  else
812  {
813  //Report an error
815  }
816  }
817  }
818  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2 ||
819  context->state == FTP_CLIENT_STATE_SUB_COMMAND_3 ||
820  context->state == FTP_CLIENT_STATE_SUB_COMMAND_4 ||
821  context->state == FTP_CLIENT_STATE_SUB_COMMAND_5 ||
822  context->state == FTP_CLIENT_STATE_SUB_COMMAND_6 ||
823  context->state == FTP_CLIENT_STATE_CONNECTING_TCP ||
824  context->state == FTP_CLIENT_STATE_SUB_COMMAND_8 ||
825  context->state == FTP_CLIENT_STATE_ACCEPTING_TCP ||
826  context->state == FTP_CLIENT_STATE_CONNECTING_TLS)
827  {
828  //Initiate data transfer
829  error = ftpClientInitDataTransfer(context, FALSE);
830  }
831  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_7)
832  {
833  //Format LIST command
834  if(osStrcmp(path, ".") == 0)
835  {
836  ftpClientFormatCommand(context, "LIST", NULL);
837  }
838  else
839  {
840  ftpClientFormatCommand(context, "LIST", path);
841  }
842 
843  //Check status code
844  if(!error)
845  {
846  //Send LIST command and wait for the server's response
848  }
849  }
850  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_9)
851  {
852  //Flush buffer
853  context->bufferPos = 0;
854  context->commandLen = 0;
855  context->replyLen = 0;
856 
857  //The content of the directory can be transferred via the data
858  //connection
860 
861  //We are done
862  break;
863  }
864  else
865  {
866  //Invalid state
867  error = ERROR_WRONG_STATE;
868  }
869  }
870 
871  //Check status code
872  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
873  {
874  //Check whether the timeout has elapsed
875  error = ftpClientCheckTimeout(context);
876  }
877 
878  //Failed to open directory?
879  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
880  {
881  //Close data connection
882  ftpClientCloseChannel(&context->dataChannel);
883  //Update FTP client state
885  }
886 
887  //Return status code
888  return error;
889 }
890 
891 
892 /**
893  * @brief Read an entry from the directory
894  * @param[in] context Pointer to the FTP client context
895  * @param[out] dirEntry Pointer to a directory entry
896  * @return Error code
897  **/
898 
900 {
901  error_t error;
902  size_t n;
903 
904  //Check parameters
905  if(context == NULL || dirEntry == NULL)
907 
908  //Initialize status code
909  error = NO_ERROR;
910 
911  //Erase the contents of the entry
912  osMemset(dirEntry, 0, sizeof(FtpDirEntry));
913 
914  //Check current state
915  if(context->state == FTP_CLIENT_STATE_READING_DATA)
916  {
917  //Loop through directory entries
918  while(!error)
919  {
920  //Determine whether more data should be collected
921  if(context->replyLen < (FTP_CLIENT_BUFFER_SIZE - 1))
922  {
923  //Receive data from the FTP server
924  error = ftpClientReadChannel(&context->dataChannel,
925  context->buffer + context->replyLen,
926  FTP_CLIENT_BUFFER_SIZE - 1 - context->replyLen,
928 
929  //Check status code
930  if(error == NO_ERROR)
931  {
932  //Advance data pointer
933  context->replyLen += n;
934 
935  //Check whether the string is terminated by a CRLF sequence
936  if(context->replyLen != 0 &&
937  context->buffer[context->replyLen - 1] == '\n')
938  {
939  //Save current time
940  context->timestamp = osGetSystemTime();
941 
942  //Properly terminate the string with a NULL character
943  context->buffer[context->replyLen] = '\0';
944  //Flush buffer
945  context->replyLen = 0;
946 
947  //Remove trailing whitespace characters
948  strRemoveTrailingSpace(context->buffer);
949 
950  //Discard empty lines
951  if(context->buffer[0] != '\0')
952  {
953  //Parse current directory entry
954  error = ftpClientParseDirEntry(context->buffer, dirEntry);
955  //We are done
956  break;
957  }
958  }
959  }
960  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
961  {
962  //Check whether the timeout has elapsed
963  error = ftpClientCheckTimeout(context);
964  }
965  else
966  {
967  //Communication error
968  }
969  }
970  else
971  {
972  //Flush buffer
973  context->replyLen = 0;
974  }
975  }
976  }
977  else
978  {
979  //Invalid state
980  error = ERROR_WRONG_STATE;
981  }
982 
983  //Return status code
984  return error;
985 }
986 
987 
988 /**
989  * @brief Close directory
990  * @param[in] context Pointer to the FTP client context
991  * @return Error code
992  **/
993 
995 {
996  //Make sure the FTP client context is valid
997  if(context == NULL)
999 
1000  //Close data connection and get transfer status
1001  return ftpClientTerminateDataTransfer(context);
1002 }
1003 
1004 
1005 /**
1006  * @brief Create a new directory
1007  * @param[in] context Pointer to the FTP client context
1008  * @param[in] path Name of the new directory
1009  * @return Error code
1010  **/
1011 
1013 {
1014  error_t error;
1015 
1016  //Check parameters
1017  if(context == NULL || path == NULL)
1018  return ERROR_INVALID_PARAMETER;
1019 
1020  //Initialize status code
1021  error = NO_ERROR;
1022 
1023  //Execute FTP command
1024  while(!error)
1025  {
1026  //Check current state
1027  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1028  {
1029  //Format MKD command
1030  error = ftpClientFormatCommand(context, "MKD", path);
1031 
1032  //Check status code
1033  if(!error)
1034  {
1035  //Send MKD command and wait for the server's response
1037  }
1038  }
1039  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1040  {
1041  //Send MKD command and wait for the server's response
1042  error = ftpClientSendCommand(context);
1043 
1044  //Check status code
1045  if(!error)
1046  {
1047  //Check FTP response code
1048  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1049  {
1050  //Report an error
1051  error = ERROR_UNEXPECTED_RESPONSE;
1052  }
1053 
1054  //Update FTP client state
1056  //We are done
1057  break;
1058  }
1059  }
1060  else
1061  {
1062  //Invalid state
1063  error = ERROR_WRONG_STATE;
1064  }
1065  }
1066 
1067  //Check status code
1068  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1069  {
1070  //Check whether the timeout has elapsed
1071  error = ftpClientCheckTimeout(context);
1072  }
1073 
1074  //Return status code
1075  return error;
1076 }
1077 
1078 
1079 /**
1080  * @brief Remove a directory
1081  * @param[in] context Pointer to the FTP client context
1082  * @param[in] path Path to the directory to be removed
1083  * @return Error code
1084  **/
1085 
1087 {
1088  error_t error;
1089 
1090  //Check parameters
1091  if(context == NULL || path == NULL)
1092  return ERROR_INVALID_PARAMETER;
1093 
1094  //Initialize status code
1095  error = NO_ERROR;
1096 
1097  //Execute FTP command
1098  while(!error)
1099  {
1100  //Check current state
1101  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1102  {
1103  //Format RMD command
1104  error = ftpClientFormatCommand(context, "RMD", path);
1105 
1106  //Check status code
1107  if(!error)
1108  {
1109  //Send RMD command and wait for the server's response
1111  }
1112  }
1113  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1114  {
1115  //Send RMD command and wait for the server's response
1116  error = ftpClientSendCommand(context);
1117 
1118  //Check status code
1119  if(!error)
1120  {
1121  //Check FTP response code
1122  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1123  {
1124  //Report an error
1125  error = ERROR_UNEXPECTED_RESPONSE;
1126  }
1127 
1128  //Update FTP client state
1130  //We are done
1131  break;
1132  }
1133  }
1134  else
1135  {
1136  //Invalid state
1137  error = ERROR_WRONG_STATE;
1138  }
1139  }
1140 
1141  //Check status code
1142  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1143  {
1144  //Check whether the timeout has elapsed
1145  error = ftpClientCheckTimeout(context);
1146  }
1147 
1148  //Return status code
1149  return error;
1150 }
1151 
1152 
1153 /**
1154  * @brief Open a file for reading, writing, or appending
1155  * @param[in] context Pointer to the FTP client context
1156  * @param[in] path Path to the file to be be opened
1157  * @param[in] mode File access mode
1158  * @return Error code
1159  **/
1160 
1162  uint_t mode)
1163 {
1164  error_t error;
1165 
1166  //Check parameters
1167  if(context == NULL || path == NULL)
1168  return ERROR_INVALID_PARAMETER;
1169 
1170  //Initialize status code
1171  error = NO_ERROR;
1172 
1173  //Execute FTP command sequence
1174  while(!error)
1175  {
1176  //Check current state
1177  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1178  {
1179  //Set representation type
1180  if((mode & FTP_FILE_MODE_TEXT) != 0)
1181  {
1182  //Use ASCII type
1183  error = ftpClientFormatCommand(context, "TYPE", "A");
1184  }
1185  else
1186  {
1187  //Use image type
1188  error = ftpClientFormatCommand(context, "TYPE", "I");
1189  }
1190 
1191  //Check status code
1192  if(!error)
1193  {
1194  //Send TYPE command and wait for the server's response
1196  }
1197  }
1198  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1199  {
1200  //Send TYPE command and wait for the server's response
1201  error = ftpClientSendCommand(context);
1202 
1203  //Check status code
1204  if(!error)
1205  {
1206  //Check FTP response code
1207  if(FTP_REPLY_CODE_2YZ(context->replyCode))
1208  {
1209  //Update FTP client state
1211  }
1212  else
1213  {
1214  //Report an error
1215  error = ERROR_UNEXPECTED_RESPONSE;
1216  }
1217  }
1218  }
1219  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2 ||
1220  context->state == FTP_CLIENT_STATE_SUB_COMMAND_3 ||
1221  context->state == FTP_CLIENT_STATE_SUB_COMMAND_4 ||
1222  context->state == FTP_CLIENT_STATE_SUB_COMMAND_5 ||
1223  context->state == FTP_CLIENT_STATE_SUB_COMMAND_6 ||
1224  context->state == FTP_CLIENT_STATE_CONNECTING_TCP ||
1225  context->state == FTP_CLIENT_STATE_SUB_COMMAND_8 ||
1226  context->state == FTP_CLIENT_STATE_ACCEPTING_TCP ||
1227  context->state == FTP_CLIENT_STATE_CONNECTING_TLS)
1228  {
1229  //Initiate data transfer
1230  if((mode & FTP_FILE_MODE_WRITE) != 0 ||
1231  (mode & FTP_FILE_MODE_APPEND) != 0)
1232  {
1233  error = ftpClientInitDataTransfer(context, TRUE);
1234  }
1235  else
1236  {
1237  error = ftpClientInitDataTransfer(context, FALSE);
1238  }
1239  }
1240  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_7)
1241  {
1242  //Format STOR/APPE/RETR command
1243  if((mode & FTP_FILE_MODE_WRITE) != 0)
1244  {
1245  ftpClientFormatCommand(context, "STOR", path);
1246  }
1247  else if((mode & FTP_FILE_MODE_APPEND) != 0)
1248  {
1249  ftpClientFormatCommand(context, "APPE", path);
1250  }
1251  else
1252  {
1253  ftpClientFormatCommand(context, "RETR", path);
1254  }
1255 
1256  //Check status code
1257  if(!error)
1258  {
1259  //Send STOR/APPE/RETR command and wait for the server's response
1261  }
1262  }
1263  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_9)
1264  {
1265  //Check data transfer direction
1266  if((mode & FTP_FILE_MODE_WRITE) != 0 ||
1267  (mode & FTP_FILE_MODE_APPEND) != 0)
1268  {
1269  //The content of the file can be written via the data connection
1271  }
1272  else
1273  {
1274  //The content of the file can be read via the data connection
1276  }
1277 
1278  //We are done
1279  break;
1280  }
1281  else
1282  {
1283  //Invalid state
1284  error = ERROR_WRONG_STATE;
1285  }
1286  }
1287 
1288  //Check status code
1289  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1290  {
1291  //Check whether the timeout has elapsed
1292  error = ftpClientCheckTimeout(context);
1293  }
1294 
1295  //Failed to open file?
1296  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
1297  {
1298  //Close data connection
1299  ftpClientCloseChannel(&context->dataChannel);
1300  //Update FTP client state
1302  }
1303 
1304  //Return status code
1305  return error;
1306 }
1307 
1308 
1309 /**
1310  * @brief Write to a remote file
1311  * @param[in] context Pointer to the FTP client context
1312  * @param[in] data Pointer to a buffer containing the data to be written
1313  * @param[in] length Number of data bytes to write
1314  * @param[in] written Number of bytes that have been written (optional parameter)
1315  * @param[in] flags Set of flags that influences the behavior of this function
1316  * @return Error code
1317  **/
1318 
1320  size_t length, size_t *written, uint_t flags)
1321 {
1322  error_t error;
1323  size_t n;
1324 
1325  //Make sure the FTP client context is valid
1326  if(context == NULL)
1327  return ERROR_INVALID_PARAMETER;
1328 
1329  //Check parameters
1330  if(data == NULL && length != 0)
1331  return ERROR_INVALID_PARAMETER;
1332 
1333  //Actual number of bytes written
1334  n = 0;
1335 
1336  //Check current state
1337  if(context->state == FTP_CLIENT_STATE_WRITING_DATA)
1338  {
1339  //Transmit data to the FTP server
1340  error = ftpClientWriteChannel(&context->dataChannel, data, length, &n,
1341  flags);
1342 
1343  //Check status code
1344  if(error == NO_ERROR || error == ERROR_TIMEOUT)
1345  {
1346  //Any data transmitted?
1347  if(n > 0)
1348  {
1349  //Save current time
1350  context->timestamp = osGetSystemTime();
1351  }
1352  }
1353  }
1354  else
1355  {
1356  //Invalid state
1357  error = ERROR_WRONG_STATE;
1358  }
1359 
1360  //Check status code
1361  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1362  {
1363  //Check whether the timeout has elapsed
1364  error = ftpClientCheckTimeout(context);
1365  }
1366 
1367  //Total number of data that have been written
1368  if(written != NULL)
1369  *written = n;
1370 
1371  //Return status code
1372  return error;
1373 }
1374 
1375 
1376 /**
1377  * @brief Read from a remote file
1378  * @param[in] context Pointer to the FTP client context
1379  * @param[out] data Buffer where to store the incoming data
1380  * @param[in] size Maximum number of bytes that can be read
1381  * @param[out] received Actual number of bytes that have been read
1382  * @param[in] flags Set of flags that influences the behavior of this function
1383  * @return Error code
1384  **/
1385 
1386 error_t ftpClientReadFile(FtpClientContext *context, void *data, size_t size,
1387  size_t *received, uint_t flags)
1388 {
1389  error_t error;
1390 
1391  //Check parameters
1392  if(context == NULL || data == NULL || received == NULL)
1393  return ERROR_INVALID_PARAMETER;
1394 
1395  //Check current state
1396  if(context->state == FTP_CLIENT_STATE_READING_DATA)
1397  {
1398  //Receive data from the FTP server
1399  error = ftpClientReadChannel(&context->dataChannel, data, size,
1400  received, flags);
1401 
1402  //Check status code
1403  if(error == NO_ERROR)
1404  {
1405  //Save current time
1406  context->timestamp = osGetSystemTime();
1407  }
1408  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1409  {
1410  //Check whether the timeout has elapsed
1411  error = ftpClientCheckTimeout(context);
1412  }
1413  else
1414  {
1415  //Communication error
1416  }
1417  }
1418  else
1419  {
1420  //Invalid state
1421  error = ERROR_WRONG_STATE;
1422  }
1423 
1424  //Return status code
1425  return error;
1426 }
1427 
1428 
1429 /**
1430  * @brief Close file
1431  * @param[in] context Pointer to the FTP client context
1432  * @return Error code
1433  **/
1434 
1436 {
1437  //Make sure the FTP client context is valid
1438  if(context == NULL)
1439  return ERROR_INVALID_PARAMETER;
1440 
1441  //Close data connection and get transfer status
1442  return ftpClientTerminateDataTransfer(context);
1443 }
1444 
1445 
1446 /**
1447  * @brief Rename a file
1448  * @param[in] context Pointer to the FTP client context
1449  * @param[in] oldPath Name of an existing file or directory
1450  * @param[in] newPath New name for the file or directory
1451  * @return Error code
1452  **/
1453 
1455  const char_t *newPath)
1456 {
1457  error_t error;
1458 
1459  //Check parameters
1460  if(context == NULL || oldPath == NULL || newPath == NULL)
1461  return ERROR_INVALID_PARAMETER;
1462 
1463  //Initialize status code
1464  error = NO_ERROR;
1465 
1466  //Execute FTP command sequence
1467  while(!error)
1468  {
1469  //Check current state
1470  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1471  {
1472  //Format RNFR command
1473  error = ftpClientFormatCommand(context, "RNFR", oldPath);
1474 
1475  //Check status code
1476  if(!error)
1477  {
1478  //Send USER command and wait for the server's response
1480  }
1481  }
1482  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1483  {
1484  //Send RNFR command and wait for the server's response
1485  error = ftpClientSendCommand(context);
1486 
1487  //Check status code
1488  if(!error)
1489  {
1490  //Check FTP response code
1491  if(FTP_REPLY_CODE_3YZ(context->replyCode))
1492  {
1493  //Format RNTO command
1494  error = ftpClientFormatCommand(context, "RNTO", newPath);
1495 
1496  //Check status code
1497  if(!error)
1498  {
1499  //Send RNTO command and wait for the server's response
1501  }
1502  }
1503  else
1504  {
1505  //Update FTP client state
1507  //Report an error
1508  error = ERROR_UNEXPECTED_RESPONSE;
1509  }
1510  }
1511  }
1512  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2)
1513  {
1514  //Send RNTO command and wait for the server's response
1515  error = ftpClientSendCommand(context);
1516 
1517  //Check status code
1518  if(!error)
1519  {
1520  //Check FTP response code
1521  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1522  {
1523  //Report an error
1524  error = ERROR_UNEXPECTED_RESPONSE;
1525  }
1526 
1527  //Update FTP client state
1529  //We are done
1530  break;
1531  }
1532  }
1533  else
1534  {
1535  //Invalid state
1536  error = ERROR_WRONG_STATE;
1537  }
1538  }
1539 
1540  //Check status code
1541  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1542  {
1543  //Check whether the timeout has elapsed
1544  error = ftpClientCheckTimeout(context);
1545  }
1546 
1547  //Return status code
1548  return error;
1549 }
1550 
1551 
1552 /**
1553  * @brief Delete a file
1554  * @param[in] context Pointer to the FTP client context
1555  * @param[in] path Path to the file to be be deleted
1556  * @return Error code
1557  **/
1558 
1560 {
1561  error_t error;
1562 
1563  //Check parameters
1564  if(context == NULL || path == NULL)
1565  return ERROR_INVALID_PARAMETER;
1566 
1567  //Initialize status code
1568  error = NO_ERROR;
1569 
1570  //Execute FTP command
1571  while(!error)
1572  {
1573  //Check current state
1574  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1575  {
1576  //Format DELE command
1577  error = ftpClientFormatCommand(context, "DELE", path);
1578 
1579  //Check status code
1580  if(!error)
1581  {
1582  //Send DELE command and wait for the server's response
1584  }
1585  }
1586  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1587  {
1588  //Send DELE command and wait for the server's response
1589  error = ftpClientSendCommand(context);
1590 
1591  //Check status code
1592  if(!error)
1593  {
1594  //Check FTP response code
1595  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1596  {
1597  //Report an error
1598  error = ERROR_UNEXPECTED_RESPONSE;
1599  }
1600 
1601  //Update FTP client state
1603  //We are done
1604  break;
1605  }
1606  }
1607  else
1608  {
1609  //Invalid state
1610  error = ERROR_WRONG_STATE;
1611  }
1612  }
1613 
1614  //Check status code
1615  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1616  {
1617  //Check whether the timeout has elapsed
1618  error = ftpClientCheckTimeout(context);
1619  }
1620 
1621  //Return status code
1622  return error;
1623 }
1624 
1625 
1626 /**
1627  * @brief Retrieve server's reply code
1628  * @param[in] context Pointer to the FTP client context
1629  * @return FTP reply code
1630  **/
1631 
1633 {
1634  uint_t replyCode;
1635 
1636  //Make sure the FTP client context is valid
1637  if(context != NULL)
1638  {
1639  //Get server's reply code
1640  replyCode = context->replyCode;
1641  }
1642  else
1643  {
1644  //The FTP client context is not valid
1645  replyCode = 0;
1646  }
1647 
1648  //Return FTP reply code
1649  return replyCode;
1650 }
1651 
1652 
1653 /**
1654  * @brief Gracefully disconnect from the FTP server
1655  * @param[in] context Pointer to the FTP client context
1656  * @return Error code
1657  **/
1658 
1660 {
1661  error_t error;
1662 
1663  //Make sure the FTP client context is valid
1664  if(context == NULL)
1665  return ERROR_INVALID_PARAMETER;
1666 
1667  //Initialize status code
1668  error = NO_ERROR;
1669 
1670  //Execute FTP command sequence
1671  while(!error)
1672  {
1673  //Check current state
1674  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1675  {
1676  //Update FTP client state
1678  }
1679  else if(context->state == FTP_CLIENT_STATE_DISCONNECTING_1)
1680  {
1681  //Shutdown data connection
1682  error = ftpClientShutdownChannel(&context->dataChannel);
1683 
1684  //Check status code
1685  if(!error)
1686  {
1687  //Close data connection
1688  ftpClientCloseChannel(&context->dataChannel);
1689  //Update FTP client state
1691  }
1692  }
1693  else if(context->state == FTP_CLIENT_STATE_DISCONNECTING_2)
1694  {
1695  //Shutdown control connection
1696  error = ftpClientShutdownChannel(&context->controlChannel);
1697 
1698  //Check status code
1699  if(!error)
1700  {
1701  //Close control connection
1702  ftpClientCloseChannel(&context->controlChannel);
1703  //Update FTP client state
1705  }
1706  }
1707  else if(context->state == FTP_CLIENT_STATE_DISCONNECTED)
1708  {
1709  //We are done
1710  break;
1711  }
1712  else
1713  {
1714  //Invalid state
1715  error = ERROR_WRONG_STATE;
1716  }
1717  }
1718 
1719  //Check status code
1720  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1721  {
1722  //Check whether the timeout has elapsed
1723  error = ftpClientCheckTimeout(context);
1724  }
1725 
1726  //Failed to gracefully disconnect from the FTP server?
1727  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
1728  {
1729  //Close data and control connections
1730  ftpClientCloseChannel(&context->dataChannel);
1731  ftpClientCloseChannel(&context->controlChannel);
1732 
1733  //Update FTP client state
1735  }
1736 
1737  //Return status code
1738  return error;
1739 }
1740 
1741 
1742 /**
1743  * @brief Close the connection with the FTP server
1744  * @param[in] context Pointer to the FTP client context
1745  * @return Error code
1746  **/
1747 
1749 {
1750  //Make sure the FTP client context is valid
1751  if(context == NULL)
1752  return ERROR_INVALID_PARAMETER;
1753 
1754  //Close data and control connections
1755  ftpClientCloseChannel(&context->dataChannel);
1756  ftpClientCloseChannel(&context->controlChannel);
1757 
1758  //Update FTP client state
1760 
1761  //Successful processing
1762  return NO_ERROR;
1763 }
1764 
1765 
1766 /**
1767  * @brief Release FTP client context
1768  * @param[in] context Pointer to the FTP client context
1769  **/
1770 
1772 {
1773  //Make sure the FTP client context is valid
1774  if(context != NULL)
1775  {
1776  //Close data and control connections
1777  ftpClientCloseChannel(&context->dataChannel);
1778  ftpClientCloseChannel(&context->controlChannel);
1779 
1780 #if (FTP_CLIENT_TLS_SUPPORT == ENABLED)
1781  //Release TLS session state
1782  tlsFreeSessionState(&context->tlsSession);
1783 #endif
1784 
1785  //Clear FTP client context
1786  osMemset(context, 0, sizeof(FtpClientContext));
1787  }
1788 }
1789 
1790 #endif
error_t ftpClientLogin(FtpClientContext *context, const char_t *username, const char_t *password)
Login to the FTP server using the provided user name and password.
Definition: ftp_client.c:374
@ FTP_CLIENT_STATE_SUB_COMMAND_2
Definition: ftp_client.h:201
error_t ftpClientOpenChannel(FtpClientContext *context, FtpClientChannel *channel, size_t txBufferSize, size_t rxBufferSize)
Open network connection.
String manipulation helper functions.
error_t ftpClientCreateDir(FtpClientContext *context, const char_t *path)
Create a new directory.
Definition: ftp_client.c:1012
error_t ftpClientReadChannel(FtpClientChannel *channel, void *data, size_t size, size_t *received, uint_t flags)
Receive data using the relevant transport protocol.
@ FTP_FILE_MODE_APPEND
Definition: ftp_client.h:158
#define FTP_REPLY_CODE_3YZ(code)
Definition: ftp_client.h:122
@ ERROR_WOULD_BLOCK
Definition: error.h:96
error_t ftpClientLoginEx(FtpClientContext *context, const char_t *username, const char_t *password, const char_t *account)
Login to the FTP server using user name, password and account.
Definition: ftp_client.c:391
IP network address.
Definition: ip.h:90
error_t ftpClientCheckTimeout(FtpClientContext *context)
Determine whether a timeout error has occurred.
#define FTP_CLIENT_BUFFER_SIZE
Definition: ftp_client.h:61
@ FTP_CLIENT_STATE_DISCONNECTING_2
Definition: ftp_client.h:212
uint_t ftpClientGetReplyCode(FtpClientContext *context)
Retrieve server's reply code.
Definition: ftp_client.c:1632
void strRemoveTrailingSpace(char_t *s)
Removes all trailing whitespace from a string.
Definition: str.c:119
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
#define FTP_REPLY_CODE_2YZ(code)
Definition: ftp_client.h:121
@ FTP_CLIENT_STATE_DISCONNECTED
Definition: ftp_client.h:195
error_t ftpClientReadFile(FtpClientContext *context, void *data, size_t size, size_t *received, uint_t flags)
Read from a remote file.
Definition: ftp_client.c:1386
@ FTP_FILE_MODE_TEXT
Definition: ftp_client.h:160
@ FTP_MODE_IMPLICIT_TLS
Definition: ftp_client.h:143
error_t ftpClientRegisterTlsInitCallback(FtpClientContext *context, FtpClientTlsInitCallback callback)
Register TLS initialization callback function.
Definition: ftp_client.c:100
#define osStrcmp(s1, s2)
Definition: os_port.h:174
@ FTP_CLIENT_STATE_SUB_COMMAND_4
Definition: ftp_client.h:203
error_t ftpClientShutdownChannel(FtpClientChannel *channel)
Shutdown network connection.
error_t ftpClientConnect(FtpClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort, uint_t mode)
Establish a connection with the specified FTP server.
Definition: ftp_client.c:169
@ FTP_CLIENT_STATE_WRITING_DATA
Definition: ftp_client.h:209
@ FTP_CLIENT_STATE_CONNECTED
Definition: ftp_client.h:199
void tlsFreeSessionState(TlsSessionState *session)
Properly dispose a session state.
Definition: tls.c:2871
error_t ftpClientCloseDir(FtpClientContext *context)
Close directory.
Definition: ftp_client.c:994
@ ERROR_WRONG_STATE
Definition: error.h:210
@ FTP_CLIENT_STATE_DISCONNECTING_1
Definition: ftp_client.h:211
#define FTP_CLIENT_TLS_TX_BUFFER_SIZE
Definition: ftp_client.h:82
error_t ftpClientClose(FtpClientContext *context)
Close the connection with the FTP server.
Definition: ftp_client.c:1748
Helper functions for FTP client.
#define FALSE
Definition: os_port.h:46
error_t ftpClientBindToInterface(FtpClientContext *context, NetInterface *interface)
Bind the FTP client to a particular network interface.
Definition: ftp_client.c:145
@ FTP_CLIENT_STATE_CONNECTING_TLS
Definition: ftp_client.h:198
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:43
#define FTP_CLIENT_MIN_TLS_RX_BUFFER_SIZE
Definition: ftp_client.h:89
error_t ftpClientTerminateDataTransfer(FtpClientContext *context)
Terminate data transfer.
@ FTP_CLIENT_STATE_SUB_COMMAND_8
Definition: ftp_client.h:207
error_t ftpClientCloseFile(FtpClientContext *context)
Close file.
Definition: ftp_client.c:1435
error_t ftpClientWriteFile(FtpClientContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Write to a remote file.
Definition: ftp_client.c:1319
error_t ftpClientDisconnect(FtpClientContext *context)
Gracefully disconnect from the FTP server.
Definition: ftp_client.c:1659
error_t ftpClientDeleteFile(FtpClientContext *context, const char_t *path)
Delete a file.
Definition: ftp_client.c:1559
#define NetInterface
Definition: net.h:36
error_t ftpClientOpenFile(FtpClientContext *context, const char_t *path, uint_t mode)
Open a file for reading, writing, or appending.
Definition: ftp_client.c:1161
error_t ftpClientWriteChannel(FtpClientChannel *channel, const void *data, size_t length, size_t *written, uint_t flags)
Send data using the relevant transport protocol.
error_t ftpClientOpenDir(FtpClientContext *context, const char_t *path)
Open a directory.
Definition: ftp_client.c:769
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1354
@ ERROR_UNEXPECTED_RESPONSE
Definition: error.h:70
uint8_t length
Definition: tcp.h:375
error_t ftpClientInit(FtpClientContext *context)
Initialize FTP client context.
Definition: ftp_client.c:60
@ FTP_CLIENT_STATE_CONNECTING_TCP
Definition: ftp_client.h:197
@ FTP_MODE_EXPLICIT_TLS
Definition: ftp_client.h:144
@ FTP_CLIENT_STATE_SUB_COMMAND_3
Definition: ftp_client.h:202
@ FTP_CLIENT_STATE_SUB_COMMAND_9
Definition: ftp_client.h:208
#define FTP_CLIENT_DEFAULT_TIMEOUT
Definition: ftp_client.h:54
error_t ftpClientGetWorkingDir(FtpClientContext *context, char_t *path, size_t maxLen)
Get current working directory.
Definition: ftp_client.c:541
error_t ftpClientInitDataTransfer(FtpClientContext *context, bool_t direction)
Initiate data transfer.
error_t ftpClientChangeWorkingDir(FtpClientContext *context, const char_t *path)
Change working directory.
Definition: ftp_client.c:621
uint32_t systime_t
System time.
uint8_t flags
Definition: tcp.h:358
FTP client (File Transfer Protocol)
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:55
void ftpClientDeinit(FtpClientContext *context)
Release FTP client context.
Definition: ftp_client.c:1771
#define FTP_CLIENT_MIN_TCP_BUFFER_SIZE
Definition: ftp_client.h:68
error_t ftpClientEstablishSecureChannel(FtpClientChannel *channel)
Establish secure connection.
uint8_t n
#define FtpClientContext
Definition: ftp_client.h:128
error_t ftpClientSetTimeout(FtpClientContext *context, systime_t timeout)
Set communication timeout.
Definition: ftp_client.c:124
error_t ftpClientParseDirEntry(char_t *line, FtpDirEntry *dirEntry)
Parse directory entry.
Transport protocol abstraction layer.
error_t ftpClientReadDir(FtpClientContext *context, FtpDirEntry *dirEntry)
Read an entry from the directory.
Definition: ftp_client.c:899
void ftpClientChangeState(FtpClientContext *context, FtpClientState newState)
Update FTP client state.
@ FTP_FILE_MODE_WRITE
Definition: ftp_client.h:157
@ FTP_CLIENT_STATE_SUB_COMMAND_1
Definition: ftp_client.h:200
error_t(* FtpClientTlsInitCallback)(FtpClientContext *context, TlsContext *tlsContext)
TLS initialization callback function.
Definition: ftp_client.h:223
error_t ftpClientFormatCommand(FtpClientContext *context, const char_t *command, const char_t *argument)
Format FTP command.
Directory entry.
Definition: ftp_client.h:275
error_t ftpClientSendCommand(FtpClientContext *context)
Send FTP command and wait for a reply.
@ FTP_MODE_PASSIVE
Definition: ftp_client.h:146
error_t ftpClientOpenSecureChannel(FtpClientContext *context, FtpClientChannel *channel, size_t txBufferSize, size_t rxBufferSize)
Open secure connection.
@ FTP_CLIENT_STATE_READING_DATA
Definition: ftp_client.h:210
error_t ftpClientDeleteDir(FtpClientContext *context, const char_t *path)
Remove a directory.
Definition: ftp_client.c:1086
@ FTP_CLIENT_STATE_SUB_COMMAND_6
Definition: ftp_client.h:205
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
error_t ftpClientChangeToParentDir(FtpClientContext *context)
Change to parent directory.
Definition: ftp_client.c:695
error_t tlsInitSessionState(TlsSessionState *session)
Initialize session state.
Definition: tls.c:2728
error_t ftpClientParsePwdReply(FtpClientContext *context, char_t *path, size_t maxLen)
Parse PWD response.
@ FTP_CLIENT_STATE_SUB_COMMAND_5
Definition: ftp_client.h:204
@ SOCKET_FLAG_BREAK_CRLF
Definition: socket.h:141
error_t ftpClientRenameFile(FtpClientContext *context, const char_t *oldPath, const char_t *newPath)
Rename a file.
Definition: ftp_client.c:1454
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
@ FTP_CLIENT_STATE_SUB_COMMAND_7
Definition: ftp_client.h:206
@ FTP_CLIENT_STATE_ACCEPTING_TCP
Definition: ftp_client.h:196
void ftpClientCloseChannel(FtpClientChannel *channel)
Close network connection.
systime_t osGetSystemTime(void)
Retrieve system time.