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