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-2019 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 1.9.6
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  memset(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(!strcmp(path, "."))
837  ftpClientFormatCommand(context, "LIST", NULL);
838  else
839  ftpClientFormatCommand(context, "LIST", path);
840 
841  //Check status code
842  if(!error)
843  {
844  //Send LIST command and wait for the server's response
846  }
847  }
848  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_9)
849  {
850  //Flush buffer
851  context->bufferPos = 0;
852  context->commandLen = 0;
853  context->replyLen = 0;
854 
855  //The content of the directory can be transferred via the data
856  //connection
858 
859  //We are done
860  break;
861  }
862  else
863  {
864  //Invalid state
865  error = ERROR_WRONG_STATE;
866  }
867  }
868 
869  //Check status code
870  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
871  {
872  //Check whether the timeout has elapsed
873  error = ftpClientCheckTimeout(context);
874  }
875 
876  //Failed to open directory?
877  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
878  {
879  //Close data connection
880  ftpClientCloseChannel(&context->dataChannel);
881  //Update FTP client state
883  }
884 
885  //Return status code
886  return error;
887 }
888 
889 
890 /**
891  * @brief Read an entry from the directory
892  * @param[in] context Pointer to the FTP client context
893  * @param[out] dirEntry Pointer to a directory entry
894  * @return Error code
895  **/
896 
898 {
899  error_t error;
900  size_t n;
901 
902  //Check parameters
903  if(context == NULL || dirEntry == NULL)
905 
906  //Initialize status code
907  error = NO_ERROR;
908 
909  //Erase the contents of the entry
910  memset(dirEntry, 0, sizeof(FtpDirEntry));
911 
912  //Check current state
913  if(context->state == FTP_CLIENT_STATE_READING_DATA)
914  {
915  //Loop through directory entries
916  while(!error)
917  {
918  //Determine whether more data should be collected
919  if(context->replyLen < (FTP_CLIENT_BUFFER_SIZE - 1))
920  {
921  //Receive data from the FTP server
922  error = ftpClientReadChannel(&context->dataChannel,
923  context->buffer + context->replyLen,
924  FTP_CLIENT_BUFFER_SIZE - 1 - context->replyLen,
926 
927  //Check status code
928  if(error == NO_ERROR)
929  {
930  //Advance data pointer
931  context->replyLen += n;
932 
933  //Check whether the string is terminated by a CRLF sequence
934  if(context->replyLen != 0 &&
935  context->buffer[context->replyLen - 1] == '\n')
936  {
937  //Save current time
938  context->timestamp = osGetSystemTime();
939 
940  //Properly terminate the string with a NULL character
941  context->buffer[context->replyLen] = '\0';
942  //Flush buffer
943  context->replyLen = 0;
944 
945  //Remove trailing whitespace characters
946  strRemoveTrailingSpace(context->buffer);
947 
948  //Discard empty lines
949  if(context->buffer[0] != '\0')
950  {
951  //Parse current directory entry
952  error = ftpClientParseDirEntry(context->buffer, dirEntry);
953  //We are done
954  break;
955  }
956  }
957  }
958  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
959  {
960  //Check whether the timeout has elapsed
961  error = ftpClientCheckTimeout(context);
962  }
963  else
964  {
965  //Communication error
966  }
967  }
968  else
969  {
970  //Flush buffer
971  context->replyLen = 0;
972  }
973  }
974  }
975  else
976  {
977  //Invalid state
978  error = ERROR_WRONG_STATE;
979  }
980 
981  //Return status code
982  return error;
983 }
984 
985 
986 /**
987  * @brief Close directory
988  * @param[in] context Pointer to the FTP client context
989  * @return Error code
990  **/
991 
993 {
994  //Make sure the FTP client context is valid
995  if(context == NULL)
997 
998  //Close data connection and get transfer status
999  return ftpClientTerminateDataTransfer(context);
1000 }
1001 
1002 
1003 /**
1004  * @brief Create a new directory
1005  * @param[in] context Pointer to the FTP client context
1006  * @param[in] path Name of the new directory
1007  * @return Error code
1008  **/
1009 
1011 {
1012  error_t error;
1013 
1014  //Check parameters
1015  if(context == NULL || path == NULL)
1016  return ERROR_INVALID_PARAMETER;
1017 
1018  //Initialize status code
1019  error = NO_ERROR;
1020 
1021  //Execute FTP command
1022  while(!error)
1023  {
1024  //Check current state
1025  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1026  {
1027  //Format MKD command
1028  error = ftpClientFormatCommand(context, "MKD", path);
1029 
1030  //Check status code
1031  if(!error)
1032  {
1033  //Send MKD command and wait for the server's response
1035  }
1036  }
1037  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1038  {
1039  //Send MKD command and wait for the server's response
1040  error = ftpClientSendCommand(context);
1041 
1042  //Check status code
1043  if(!error)
1044  {
1045  //Check FTP response code
1046  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1047  {
1048  //Report an error
1049  error = ERROR_UNEXPECTED_RESPONSE;
1050  }
1051 
1052  //Update FTP client state
1054  //We are done
1055  break;
1056  }
1057  }
1058  else
1059  {
1060  //Invalid state
1061  error = ERROR_WRONG_STATE;
1062  }
1063  }
1064 
1065  //Check status code
1066  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1067  {
1068  //Check whether the timeout has elapsed
1069  error = ftpClientCheckTimeout(context);
1070  }
1071 
1072  //Return status code
1073  return error;
1074 }
1075 
1076 
1077 /**
1078  * @brief Remove a directory
1079  * @param[in] context Pointer to the FTP client context
1080  * @param[in] path Path to the directory to be removed
1081  * @return Error code
1082  **/
1083 
1085 {
1086  error_t error;
1087 
1088  //Check parameters
1089  if(context == NULL || path == NULL)
1090  return ERROR_INVALID_PARAMETER;
1091 
1092  //Initialize status code
1093  error = NO_ERROR;
1094 
1095  //Execute FTP command
1096  while(!error)
1097  {
1098  //Check current state
1099  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1100  {
1101  //Format RMD command
1102  error = ftpClientFormatCommand(context, "RMD", path);
1103 
1104  //Check status code
1105  if(!error)
1106  {
1107  //Send RMD command and wait for the server's response
1109  }
1110  }
1111  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1112  {
1113  //Send RMD command and wait for the server's response
1114  error = ftpClientSendCommand(context);
1115 
1116  //Check status code
1117  if(!error)
1118  {
1119  //Check FTP response code
1120  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1121  {
1122  //Report an error
1123  error = ERROR_UNEXPECTED_RESPONSE;
1124  }
1125 
1126  //Update FTP client state
1128  //We are done
1129  break;
1130  }
1131  }
1132  else
1133  {
1134  //Invalid state
1135  error = ERROR_WRONG_STATE;
1136  }
1137  }
1138 
1139  //Check status code
1140  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1141  {
1142  //Check whether the timeout has elapsed
1143  error = ftpClientCheckTimeout(context);
1144  }
1145 
1146  //Return status code
1147  return error;
1148 }
1149 
1150 
1151 /**
1152  * @brief Open a file for reading, writing, or appending
1153  * @param[in] context Pointer to the FTP client context
1154  * @param[in] path Path to the file to be be opened
1155  * @param[in] mode File access mode
1156  * @return Error code
1157  **/
1158 
1160  uint_t mode)
1161 {
1162  error_t error;
1163 
1164  //Check parameters
1165  if(context == NULL || path == NULL)
1166  return ERROR_INVALID_PARAMETER;
1167 
1168  //Initialize status code
1169  error = NO_ERROR;
1170 
1171  //Execute FTP command sequence
1172  while(!error)
1173  {
1174  //Check current state
1175  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1176  {
1177  //Set representation type
1178  if(mode & FTP_FILE_MODE_TEXT)
1179  {
1180  //Use ASCII type
1181  error = ftpClientFormatCommand(context, "TYPE", "A");
1182  }
1183  else
1184  {
1185  //Use image type
1186  error = ftpClientFormatCommand(context, "TYPE", "I");
1187  }
1188 
1189  //Check status code
1190  if(!error)
1191  {
1192  //Send TYPE command and wait for the server's response
1194  }
1195  }
1196  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1197  {
1198  //Send TYPE command and wait for the server's response
1199  error = ftpClientSendCommand(context);
1200 
1201  //Check status code
1202  if(!error)
1203  {
1204  //Check FTP response code
1205  if(FTP_REPLY_CODE_2YZ(context->replyCode))
1206  {
1207  //Update FTP client state
1209  }
1210  else
1211  {
1212  //Report an error
1213  error = ERROR_UNEXPECTED_RESPONSE;
1214  }
1215  }
1216  }
1217  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2 ||
1218  context->state == FTP_CLIENT_STATE_SUB_COMMAND_3 ||
1219  context->state == FTP_CLIENT_STATE_SUB_COMMAND_4 ||
1220  context->state == FTP_CLIENT_STATE_SUB_COMMAND_5 ||
1221  context->state == FTP_CLIENT_STATE_SUB_COMMAND_6 ||
1222  context->state == FTP_CLIENT_STATE_CONNECTING_TCP ||
1223  context->state == FTP_CLIENT_STATE_SUB_COMMAND_8 ||
1224  context->state == FTP_CLIENT_STATE_ACCEPTING_TCP ||
1225  context->state == FTP_CLIENT_STATE_CONNECTING_TLS)
1226  {
1227  //Initiate data transfer
1229  error = ftpClientInitDataTransfer(context, TRUE);
1230  else
1231  error = ftpClientInitDataTransfer(context, FALSE);
1232  }
1233  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_7)
1234  {
1235  //Format STOR/APPE/RETR command
1237  ftpClientFormatCommand(context, "STOR", path);
1238  else if(mode & FTP_FILE_MODE_APPEND)
1239  ftpClientFormatCommand(context, "APPE", path);
1240  else
1241  ftpClientFormatCommand(context, "RETR", path);
1242 
1243  //Check status code
1244  if(!error)
1245  {
1246  //Send STOR/APPE/RETR command and wait for the server's response
1248  }
1249  }
1250  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_9)
1251  {
1252  //Check data transfer direction
1254  {
1255  //The content of the file can be written via the data connection
1257  }
1258  else
1259  {
1260  //The content of the file can be read via the data connection
1262  }
1263 
1264  //We are done
1265  break;
1266  }
1267  else
1268  {
1269  //Invalid state
1270  error = ERROR_WRONG_STATE;
1271  }
1272  }
1273 
1274  //Check status code
1275  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1276  {
1277  //Check whether the timeout has elapsed
1278  error = ftpClientCheckTimeout(context);
1279  }
1280 
1281  //Failed to open file?
1282  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
1283  {
1284  //Close data connection
1285  ftpClientCloseChannel(&context->dataChannel);
1286  //Update FTP client state
1288  }
1289 
1290  //Return status code
1291  return error;
1292 }
1293 
1294 
1295 /**
1296  * @brief Write to a remote file
1297  * @param[in] context Pointer to the FTP client context
1298  * @param[in] data Pointer to a buffer containing the data to be written
1299  * @param[in] length Number of data bytes to write
1300  * @param[in] written Number of bytes that have been written (optional parameter)
1301  * @param[in] flags Set of flags that influences the behavior of this function
1302  * @return Error code
1303  **/
1304 
1306  size_t length, size_t *written, uint_t flags)
1307 {
1308  error_t error;
1309  size_t n;
1310 
1311  //Make sure the FTP client context is valid
1312  if(context == NULL)
1313  return ERROR_INVALID_PARAMETER;
1314 
1315  //Check parameters
1316  if(data == NULL && length != 0)
1317  return ERROR_INVALID_PARAMETER;
1318 
1319  //Actual number of bytes written
1320  n = 0;
1321 
1322  //Check current state
1323  if(context->state == FTP_CLIENT_STATE_WRITING_DATA)
1324  {
1325  //Transmit data to the FTP server
1326  error = ftpClientWriteChannel(&context->dataChannel, data, length, &n,
1327  flags);
1328 
1329  //Check status code
1330  if(error == NO_ERROR || error == ERROR_TIMEOUT)
1331  {
1332  //Any data transmitted?
1333  if(n > 0)
1334  {
1335  //Save current time
1336  context->timestamp = osGetSystemTime();
1337  }
1338  }
1339  }
1340  else
1341  {
1342  //Invalid state
1343  error = ERROR_WRONG_STATE;
1344  }
1345 
1346  //Check status code
1347  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1348  {
1349  //Check whether the timeout has elapsed
1350  error = ftpClientCheckTimeout(context);
1351  }
1352 
1353  //Total number of data that have been written
1354  if(written != NULL)
1355  *written = n;
1356 
1357  //Return status code
1358  return error;
1359 }
1360 
1361 
1362 /**
1363  * @brief Read from a remote file
1364  * @param[in] context Pointer to the FTP client context
1365  * @param[out] data Buffer where to store the incoming data
1366  * @param[in] size Maximum number of bytes that can be read
1367  * @param[out] received Actual number of bytes that have been read
1368  * @param[in] flags Set of flags that influences the behavior of this function
1369  * @return Error code
1370  **/
1371 
1372 error_t ftpClientReadFile(FtpClientContext *context, void *data, size_t size,
1373  size_t *received, uint_t flags)
1374 {
1375  error_t error;
1376 
1377  //Check parameters
1378  if(context == NULL || data == NULL || received == NULL)
1379  return ERROR_INVALID_PARAMETER;
1380 
1381  //Check current state
1382  if(context->state == FTP_CLIENT_STATE_READING_DATA)
1383  {
1384  //Receive data from the FTP server
1385  error = ftpClientReadChannel(&context->dataChannel, data, size,
1386  received, flags);
1387 
1388  //Check status code
1389  if(error == NO_ERROR)
1390  {
1391  //Save current time
1392  context->timestamp = osGetSystemTime();
1393  }
1394  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1395  {
1396  //Check whether the timeout has elapsed
1397  error = ftpClientCheckTimeout(context);
1398  }
1399  else
1400  {
1401  //Communication error
1402  }
1403  }
1404  else
1405  {
1406  //Invalid state
1407  error = ERROR_WRONG_STATE;
1408  }
1409 
1410  //Return status code
1411  return error;
1412 }
1413 
1414 
1415 /**
1416  * @brief Close file
1417  * @param[in] context Pointer to the FTP client context
1418  * @return Error code
1419  **/
1420 
1422 {
1423  //Make sure the FTP client context is valid
1424  if(context == NULL)
1425  return ERROR_INVALID_PARAMETER;
1426 
1427  //Close data connection and get transfer status
1428  return ftpClientTerminateDataTransfer(context);
1429 }
1430 
1431 
1432 /**
1433  * @brief Rename a file
1434  * @param[in] context Pointer to the FTP client context
1435  * @param[in] oldPath Name of an existing file or directory
1436  * @param[in] newPath New name for the file or directory
1437  * @return Error code
1438  **/
1439 
1441  const char_t *newPath)
1442 {
1443  error_t error;
1444 
1445  //Check parameters
1446  if(context == NULL || oldPath == NULL || newPath == NULL)
1447  return ERROR_INVALID_PARAMETER;
1448 
1449  //Initialize status code
1450  error = NO_ERROR;
1451 
1452  //Execute FTP command sequence
1453  while(!error)
1454  {
1455  //Check current state
1456  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1457  {
1458  //Format RNFR command
1459  error = ftpClientFormatCommand(context, "RNFR", oldPath);
1460 
1461  //Check status code
1462  if(!error)
1463  {
1464  //Send USER command and wait for the server's response
1466  }
1467  }
1468  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1469  {
1470  //Send RNFR command and wait for the server's response
1471  error = ftpClientSendCommand(context);
1472 
1473  //Check status code
1474  if(!error)
1475  {
1476  //Check FTP response code
1477  if(FTP_REPLY_CODE_3YZ(context->replyCode))
1478  {
1479  //Format RNTO command
1480  error = ftpClientFormatCommand(context, "RNTO", newPath);
1481 
1482  //Check status code
1483  if(!error)
1484  {
1485  //Send RNTO command and wait for the server's response
1487  }
1488  }
1489  else
1490  {
1491  //Update FTP client state
1493  //Report an error
1494  error = ERROR_UNEXPECTED_RESPONSE;
1495  }
1496  }
1497  }
1498  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_2)
1499  {
1500  //Send RNTO command and wait for the server's response
1501  error = ftpClientSendCommand(context);
1502 
1503  //Check status code
1504  if(!error)
1505  {
1506  //Check FTP response code
1507  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1508  {
1509  //Report an error
1510  error = ERROR_UNEXPECTED_RESPONSE;
1511  }
1512 
1513  //Update FTP client state
1515  //We are done
1516  break;
1517  }
1518  }
1519  else
1520  {
1521  //Invalid state
1522  error = ERROR_WRONG_STATE;
1523  }
1524  }
1525 
1526  //Check status code
1527  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1528  {
1529  //Check whether the timeout has elapsed
1530  error = ftpClientCheckTimeout(context);
1531  }
1532 
1533  //Return status code
1534  return error;
1535 }
1536 
1537 
1538 /**
1539  * @brief Delete a file
1540  * @param[in] context Pointer to the FTP client context
1541  * @param[in] path Path to the file to be be deleted
1542  * @return Error code
1543  **/
1544 
1546 {
1547  error_t error;
1548 
1549  //Check parameters
1550  if(context == NULL || path == NULL)
1551  return ERROR_INVALID_PARAMETER;
1552 
1553  //Initialize status code
1554  error = NO_ERROR;
1555 
1556  //Execute FTP command
1557  while(!error)
1558  {
1559  //Check current state
1560  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1561  {
1562  //Format DELE command
1563  error = ftpClientFormatCommand(context, "DELE", path);
1564 
1565  //Check status code
1566  if(!error)
1567  {
1568  //Send DELE command and wait for the server's response
1570  }
1571  }
1572  else if(context->state == FTP_CLIENT_STATE_SUB_COMMAND_1)
1573  {
1574  //Send DELE command and wait for the server's response
1575  error = ftpClientSendCommand(context);
1576 
1577  //Check status code
1578  if(!error)
1579  {
1580  //Check FTP response code
1581  if(!FTP_REPLY_CODE_2YZ(context->replyCode))
1582  {
1583  //Report an error
1584  error = ERROR_UNEXPECTED_RESPONSE;
1585  }
1586 
1587  //Update FTP client state
1589  //We are done
1590  break;
1591  }
1592  }
1593  else
1594  {
1595  //Invalid state
1596  error = ERROR_WRONG_STATE;
1597  }
1598  }
1599 
1600  //Check status code
1601  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1602  {
1603  //Check whether the timeout has elapsed
1604  error = ftpClientCheckTimeout(context);
1605  }
1606 
1607  //Return status code
1608  return error;
1609 }
1610 
1611 
1612 /**
1613  * @brief Retrieve server's reply code
1614  * @param[in] context Pointer to the FTP client context
1615  * @return FTP reply code
1616  **/
1617 
1619 {
1620  uint_t replyCode;
1621 
1622  //Make sure the FTP client context is valid
1623  if(context != NULL)
1624  {
1625  //Get server's reply code
1626  replyCode = context->replyCode;
1627  }
1628  else
1629  {
1630  //The FTP client context is not valid
1631  replyCode = 0;
1632  }
1633 
1634  //Return FTP reply code
1635  return replyCode;
1636 }
1637 
1638 
1639 /**
1640  * @brief Gracefully disconnect from the FTP server
1641  * @param[in] context Pointer to the FTP client context
1642  * @return Error code
1643  **/
1644 
1646 {
1647  error_t error;
1648 
1649  //Make sure the FTP client context is valid
1650  if(context == NULL)
1651  return ERROR_INVALID_PARAMETER;
1652 
1653  //Initialize status code
1654  error = NO_ERROR;
1655 
1656  //Execute FTP command sequence
1657  while(!error)
1658  {
1659  //Check current state
1660  if(context->state == FTP_CLIENT_STATE_CONNECTED)
1661  {
1662  //Update FTP client state
1664  }
1665  else if(context->state == FTP_CLIENT_STATE_DISCONNECTING_1)
1666  {
1667  //Shutdown data connection
1668  error = ftpClientShutdownChannel(&context->dataChannel);
1669 
1670  //Check status code
1671  if(!error)
1672  {
1673  //Close data connection
1674  ftpClientCloseChannel(&context->dataChannel);
1675  //Update FTP client state
1677  }
1678  }
1679  else if(context->state == FTP_CLIENT_STATE_DISCONNECTING_2)
1680  {
1681  //Shutdown control connection
1682  error = ftpClientShutdownChannel(&context->controlChannel);
1683 
1684  //Check status code
1685  if(!error)
1686  {
1687  //Close control connection
1688  ftpClientCloseChannel(&context->controlChannel);
1689  //Update FTP client state
1691  }
1692  }
1693  else if(context->state == FTP_CLIENT_STATE_DISCONNECTED)
1694  {
1695  //We are done
1696  break;
1697  }
1698  else
1699  {
1700  //Invalid state
1701  error = ERROR_WRONG_STATE;
1702  }
1703  }
1704 
1705  //Check status code
1706  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1707  {
1708  //Check whether the timeout has elapsed
1709  error = ftpClientCheckTimeout(context);
1710  }
1711 
1712  //Failed to gracefully disconnect from the FTP server?
1713  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
1714  {
1715  //Close data and control connections
1716  ftpClientCloseChannel(&context->dataChannel);
1717  ftpClientCloseChannel(&context->controlChannel);
1718 
1719  //Update FTP client state
1721  }
1722 
1723  //Return status code
1724  return error;
1725 }
1726 
1727 
1728 /**
1729  * @brief Close the connection with the FTP server
1730  * @param[in] context Pointer to the FTP client context
1731  * @return Error code
1732  **/
1733 
1735 {
1736  //Make sure the FTP client context is valid
1737  if(context == NULL)
1738  return ERROR_INVALID_PARAMETER;
1739 
1740  //Close data and control connections
1741  ftpClientCloseChannel(&context->dataChannel);
1742  ftpClientCloseChannel(&context->controlChannel);
1743 
1744  //Update FTP client state
1746 
1747  //Successful processing
1748  return NO_ERROR;
1749 }
1750 
1751 
1752 /**
1753  * @brief Release FTP client context
1754  * @param[in] context Pointer to the FTP client context
1755  **/
1756 
1758 {
1759  //Make sure the FTP client context is valid
1760  if(context != NULL)
1761  {
1762  //Close data and control connections
1763  ftpClientCloseChannel(&context->dataChannel);
1764  ftpClientCloseChannel(&context->controlChannel);
1765 
1766 #if (FTP_CLIENT_TLS_SUPPORT == ENABLED)
1767  //Release TLS session state
1768  tlsFreeSessionState(&context->tlsSession);
1769 #endif
1770 
1771  //Clear FTP client context
1772  memset(context, 0, sizeof(FtpClientContext));
1773  }
1774 }
1775 
1776 #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: dtls_misc.h:149
@ 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:1010
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
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:71
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:1618
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:1372
@ 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
@ 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:2711
error_t ftpClientCloseDir(FtpClientContext *context)
Close directory.
Definition: ftp_client.c:992
@ ERROR_WRONG_STATE
Definition: error.h:207
@ 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:1734
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:42
#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:1421
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:1305
error_t ftpClientDisconnect(FtpClientContext *context)
Gracefully disconnect from the FTP server.
Definition: ftp_client.c:1645
error_t ftpClientDeleteFile(FtpClientContext *context, const char_t *path)
Delete a file.
Definition: ftp_client.c:1545
#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:1159
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:381
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:314
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:1757
#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:897
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:268
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:1084
@ FTP_CLIENT_STATE_SUB_COMMAND_6
Definition: ftp_client.h:200
unsigned int uint_t
Definition: compiler_port.h:45
uint8_t data[]
Definition: dtls_misc.h:176
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:2406
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:123
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:1440
@ 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.