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.2
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  {
1370  *written = n;
1371  }
1372 
1373  //Return status code
1374  return error;
1375 }
1376 
1377 
1378 /**
1379  * @brief Read from a remote file
1380  * @param[in] context Pointer to the FTP client context
1381  * @param[out] data Buffer where to store the incoming data
1382  * @param[in] size Maximum number of bytes that can be read
1383  * @param[out] received Actual number of bytes that have been read
1384  * @param[in] flags Set of flags that influences the behavior of this function
1385  * @return Error code
1386  **/
1387 
1388 error_t ftpClientReadFile(FtpClientContext *context, void *data, size_t size,
1389  size_t *received, uint_t flags)
1390 {
1391  error_t error;
1392 
1393  //Check parameters
1394  if(context == NULL || data == NULL || received == NULL)
1395  return ERROR_INVALID_PARAMETER;
1396 
1397  //Check current state
1398  if(context->state == FTP_CLIENT_STATE_READING_DATA)
1399  {
1400  //Receive data from the FTP server
1401  error = ftpClientReadChannel(&context->dataChannel, data, size,
1402  received, flags);
1403 
1404  //Check status code
1405  if(error == NO_ERROR)
1406  {
1407  //Save current time
1408  context->timestamp = osGetSystemTime();
1409  }
1410  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1411  {
1412  //Check whether the timeout has elapsed
1413  error = ftpClientCheckTimeout(context);
1414  }
1415  else
1416  {
1417  //Communication error
1418  }
1419  }
1420  else
1421  {
1422  //Invalid state
1423  error = ERROR_WRONG_STATE;
1424  }
1425 
1426  //Return status code
1427  return error;
1428 }
1429 
1430 
1431 /**
1432  * @brief Close file
1433  * @param[in] context Pointer to the FTP client context
1434  * @return Error code
1435  **/
1436 
1438 {
1439  //Make sure the FTP client context is valid
1440  if(context == NULL)
1441  return ERROR_INVALID_PARAMETER;
1442 
1443  //Close data connection and get transfer status
1444  return ftpClientTerminateDataTransfer(context);
1445 }
1446 
1447 
1448 /**
1449  * @brief Rename a file
1450  * @param[in] context Pointer to the FTP client context
1451  * @param[in] oldPath Name of an existing file or directory
1452  * @param[in] newPath New name for the file or directory
1453  * @return Error code
1454  **/
1455 
1457  const char_t *newPath)
1458 {
1459  error_t error;
1460 
1461  //Check parameters
1462  if(context == NULL || oldPath == NULL || newPath == NULL)
1463  return ERROR_INVALID_PARAMETER;
1464 
1465  //Initialize status code
1466  error = NO_ERROR;
1467 
1468  //Execute FTP command sequence
1469  while(!error)
1470  {
1471  //Check current state
1472  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1473  {
1474  //Format RNFR command
1475  error = ftpClientFormatCommand(context, "RNFR", oldPath);
1476 
1477  //Check status code
1478  if(!error)
1479  {
1480  //Send USER command and wait for the server's response
1482  }
1483  }
1484  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1485  {
1486  //Send RNFR command and wait for the server's response
1487  error = ftpClientSendCommand(context);
1488 
1489  //Check status code
1490  if(!error)
1491  {
1492  //Check FTP response code
1493  if(FTP_REPLY_CODE_3YZ(context->replyCode))
1494  {
1495  //Format RNTO command
1496  error = ftpClientFormatCommand(context, "RNTO", newPath);
1497 
1498  //Check status code
1499  if(!error)
1500  {
1501  //Send RNTO command and wait for the server's response
1503  }
1504  }
1505  else
1506  {
1507  //Update FTP client state
1509  //Report an error
1510  error = ERROR_UNEXPECTED_RESPONSE;
1511  }
1512  }
1513  }
1514  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2)
1515  {
1516  //Send RNTO command and wait for the server's response
1517  error = ftpClientSendCommand(context);
1518 
1519  //Check status code
1520  if(!error)
1521  {
1522  //Check FTP response code
1523  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1524  {
1525  //Report an error
1526  error = ERROR_UNEXPECTED_RESPONSE;
1527  }
1528 
1529  //Update FTP client state
1531  //We are done
1532  break;
1533  }
1534  }
1535  else
1536  {
1537  //Invalid state
1538  error = ERROR_WRONG_STATE;
1539  }
1540  }
1541 
1542  //Check status code
1543  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1544  {
1545  //Check whether the timeout has elapsed
1546  error = ftpClientCheckTimeout(context);
1547  }
1548 
1549  //Return status code
1550  return error;
1551 }
1552 
1553 
1554 /**
1555  * @brief Delete a file
1556  * @param[in] context Pointer to the FTP client context
1557  * @param[in] path Path to the file to be be deleted
1558  * @return Error code
1559  **/
1560 
1562 {
1563  error_t error;
1564 
1565  //Check parameters
1566  if(context == NULL || path == NULL)
1567  return ERROR_INVALID_PARAMETER;
1568 
1569  //Initialize status code
1570  error = NO_ERROR;
1571 
1572  //Execute FTP command
1573  while(!error)
1574  {
1575  //Check current state
1576  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1577  {
1578  //Format DELE command
1579  error = ftpClientFormatCommand(context, "DELE", path);
1580 
1581  //Check status code
1582  if(!error)
1583  {
1584  //Send DELE command and wait for the server's response
1586  }
1587  }
1588  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1589  {
1590  //Send DELE command and wait for the server's response
1591  error = ftpClientSendCommand(context);
1592 
1593  //Check status code
1594  if(!error)
1595  {
1596  //Check FTP response code
1597  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1598  {
1599  //Report an error
1600  error = ERROR_UNEXPECTED_RESPONSE;
1601  }
1602 
1603  //Update FTP client state
1605  //We are done
1606  break;
1607  }
1608  }
1609  else
1610  {
1611  //Invalid state
1612  error = ERROR_WRONG_STATE;
1613  }
1614  }
1615 
1616  //Check status code
1617  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1618  {
1619  //Check whether the timeout has elapsed
1620  error = ftpClientCheckTimeout(context);
1621  }
1622 
1623  //Return status code
1624  return error;
1625 }
1626 
1627 
1628 /**
1629  * @brief Retrieve server's reply code
1630  * @param[in] context Pointer to the FTP client context
1631  * @return FTP reply code
1632  **/
1633 
1635 {
1636  uint_t replyCode;
1637 
1638  //Make sure the FTP client context is valid
1639  if(context != NULL)
1640  {
1641  //Get server's reply code
1642  replyCode = context->replyCode;
1643  }
1644  else
1645  {
1646  //The FTP client context is not valid
1647  replyCode = 0;
1648  }
1649 
1650  //Return FTP reply code
1651  return replyCode;
1652 }
1653 
1654 
1655 /**
1656  * @brief Gracefully disconnect from the FTP server
1657  * @param[in] context Pointer to the FTP client context
1658  * @return Error code
1659  **/
1660 
1662 {
1663  error_t error;
1664 
1665  //Make sure the FTP client context is valid
1666  if(context == NULL)
1667  return ERROR_INVALID_PARAMETER;
1668 
1669  //Initialize status code
1670  error = NO_ERROR;
1671 
1672  //Execute FTP command sequence
1673  while(!error)
1674  {
1675  //Check current state
1676  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1677  {
1678  //Update FTP client state
1680  }
1681  else if(context->state == FTP_CLIENT_STATE_DISCONNECTING_1)
1682  {
1683  //Shutdown data connection
1684  error = ftpClientShutdownChannel(&context->dataChannel);
1685 
1686  //Check status code
1687  if(!error)
1688  {
1689  //Close data connection
1690  ftpClientCloseChannel(&context->dataChannel);
1691  //Update FTP client state
1693  }
1694  }
1695  else if(context->state == FTP_CLIENT_STATE_DISCONNECTING_2)
1696  {
1697  //Shutdown control connection
1698  error = ftpClientShutdownChannel(&context->controlChannel);
1699 
1700  //Check status code
1701  if(!error)
1702  {
1703  //Close control connection
1704  ftpClientCloseChannel(&context->controlChannel);
1705  //Update FTP client state
1707  }
1708  }
1709  else if(context->state == FTP_CLIENT_STATE_DISCONNECTED)
1710  {
1711  //We are done
1712  break;
1713  }
1714  else
1715  {
1716  //Invalid state
1717  error = ERROR_WRONG_STATE;
1718  }
1719  }
1720 
1721  //Check status code
1722  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1723  {
1724  //Check whether the timeout has elapsed
1725  error = ftpClientCheckTimeout(context);
1726  }
1727 
1728  //Failed to gracefully disconnect from the FTP server?
1729  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
1730  {
1731  //Close data and control connections
1732  ftpClientCloseChannel(&context->dataChannel);
1733  ftpClientCloseChannel(&context->controlChannel);
1734 
1735  //Update FTP client state
1737  }
1738 
1739  //Return status code
1740  return error;
1741 }
1742 
1743 
1744 /**
1745  * @brief Close the connection with the FTP server
1746  * @param[in] context Pointer to the FTP client context
1747  * @return Error code
1748  **/
1749 
1751 {
1752  //Make sure the FTP client context is valid
1753  if(context == NULL)
1754  return ERROR_INVALID_PARAMETER;
1755 
1756  //Close data and control connections
1757  ftpClientCloseChannel(&context->dataChannel);
1758  ftpClientCloseChannel(&context->controlChannel);
1759 
1760  //Update FTP client state
1762 
1763  //Successful processing
1764  return NO_ERROR;
1765 }
1766 
1767 
1768 /**
1769  * @brief Release FTP client context
1770  * @param[in] context Pointer to the FTP client context
1771  **/
1772 
1774 {
1775  //Make sure the FTP client context is valid
1776  if(context != NULL)
1777  {
1778  //Close data and control connections
1779  ftpClientCloseChannel(&context->dataChannel);
1780  ftpClientCloseChannel(&context->controlChannel);
1781 
1782 #if (FTP_CLIENT_TLS_SUPPORT == ENABLED)
1783  //Release TLS session state
1784  tlsFreeSessionState(&context->tlsSession);
1785 #endif
1786 
1787  //Clear FTP client context
1788  osMemset(context, 0, sizeof(FtpClientContext));
1789  }
1790 }
1791 
1792 #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:1634
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:224
#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:1388
@ 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:2883
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:1750
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:1437
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:1661
error_t ftpClientDeleteFile(FtpClientContext *context, const char_t *path)
Delete a file.
Definition: ftp_client.c:1561
#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:1773
#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:2740
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:1456
@ 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.