FTP client library for mbed-os

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FTPClient.cpp Source File

FTPClient.cpp

00001 /* FTP client library
00002  * Copyright (c) 2018 Renesas Electronics Corporation
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed.h"
00018 #include "FTPClient.h"
00019 
00020 #define FTP_BUF_SIZE     (1460)
00021 
00022 //#define ftp_debug_print  printf
00023 
00024 #ifndef ftp_debug_print
00025 static int ftp_debug_print(const char *format, ...) {
00026     return 0;
00027 }
00028 #endif
00029 
00030 FTPClient::FTPClient(NetworkInterface *net, const char* root) {
00031     _ctr_open = false;
00032     _login = false;
00033     strcpy(_root, root);
00034     p_network = net;
00035     p_ftp_buf = new char[FTP_BUF_SIZE];
00036 }
00037 
00038 FTPClient::~FTPClient() {
00039     delete [] p_ftp_buf;
00040 }
00041 
00042 bool FTPClient::open(const char* ip_addr, int port, const char* user, const char* pass) {
00043     if (_ctr_open) {
00044         FTPClientControlSock.close();
00045     }
00046 
00047     FTPClientControlSock.open(p_network);
00048     if (FTPClientControlSock.connect(ip_addr, port) < 0) {
00049         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00050         return false;
00051     }
00052     _ctr_open = true;
00053 
00054     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00055         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00056         return false;
00057     }
00058     if (strncmp(p_ftp_buf, "220", 3) != 0) {
00059         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00060         return false;
00061     }
00062 
00063     _login = false;
00064     sprintf(p_ftp_buf, "user %s\r\n", user);
00065     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00066     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00067         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00068         return false;
00069     }
00070     if (strncmp(p_ftp_buf, "331", 3) != 0) {
00071         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00072         return false;
00073     }
00074 
00075     sprintf(p_ftp_buf, "pass %s\r\n", pass);
00076     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00077     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00078         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00079         return false;
00080     }
00081     if (strncmp(p_ftp_buf, "230", 3) != 0) {
00082         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00083         return false;
00084     }
00085 
00086     sprintf(p_ftp_buf, "type I\r\n");
00087     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00088     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00089         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00090         return false;
00091     }
00092 
00093     _login = true;
00094     return true;
00095 }
00096 
00097 bool FTPClient::quit() {
00098     if (!_login) {
00099         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00100         return false;
00101     }
00102 
00103     sprintf(p_ftp_buf, "quit\r\n");
00104     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00105     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00106         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00107         return false;
00108     }
00109     if (strncmp(p_ftp_buf, "250", 3) != 0) {
00110         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00111         return false;
00112     }
00113     _login = false;
00114 
00115     FTPClientControlSock.close();
00116     _ctr_open = false;
00117     return true;
00118 }
00119 
00120 bool FTPClient::get(const char* file_name) {
00121     FILE* fp;
00122     int size;
00123 
00124     if (!_login) {
00125         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00126         return false;
00127     }
00128 
00129     if (!open_data_sock()) {
00130         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00131         return false;
00132     }
00133 
00134     FTPClientDataSock.set_timeout(500);
00135     sprintf(p_ftp_buf, "retr %s\r\n", file_name);
00136     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00137     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00138         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00139         return false;
00140     }
00141     if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) {
00142         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00143         return false;
00144     }
00145 
00146     sprintf(p_ftp_buf, "%s/%s", _root, file_name);
00147     fp = fopen(p_ftp_buf, "w");
00148     while (1) {
00149         size = FTPClientDataSock.recv(p_ftp_buf, FTP_BUF_SIZE);
00150         if (size > 0) {
00151             fwrite(p_ftp_buf, size, sizeof(char), fp);
00152         } else {
00153             break;
00154         }
00155     }
00156     fclose(fp);
00157     FTPClientDataSock.close();
00158 
00159     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00160         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00161         return false;
00162     }
00163     if (strncmp(p_ftp_buf, "226", 3) != 0) {
00164         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00165         return false;
00166     }
00167     return true;
00168 }
00169 
00170 bool FTPClient::put(const char* file_name) {
00171     FILE* fp;
00172     int32_t remain_size;
00173     int32_t send_size;
00174 
00175     if (!_login) {
00176         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00177         return false;
00178     }
00179 
00180     if (!open_data_sock()) {
00181         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00182         return false;
00183     }
00184 
00185     FTPClientDataSock.set_timeout(osWaitForever);
00186     sprintf(p_ftp_buf, "stor %s\r\n", file_name);
00187     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00188     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00189         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00190         return false;
00191     }
00192     if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) {
00193         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00194         return false;
00195     }
00196 
00197     sprintf(p_ftp_buf, "%s/%s", _root, file_name);
00198     fp = fopen(p_ftp_buf, "r"); 
00199     fseek(fp, 0, SEEK_END);
00200     remain_size = ftell(fp);
00201     fseek(fp, 0, SEEK_SET);
00202 
00203     while (remain_size > 0) {
00204         if (remain_size > FTP_BUF_SIZE) {
00205             send_size = FTP_BUF_SIZE;
00206         } else {
00207             send_size = remain_size;
00208         }
00209         fread(p_ftp_buf, 1, send_size, fp);
00210         FTPClientDataSock.send(p_ftp_buf, send_size);
00211         remain_size -= send_size;
00212     }
00213     fclose(fp); 
00214     FTPClientDataSock.close();
00215 
00216     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00217         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00218         return false;
00219     }
00220     if (strncmp(p_ftp_buf, "226", 3) != 0) {
00221         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00222         return false;
00223     }
00224     return true;
00225 }
00226 
00227 bool FTPClient::del(const char* file_name) {
00228     if (!_login) {
00229         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00230         return false;
00231     }
00232 
00233     sprintf(p_ftp_buf, "dele %s\r\n", file_name);
00234     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00235     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00236         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00237         return false;
00238     }
00239     if (strncmp(p_ftp_buf, "250", 3) != 0) {
00240         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00241         return false;
00242     }
00243 
00244     return true;
00245 }
00246 
00247 bool FTPClient::mkdir(const char* dir_name) {
00248     if (!_login) {
00249         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00250         return false;
00251     }
00252 
00253     sprintf(p_ftp_buf, "xmkd %s\r\n", dir_name);
00254     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00255     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00256         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00257         return false;
00258     }
00259     if (strncmp(p_ftp_buf, "257", 3) != 0) {
00260         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00261         return false;
00262     }
00263 
00264     return true;
00265 }
00266 
00267 bool FTPClient::cd(const char* dir_name) {
00268     if (!_login) {
00269         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00270         return false;
00271     }
00272 
00273     sprintf(p_ftp_buf, "cwd %s\r\n", dir_name);
00274     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00275     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00276         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00277         return false;
00278     }
00279     if (strncmp(p_ftp_buf, "250", 3) != 0) {
00280         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00281         return false;
00282     }
00283 
00284     return true;
00285 }
00286 
00287 bool FTPClient::dir(char* list_buf, int buf_size) {
00288     int size;
00289     int idx = 0;
00290     int remain_size = buf_size - 1;
00291 
00292     if (list_buf == NULL) {
00293         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00294         return false;
00295     }
00296     list_buf[0] = '\0';
00297 
00298     if (!_login) {
00299         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00300         return false;
00301     }
00302 
00303     if (!open_data_sock()) {
00304         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00305         return false;
00306     }
00307 
00308     FTPClientDataSock.set_timeout(500);
00309     sprintf(p_ftp_buf, "list\r\n");
00310     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00311     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00312         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00313         return false;
00314     }
00315     if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) {
00316         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00317         return false;
00318     }
00319 
00320     while (remain_size > 0) {
00321         size = FTPClientDataSock.recv(p_ftp_buf, FTP_BUF_SIZE);
00322         if (size > 0) {
00323             if (size > remain_size) {
00324                 size = remain_size;
00325             }
00326             memcpy(&list_buf[idx], p_ftp_buf, size);
00327             idx += size;
00328             remain_size -= size;
00329         } else {
00330             break;
00331         }
00332     }
00333     list_buf[idx] = '\0';
00334     FTPClientDataSock.close();
00335 
00336     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00337         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00338         return false;
00339     }
00340     if (strncmp(p_ftp_buf, "226", 3) != 0) {
00341         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00342         return false;
00343     }
00344     return true;
00345 }
00346 
00347 bool FTPClient::ls(char* list_buf, int buf_size) {
00348     int size;
00349     int idx = 0;
00350     int remain_size = buf_size - 1;
00351 
00352     if (list_buf == NULL) {
00353         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00354         return false;
00355     }
00356     list_buf[0] = '\0';
00357 
00358     if (!_login) {
00359         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00360         return false;
00361     }
00362 
00363     if (!open_data_sock()) {
00364         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00365         return false;
00366     }
00367 
00368     FTPClientDataSock.set_timeout(500);
00369     sprintf(p_ftp_buf, "nlst\r\n");
00370     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00371     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00372         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00373         return false;
00374     }
00375     if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) {
00376         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00377         return false;
00378     }
00379 
00380     while (remain_size > 0) {
00381         size = FTPClientDataSock.recv(p_ftp_buf, FTP_BUF_SIZE);
00382         if (size > 0) {
00383             if (size > remain_size) {
00384                 size = remain_size;
00385             }
00386             memcpy(&list_buf[idx], p_ftp_buf, size);
00387             idx += size;
00388             remain_size -= size;
00389         } else {
00390             break;
00391         }
00392     }
00393     list_buf[idx] = '\0';
00394     FTPClientDataSock.close();
00395 
00396     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00397         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00398         return false;
00399     }
00400     if (strncmp(p_ftp_buf, "226", 3) != 0) {
00401         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00402         return false;
00403     }
00404     return true;
00405 }
00406 
00407 bool FTPClient::open_data_sock() {
00408     uint8_t ip_addr[4];
00409     int i;
00410     int remote_port = 0;
00411     char* token = NULL;
00412     char* savept = NULL;
00413 
00414     sprintf(p_ftp_buf, "pasv\r\n");
00415     FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf));
00416     if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) {
00417         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00418         return false;
00419     }
00420     if (strncmp(p_ftp_buf, "227", 3) != 0) {
00421         ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00422         return false;
00423     }
00424 
00425     token = strchr(p_ftp_buf, '(') + 1;
00426     for (i = 0; i < 4; i++) {
00427         token = strtok_r(token, ",", &savept);
00428         ip_addr[i] = (uint8_t)atoi(token);
00429         token = savept;
00430         if (token == NULL) {
00431             ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00432             return false;
00433         }
00434     }
00435 
00436     for (i = 0; i < 2; i++) {
00437         token = strtok_r(token, ",)", &savept);
00438         remote_port <<= 8;
00439         remote_port += atoi(token);
00440         token = savept;
00441         if (token == NULL) {
00442             ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00443             return false;
00444         }
00445     }
00446     sprintf(ftp_data_ip_addr, "%d.%d.%d.%d", ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]);
00447 
00448     FTPClientDataSock.open(p_network);
00449     for (i = 0; i < 20; i++) {
00450         if (FTPClientDataSock.connect(ftp_data_ip_addr, remote_port) >= 0) {
00451             return true;
00452         }
00453         wait(1);
00454     }
00455     ftp_debug_print("ERROR: %s(%d)\r\n", __FILE__, __LINE__);
00456     return false;
00457 }
00458