FTP client library for mbed-os
Diff: FTPClient.cpp
- Revision:
- 0:c2da359279a6
- Child:
- 1:e069c405c934
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FTPClient.cpp Wed Feb 07 07:01:38 2018 +0000 @@ -0,0 +1,392 @@ +/* FTP client library + * Copyright (c) 2018 Renesas Electronics Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed.h" +#include "FTPClient.h" + +#define FTP_BUF_SIZE (1460) + +FTPClient::FTPClient(NetworkInterface *net, const char* root) { + _ctr_open = false; + _login = false; + strcpy(_root, root); + p_network = net; + p_ftp_buf = new char[FTP_BUF_SIZE]; +} + +FTPClient::~FTPClient() { + delete [] p_ftp_buf; +} + +bool FTPClient::open(const char* ip_addr, int port, const char* user, const char* pass) { + if (_ctr_open) { + FTPClientControlSock.close(); + } + + FTPClientControlSock.open(p_network); + if (FTPClientControlSock.connect(ip_addr, port) < 0) { + return false; + } + _ctr_open = true; + + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "220", 3) != 0) { + return false; + } + + _login = false; + sprintf(p_ftp_buf, "user %s\r\n", user); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "331", 3) != 0) { + return false; + } + + sprintf(p_ftp_buf, "pass %s\r\n", pass); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "230", 3) != 0) { + return false; + } + _login = true; + return true; +} + +bool FTPClient::quit() { + if (!_login) { + return false; + } + + sprintf(p_ftp_buf, "quit\r\n"); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "250", 3) != 0) { + return false; + } + _login = false; + + FTPClientControlSock.close(); + _ctr_open = false; + return true; +} + +bool FTPClient::get(const char* file_name) { + FILE* fp; + int size; + + if (!_login) { + return false; + } + + if (!open_data_sock()) { + return false; + } + + FTPClientDataSock.set_timeout(500); + sprintf(p_ftp_buf, "retr %s\r\n", file_name); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) { + return false; + } + + sprintf(p_ftp_buf, "%s/%s", _root, file_name); + fp = fopen(p_ftp_buf, "w"); + while (1) { + size = FTPClientDataSock.recv(p_ftp_buf, FTP_BUF_SIZE); + if (size > 0) { + fwrite(p_ftp_buf, size, sizeof(char), fp); + } else { + break; + } + } + fclose(fp); + FTPClientDataSock.close(); + + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "226", 3) != 0) { + return false; + } + return true; +} + +bool FTPClient::put(const char* file_name) { + FILE* fp; + int32_t remain_size; + int32_t send_size; + + if (!_login) { + return false; + } + + if (!open_data_sock()) { + return false; + } + + FTPClientDataSock.set_timeout(osWaitForever); + sprintf(p_ftp_buf, "stor %s\r\n", file_name); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) { + return false; + } + + sprintf(p_ftp_buf, "%s/%s", _root, file_name); + fp = fopen(p_ftp_buf, "r"); + fseek(fp, 0, SEEK_END); + remain_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + while (remain_size > 0) { + if (remain_size > FTP_BUF_SIZE) { + send_size = FTP_BUF_SIZE; + } else { + send_size = remain_size; + } + fread(p_ftp_buf, 1, send_size, fp); + FTPClientDataSock.send(p_ftp_buf, send_size); + remain_size -= send_size; + } + fclose(fp); + FTPClientDataSock.close(); + + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "226", 3) != 0) { + return false; + } + return true; +} + +bool FTPClient::del(const char* file_name) { + if (!_login) { + return false; + } + + sprintf(p_ftp_buf, "dele %s\r\n", file_name); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "250", 3) != 0) { + return false; + } + + return true; +} + +bool FTPClient::mkdir(const char* dir_name) { + if (!_login) { + return false; + } + + sprintf(p_ftp_buf, "xmkd %s\r\n", dir_name); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "257", 3) != 0) { + return false; + } + + return true; +} + +bool FTPClient::cd(const char* dir_name) { + if (!_login) { + return false; + } + + sprintf(p_ftp_buf, "cwd %s\r\n", dir_name); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "250", 3) != 0) { + return false; + } + + return true; +} + +bool FTPClient::dir(char* list_buf, int buf_size) { + int size; + int idx = 0; + int remain_size = buf_size - 1; + + if (list_buf == NULL) { + return false; + } + list_buf[0] = '\0'; + + if (!_login) { + return false; + } + + if (!open_data_sock()) { + return false; + } + + FTPClientDataSock.set_timeout(500); + sprintf(p_ftp_buf, "list\r\n"); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) { + return false; + } + + while (remain_size > 0) { + size = FTPClientDataSock.recv(p_ftp_buf, FTP_BUF_SIZE); + if (size > 0) { + if (size > remain_size) { + size = remain_size; + } + memcpy(&list_buf[idx], p_ftp_buf, size); + idx += size; + remain_size -= size; + } else { + break; + } + } + list_buf[idx] = '\0'; + FTPClientDataSock.close(); + + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "226", 3) != 0) { + return false; + } + return true; +} + +bool FTPClient::ls(char* list_buf, int buf_size) { + int size; + int idx = 0; + int remain_size = buf_size - 1; + + if (list_buf == NULL) { + return false; + } + list_buf[0] = '\0'; + + if (!_login) { + return false; + } + + if (!open_data_sock()) { + return false; + } + + FTPClientDataSock.set_timeout(500); + sprintf(p_ftp_buf, "nlst\r\n"); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if ((strncmp(p_ftp_buf, "150", 3) != 0) && (strncmp(p_ftp_buf, "125", 3) != 0)) { + return false; + } + + while (remain_size > 0) { + size = FTPClientDataSock.recv(p_ftp_buf, FTP_BUF_SIZE); + if (size > 0) { + if (size > remain_size) { + size = remain_size; + } + memcpy(&list_buf[idx], p_ftp_buf, size); + idx += size; + remain_size -= size; + } else { + break; + } + } + list_buf[idx] = '\0'; + FTPClientDataSock.close(); + + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "226", 3) != 0) { + return false; + } + return true; +} + +bool FTPClient::open_data_sock() { + uint8_t ip_addr[4]; + int i; + int remote_port = 0; + char* token = NULL; + char* savept = NULL; + + sprintf(p_ftp_buf, "pasv\r\n"); + FTPClientControlSock.send(p_ftp_buf, strlen(p_ftp_buf)); + if (FTPClientControlSock.recv(p_ftp_buf, FTP_BUF_SIZE) <= 0) { + return false; + } + if (strncmp(p_ftp_buf, "227", 3) != 0) { + return false; + } + + token = strchr(p_ftp_buf, '(') + 1; + for (i = 0; i < 4; i++) { + token = strtok_r(token, ",", &savept); + ip_addr[i] = (uint8_t)atoi(token); + token = savept; + if (token == NULL) { + return false; + } + } + + for (i = 0; i < 2; i++) { + token = strtok_r(token, ",)", &savept); + remote_port <<= 8; + remote_port += atoi(token); + token = savept; + if (token == NULL) { + return false; + } + } + sprintf(ftp_data_ip_addr, "%d.%d.%d.%d", ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]); + + FTPClientDataSock.open(p_network); + for (i = 0; i < 20; i++) { + if (FTPClientDataSock.connect(ftp_data_ip_addr, remote_port) >= 0) { + return true; + } + wait(1); + } + return false; +} +