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