分享个使用ftpclient实现ota的例子,
默认将文件下载到download分区
#include
#include
#include
#include
#include "netdb.h"
// #include "log.h"
// #include "ftp.h"
#include
#include
#include
#define DRV_DEBUG
#define LOG_TAG "drv.FTP"
#include
static int m_socket_cmd;
static int m_socket_data;
static char m_send_buffer[1024];
static char m_recv_buffer[4096];
static void ftp_quit(void);
static void print_progress(size_t cur_size, size_t total_size);
int socket_connect(int sock, const char *url, int port)
{
struct sockaddr_in server_addr;
struct hostent *host = RT_NULL;
/* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */
host = gethostbyname(url);
if (host == RT_NULL)
{
LOG_E("Get host by name failed!");
return -1;
}
/* 初始化预连接的服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *)host->h_addr);
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* 连接到服务端 */
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
/* 连接失败 */
LOG_E("Connect fail!n");
closesocket(sock);
return -1;
}
return 1;
}
int socket_send(int sock, void *data, int len)
{
return send(sock, (char *)data, len, 0);
}
int socket_recv(int sock, void *data, int len)
{
return recv(sock, (char *)data, len, 0);
}
//命令端口,发送命令
static int ftp_send_command(char *cmd)
{
int ret;
LOG_I("send command: %srn", cmd);
ret = socket_send(m_socket_cmd, cmd, (int)strlen(cmd));
if (ret < 0)
{
LOG_E("failed to send command: %s", cmd);
return 0;
}
return 1;
}
//命令端口,接收应答
static int ftp_recv_respond(char *resp, int len)
{
int ret;
int off;
len -= 1;
for (off = 0; off < len; off += ret)
{
ret = socket_recv(m_socket_cmd, &resp[off], 1);
if (ret < 0)
{
LOG_E("recv respond error(ret=%d)!rn", ret);
return 0;
}
if (resp[off] == 'n')
{
break;
}
}
resp[off + 1] = 0;
LOG_I("respond:%s", resp);
return atoi(resp);
}
//设置FTP服务器为被动模式,并解析数据端口
static int ftp_enter_pasv(char *ipaddr, int *port)
{
int ret;
char *find;
int a, b, c, d;
int pa, pb;
ret = ftp_send_command("PASVrn");
if (ret != 1)
{
return 0;
}
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 227)
{
return 0;
}
find = strrchr(m_recv_buffer, '(');
sscanf(find, "(%d,%d,%d,%d,%d,%d)", &a, &b, &c, &d, &pa, &pb);
sprintf(ipaddr, "%d.%d.%d.%d", a, b, c, d);
*port = pa * 256 + pb;
return 1;
}
//上传文件
int ftp_upload(char *name, void *buf, int len)
{
int ret;
char ipaddr[32];
int port;
//查询数据地址
ret = ftp_enter_pasv(ipaddr, &port);
if (ret != 1)
{
return 0;
}
ret = socket_connect(m_socket_data, ipaddr, port);
if (ret != 1)
{
return 0;
}
//准备上传
sprintf(m_send_buffer, "STOR %srn", name);
ret = ftp_send_command(m_send_buffer);
if (ret != 1)
{
return 0;
}
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 150)
{
closesocket(m_socket_data);
return 0;
}
//开始上传
ret = socket_send(m_socket_data, buf, len);
if (ret != len)
{
LOG_E("send data error!rn");
closesocket(m_socket_data);
return 0;
}
closesocket(m_socket_data);
//上传完成,等待回应
ret = ftp_recv_respond(m_recv_buffer, 1024);
return (ret == 226);
}
//下载文件
int ftp_download(char *name, int len)
{
int i;
int ret;
char ipaddr[32];
int port;
int curlen = 0;
rt_uint32_t tick = 0;
const struct fal_partition *dl_part = RT_NULL;
//查询数据地址
ret = ftp_enter_pasv(ipaddr, &port);
if (ret != 1)
{
return 0;
}
//连接数据端口
ret = socket_connect(m_socket_data, ipaddr, port);
if (ret != 1)
{
LOG_E("failed to connect data portrn");
return 0;
}
/* Get download partition information and erase download partition data */
if ((dl_part = fal_partition_find("download")) == RT_NULL)
{
LOG_E("Firmware download failed! Partition (%s) find error!", "download");
ret = -RT_ERROR;
goto __exit;
}
LOG_I("Start erase flash (%s) partition!", dl_part->name);
if (fal_partition_erase(dl_part, 0, len) < 0)
{
LOG_E("Firmware download failed! Partition (%s) erase error!", dl_part->name);
ret = -RT_ERROR;
goto __exit;
}
LOG_I("Erase flash (%s) partition success!", dl_part->name);
memset(m_recv_buffer, 0x00, 4096);
LOG_I("OTA file size is (%d)", len);
//准备下载
sprintf(m_send_buffer, "RETR %srn", name);
ret = ftp_send_command(m_send_buffer);
if (ret != 1)
{
return 0;
}
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 150)
{
closesocket(m_socket_data);
return 0;
}
//开始下载,读取完数据后,服务器会自动关闭连接
tick = rt_tick_get();
for (curlen = 0; curlen < len; curlen += ret)
{
ret = socket_recv(m_socket_data, m_recv_buffer, 4096);
// LOG_I("download %d/%d.rn", curlen + ret, len);
if (ret > 0)
{
/* Write the data to the corresponding partition address */
if (fal_partition_write(dl_part, curlen, m_recv_buffer, ret) < 0)
{
LOG_E("Firmware download failed! Partition (%s) write data error!", dl_part->name);
ret = -RT_ERROR;
goto __exit;
}
// curlen += ret;
print_progress(curlen + ret, len);
}
else
{
LOG_E("Exit: server return err (%d)!", len);
ret = -RT_ERROR;
goto __exit;
}
}
// //下载完成
LOG_I("time=%d download %d/%d bytes complete.rn", rt_tick_get() - tick, curlen, len);
closesocket(m_socket_data);
ret = ftp_recv_respond(m_recv_buffer, 4096);
if (ret == 226)
{
ftp_quit();
ret = RT_EOK;
}
// else
// {
// ret = -RT_ERROR;
// goto __exit;
// }
if (curlen == len)
{
LOG_I("Download firmware to flash success.");
LOG_I("System now will restart...");
rt_thread_delay(rt_tick_from_millisecond(5));
/* Reset the device, Start new firmware */
extern void rt_hw_cpu_reset(void);
rt_hw_cpu_reset();
}
__exit:
closesocket(m_socket_data);
ret = ftp_recv_respond(m_recv_buffer, 4096);
return (ret == 226);
}
//返回文件大小
int ftp_filesize(char *name)
{
int ret;
int size;
sprintf(m_send_buffer, "SIZE %srn", name);
ret = ftp_send_command(m_send_buffer);
if (ret != 1)
{
return 0;
}
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 213)
{
return 0;
}
size = atoi(m_recv_buffer + 4);
return size;
}
//登陆服务器
int ftp_login(char *addr, int port, char *username, char *password)
{
int ret;
LOG_I("connect...rn");
ret = socket_connect(m_socket_cmd, addr, port);
if (ret != 1)
{
LOG_E("connect server failed!rn");
return 0;
}
LOG_I("connect ok.rn");
//等待欢迎信息 一共4行
// 220---------- Welcome to Pure-FTPd ----------
// 220-You are user number 1 of 5 allowed.
// 220-Local time is now 16:30. Server port: 21.
// 220 You will be disconnected after 15 minutes of inactivity.
ret = ftp_recv_respond(m_recv_buffer, 1024);
ret = ftp_recv_respond(m_recv_buffer, 1024);
ret = ftp_recv_respond(m_recv_buffer, 1024);
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 220)
{
LOG_E("bad server, ret=%d!rn", ret);
closesocket(m_socket_cmd);
return 0;
}
LOG_I("login...rn");
//发送USER
sprintf(m_send_buffer, "USER %srn", username);
ret = ftp_send_command(m_send_buffer);
if (ret != 1)
{
LOG_E("bad ftp_send_command, ret=%d!rn", ret);
closesocket(m_socket_cmd);
return 0;
}
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 331)
{
LOG_E("bad ftp_recv_respond, ret=%d!rn", ret);
closesocket(m_socket_cmd);
return 0;
}
//发送PASS
sprintf(m_send_buffer, "PASS %srn", password);
ret = ftp_send_command(m_send_buffer);
if (ret != 1)
{
LOG_E("bad ftp_send_command, ret=%d!rn", ret);
closesocket(m_socket_cmd);
return 0;
}
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 230)
{
LOG_E("bad ftp_recv_respond, ret=%d!rn", ret);
closesocket(m_socket_cmd);
return 0;
}
LOG_I("login success.rn");
//设置为二进制模式
ret = ftp_send_command("TYPE Irn");
if (ret != 1)
{
closesocket(m_socket_cmd);
return 0;
}
ret = ftp_recv_respond(m_recv_buffer, 1024);
if (ret != 200)
{
closesocket(m_socket_cmd);
return 0;
}
return 1;
}
void ftp_quit(void)
{
ftp_send_command("QUITrn");
closesocket(m_socket_cmd);
}
void ftp_init(void)
{
// m_socket_cmd = socket_create();
// m_socket_data = socket_create();
if ((m_socket_cmd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/* 创建失败的错误处理 */
LOG_E("Create Socket errorn");
}
if ((m_socket_data = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
/* 创建失败的错误处理 */
LOG_E("Create Socket errorn");
}
}
static void print_progress(size_t cur_size, size_t total_size)
{
static unsigned char progress_sign[100 + 1];
uint8_t i, per = cur_size * 100 / total_size;
if (per > 100)
{
per = 100;
}
for (i = 0; i < 100; i++)
{
if (i < per)
{
progress_sign[i] = '=';
}
else if (per == i)
{
progress_sign[i] = '>';
}
else
{
progress_sign[i] = ' ';
}
}
progress_sign[sizeof(progress_sign) - 1] = ' |