1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4 #include <unistd.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <fcntl.h>
8 #include "ota_log.h"
9 #include "ota_hal_os.h"
10 #include "ota_import.h"
11 #include "ota_hal_trans.h"
12 #include "httpclient.h"
13
14 int ota_get_upgrade_status(void);
15 void ota_set_upgrade_status(char is_upgrade);
16 int ota_download_extract_url(char *src_url, char *dest_url, unsigned int dest_buf_len);
17 int ota_httpc_request_send(httpclient_t *client, char *url, httpclient_data_t *client_data);
18 int ota_httpc_recv_data(httpclient_t *client, httpclient_data_t *client_data);
19 int ota_httpc_settings_init(httpclient_t *client, httpclient_data_t *client_data);
20 void ota_httpc_settings_destory(httpclient_t *client);
21 /**
22 * ota_download_store_fs_start OTA download file start and store in fs
23 *
24 * @param[in] char *url download url
25 * @param[in] unsigned int url_len download url length
26 * @param[in] char *store_path store file path and name eg:/root/test.bin
27 * @param[in] report_func report_func report http downloading status function
28 * @param[in] void *user_param user's param for report_func
29 *
30 * @return OTA_SUCCESS OTA success.
31 * @return OTA_DOWNLOAD_INIT_FAIL OTA download init failed.
32 * @return OTA_DOWNLOAD_CON_FAIL OTA download connect failed.
33 * @return OTA_DOWNLOAD_REQ_FAIL OTA download request failed.
34 * @return OTA_DOWNLOAD_RECV_FAIL OTA download receive failed.
35 */
ota_download_store_fs_start(char * url,unsigned int url_len,char * store_path,report_func report_func,void * user_param)36 int ota_download_store_fs_start(char *url, unsigned int url_len, char *store_path,
37 report_func report_func, void *user_param)
38 {
39 int j = 0;
40 int fd = -1;
41 int ret = OTA_DOWNLOAD_INIT_FAIL;
42 unsigned int off_size = 0;
43 int ota_rx_size = 0;
44 int ota_file_size = 0;
45 char tmp_header[64] = {0};
46 unsigned char ota_header_found = false;
47 httpclient_t client = {0};
48 httpclient_data_t client_data = {0};
49 char *new_url = NULL;
50 int tmp_url_len = 0;
51 int percent = 0;
52 int divisor = 5;
53 if ((store_path == NULL) || (url == NULL)) {
54 ret = OTA_DOWNLOAD_INIT_FAIL;
55 return ret;
56 }
57 if (ota_get_upgrade_status() == 1) {
58 ret = OTA_DOWNLOAD_INIT_FAIL;
59 return ret;
60 }
61 tmp_url_len = url_len + 1;
62 new_url = ota_malloc(tmp_url_len);
63 if (new_url == NULL) {
64 ret = OTA_DOWNLOAD_INIT_FAIL;
65 return ret;
66 }
67 memset(new_url, 0, tmp_url_len);
68 if (ota_download_extract_url(url, new_url, tmp_url_len) < 0) {
69 if (new_url != NULL) {
70 ota_free(new_url);
71 }
72 ret = OTA_DOWNLOAD_INIT_FAIL;
73 return ret;
74 }
75 fd = ota_fopen(store_path, O_WRONLY | O_CREAT | O_TRUNC);
76 if (fd < 0) {
77 if (new_url != NULL) {
78 ota_free(new_url);
79 }
80 ret = OTA_DOWNLOAD_INIT_FAIL;
81 OTA_LOG_E("open %s failed\n", store_path);
82 return ret;
83 }
84 for (j = OTA_DOWNLOAD_RETRY_CNT; (j > 0) && (ret < 0); j--) {
85 ret = ota_httpc_settings_init(&client, &client_data);
86 if (ret < 0) {
87 ret = OTA_DOWNLOAD_INIT_FAIL;
88 goto EXIT;
89 }
90 memset(tmp_header, 0, sizeof(tmp_header));
91 if (j >= OTA_DOWNLOAD_RETRY_CNT) {
92 strncpy(tmp_header, "Accept: */*\r\n", sizeof(tmp_header));
93 tmp_header[sizeof(tmp_header) - 1] = 0;
94 } else {
95 ota_msleep(6000);
96 OTA_LOG_I("reconnect retry:%d ret:%d rx_size:%d\n", j, ret, off_size);
97 ota_snprintf(tmp_header, sizeof(tmp_header), "Range: bytes=%d-\r\n", off_size);
98 }
99 client.header = tmp_header;
100 ret = httpclient_conn(&client, new_url);
101 if (ret < 0) {
102 ret = OTA_DOWNLOAD_CON_FAIL;
103 goto EXIT;
104 }
105 ret = ota_httpc_request_send(&client, new_url, &client_data);
106 if (ret < 0) {
107 ret = OTA_DOWNLOAD_REQ_FAIL;
108 goto EXIT;
109 }
110 ota_set_upgrade_status(1);
111 OTA_LOG_E("ota download begin....\n");
112 while (ota_file_size == 0 || ota_rx_size < ota_file_size) {
113 ret = ota_httpc_recv_data(&client, &client_data);
114 if (ota_get_upgrade_status() == 0) {
115 OTA_LOG_E("download stop.\n");
116 ret = OTA_DOWNLOAD_RECV_FAIL;
117 break;
118 } else if (ret < 0) {
119 ret = OTA_DOWNLOAD_RECV_FAIL;
120 break;
121 } else {
122 if (ota_header_found == false) {
123 int val_pos, val_len;
124 ota_header_found = true;
125 if (0 == httpclient_get_response_header_value(client_data.header_buf, "Content-Length", (int *)&val_pos, (int *)&val_len)) {
126 sscanf(client_data.header_buf + val_pos, "%d", &ota_file_size);
127 }
128 }
129 ret = ota_fwrite(fd, client_data.response_buf, client_data.content_block_len);
130 if (ret < 0) {
131 ret = OTA_UPGRADE_WRITE_FAIL;
132 goto EXIT;
133 }
134 ota_rx_size += client_data.content_block_len;
135 ota_msleep(5);
136 off_size = ota_rx_size;
137 if (ota_file_size) {
138 percent = ((long)(ota_rx_size >> 6) * 100) / (long)(ota_file_size >> 6);
139 if (percent / divisor) {
140 divisor += 5;
141 if (report_func != NULL) {
142 ret = report_func(user_param, percent);
143 if (ret < 0) {
144 OTA_LOG_E("report http download process failed, ret = %d", ret);
145 }
146 }
147 OTA_LOG_I(" in fs recv data(%d/%d) off:%d\r\n", ota_rx_size, ota_file_size, off_size);
148 }
149 }
150 }
151 }
152
153 EXIT:
154 ota_set_upgrade_status(0);
155 ota_httpc_settings_destory(&client);
156 ota_header_found = false;
157 ota_file_size = 0;
158 ota_rx_size = 0;
159 }
160 if (fd >= 0) {
161 (void)ota_fclose(fd);
162 fd = -1;
163 }
164 if (new_url != NULL) {
165 ota_free(new_url);
166 new_url = NULL;
167 }
168 OTA_LOG_I("in fs download complete:%d\n", ret);
169 return ret;
170 }