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