1 /*
2 * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3 */
4
5 #include <unistd.h>
6 #include <string.h>
7 #include <stdlib.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 static int ota_upgrading = 0;
15 static unsigned char dl_buf[OTA_DOWNLOAD_BLOCK_SIZE] = {0};
16 static unsigned char head_buf[OTA_DOWNLOAD_BLOCK_SIZE] = {0};
17 #if defined OTA_CONFIG_SECURE_DL_MODE
18 static const char *ca_cert = \
19 { \
20 "-----BEGIN CERTIFICATE-----\r\n"
21 "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \
22 "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \
23 "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \
24 "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \
25 "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \
26 "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \
27 "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \
28 "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \
29 "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \
30 "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \
31 "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \
32 "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \
33 "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \
34 "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \
35 "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \
36 "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \
37 "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \
38 "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \
39 "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \
40 "-----END CERTIFICATE-----"
41 };
42 #endif
43
ota_set_upgrade_status(char is_upgrade)44 void ota_set_upgrade_status(char is_upgrade)
45 {
46 ota_upgrading = is_upgrade;
47 }
48
ota_get_upgrade_status()49 int ota_get_upgrade_status()
50 {
51 return ota_upgrading;
52 }
53
54 /**
55 * ota_httpc_settings_init init httpc settings
56 *
57 * @param[in] httpclient_t *client http client handle
58 * @param[in] httpclient_data_t *client_data httpc data
59 *
60 * @return 0 success
61 * @return -1 fail
62 */
ota_httpc_settings_init(httpclient_t * client,httpclient_data_t * client_data)63 int ota_httpc_settings_init(httpclient_t *client, httpclient_data_t *client_data)
64 {
65 int ret = -1;
66 if ((client != NULL) && (client_data != NULL)) {
67 ret = 0;
68 #if defined OTA_CONFIG_SECURE_DL_MODE
69 OTA_LOG_I("init https ota.\n");
70 client->server_cert = ca_cert;
71 client->server_cert_len = strlen(ca_cert) + 1;
72 #else
73 OTA_LOG_I("init http.\n");
74 #endif
75 memset(head_buf, 0, sizeof(head_buf));
76 client_data->header_buf = (char *)head_buf;
77 client_data->header_buf_len = sizeof(head_buf);
78
79 memset(dl_buf, 0, sizeof(dl_buf));
80 client_data->response_buf = (char *)dl_buf;
81 client_data->response_buf_len = sizeof(dl_buf);
82 }
83 return ret;
84 }
85
86 /**
87 * ota_httpc_settings_destory destory httpc settings
88 *
89 * @param[in] httpc_connection_t *settings httpc settings
90 *
91 * @return void
92 */
ota_httpc_settings_destory(httpclient_t * client)93 void ota_httpc_settings_destory(httpclient_t *client)
94 {
95 httpclient_clse(client);
96 }
97
98 /**
99 * ota_httpc_request_send OTA send request to server
100 *
101 * @param[in] httpclient_t *client httpc client
102 * @param[in] char *url host url
103 * @param[in] httpclient_data_t *client_data ttpc response infomation
104 *
105 * @return 0 success.
106 * @return -1 failed.
107 */
ota_httpc_request_send(httpclient_t * client,char * url,httpclient_data_t * client_data)108 int ota_httpc_request_send(httpclient_t *client, char *url, httpclient_data_t *client_data)
109 {
110 int ret = -1;
111 if (client == NULL || url == NULL || client_data == NULL) {
112 OTA_LOG_E("http recv fuc input parameter err\n");
113 } else {
114 ret = httpclient_send(client, url, HTTP_GET, client_data);
115 if (ret < 0) {
116 OTA_LOG_E("send data ret:%d\n", ret);
117 }
118 }
119 return ret;
120 }
121
122 /**
123 * ota_httpc_recv_data OTA receive data from httpc
124 *
125 * @param[in] httpclient_t *client httpc handle
126 * @param[in] httpclient_data_t *client_data httpc response infomation
127 *
128 * @return 0 success.
129 * @return -1 failed.
130 */
ota_httpc_recv_data(httpclient_t * client,httpclient_data_t * client_data)131 int ota_httpc_recv_data(httpclient_t *client, httpclient_data_t *client_data)
132 {
133 int ret = -1;
134 if (client == NULL || client_data == NULL) {
135 OTA_LOG_E("http recv fuc input parameter err\n");
136 } else {
137 ret = httpclient_recv(client, client_data);
138 if ((ret == HTTP_ERECV) || (ret == HTTP_ETIMEOUT)) {
139 OTA_LOG_E("recv ret:%d\n", ret);
140 }
141 }
142 return ret;
143 }
144
145 /**
146 * ota_download_extract_url OTA extrack http url from https url
147 *
148 * @param[in] char *src_url src https url.
149 * @param[in] char *dest_url new url store buf.
150 * @param[in] char *dest_buf_len new url store buf len.
151 *
152 * @return 0 success, others fail
153 */
ota_download_extract_url(char * src_url,char * dest_url,unsigned int dest_buf_len)154 int ota_download_extract_url(char *src_url, char *dest_url, unsigned int dest_buf_len)
155 {
156 int ret = 0;
157 unsigned int len = 0;
158 if ((src_url == NULL) || (strlen(src_url) == 0) || (dest_url == NULL)) {
159 OTA_LOG_E("url parms error!");
160 return OTA_DOWNLOAD_INIT_FAIL;
161 }
162 len = strlen(src_url);
163 if (len > dest_buf_len) {
164 OTA_LOG_E("url too long!");
165 return OTA_DOWNLOAD_INIT_FAIL;
166 }
167 OTA_LOG_I("cpy len = %d\r\n", len);
168 strncpy(dest_url, src_url, dest_buf_len);
169 dest_url[dest_buf_len - 1] = 0;
170 #ifndef OTA_CONFIG_SECURE_DL_MODE
171 if (dest_url[4] == 's') {
172 int i = 0;
173 for (i = 4; i < len; i++) {
174 dest_url[i] = dest_url[i + 1];
175 }
176 dest_url[i] = 0;
177 }
178 #endif
179 OTA_LOG_I("http_uri:%s\n", dest_url);
180 return ret;
181 }
182
183 /**
184 * ota_download_image_header OTA download image header
185 *
186 * @param[in] ota_service_t *ctx ota service context
187 * @param[in] char *url download url
188 * @param[in] unsigned int url_len download url length
189 * @param[in] unsigned int size image size
190 *
191 *
192 * @return OTA_SUCCESS OTA success.
193 * @return OTA_DOWNLOAD_INIT_FAIL OTA download init failed.
194 * @return OTA_DOWNLOAD_CON_FAIL OTA download connect failed.
195 * @return OTA_DOWNLOAD_REQ_FAIL OTA download request failed.
196 * @return OTA_DOWNLOAD_RECV_FAIL OTA download receive failed.
197 */
ota_download_image_header(ota_service_t * ctx,char * url,unsigned int url_len,unsigned int size)198 int ota_download_image_header(ota_service_t *ctx, char *url, unsigned int url_len, unsigned int size)
199 {
200 int ret = OTA_DOWNLOAD_INIT_FAIL;
201 unsigned int off_size = 0;
202 char *content = NULL;
203 char tmp_header[64] = {0};
204 int retry_tm = 0;
205 int ota_rx_size = 0;
206 int want_download_size = 0;
207 unsigned char ota_header_found = false;
208 httpclient_t client = { 0 };
209 httpclient_data_t client_data = {0};
210 char *new_url = NULL;
211 int tmp_url_len = 0;
212
213 #ifdef OTA_CONFIG_LOCAL_RSA
214 char *sign_info_ptr = NULL;
215 #endif
216 char *image_info_ptr = NULL;
217 if ((ctx == NULL) || (url == NULL) || (ota_get_upgrade_status() == 1)) {
218 ret = OTA_DOWNLOAD_INIT_FAIL;
219 return ret;
220 }
221 #ifdef OTA_CONFIG_LOCAL_RSA
222 sign_info_ptr = (char *)ctx->header.sign_info;
223 if (sign_info_ptr == NULL) {
224 ret = OTA_DOWNLOAD_INIT_FAIL;
225 return ret;
226 }
227 #endif
228 image_info_ptr = (char *)ctx->header.image_info;
229 if (image_info_ptr == NULL) {
230 ret = OTA_DOWNLOAD_INIT_FAIL;
231 return ret;
232 }
233 tmp_url_len = url_len + 1;
234 OTA_LOG_I("URl len = %d\r\n", url_len);
235 new_url = ota_malloc(tmp_url_len);
236 if (new_url == NULL) {
237 ret = OTA_DOWNLOAD_INIT_FAIL;
238 return ret;
239 }
240 memset(new_url, 0, tmp_url_len);
241 if (ota_download_extract_url(url, new_url, tmp_url_len) < 0) {
242 if (new_url != NULL) {
243 ota_free(new_url);
244 }
245 ret = OTA_DOWNLOAD_INIT_FAIL;
246 return ret;
247 }
248 #ifdef OTA_CONFIG_LOCAL_RSA
249 off_size = size - sizeof(ota_image_info_t) - sizeof(ota_sign_info_t);
250 #else
251 off_size = size - sizeof(ota_image_info_t);
252 #endif
253 for (retry_tm = OTA_DOWNLOAD_RETRY_CNT; (retry_tm > 0) && (ret < 0); retry_tm--) {
254 if (retry_tm < OTA_DOWNLOAD_RETRY_CNT) {
255 OTA_LOG_I("retry count.\n");
256 ota_msleep(6000);
257 }
258 ret = ota_httpc_settings_init(&client, &client_data);
259 if (ret < 0) {
260 ret = OTA_DOWNLOAD_INIT_FAIL;
261 goto OVER;
262 }
263 memset(tmp_header, 0, sizeof(tmp_header));
264 OTA_LOG_I("retry:%d ret:%d rx_size:%d\n", retry_tm, ret, off_size);
265 ota_snprintf(tmp_header, sizeof(tmp_header), "Range: bytes=%d-\r\n", off_size);
266 client.header = tmp_header;
267 OTA_LOG_I("http conn.\n");
268 ret = httpclient_conn(&client, new_url);
269 if (ret < 0) {
270 ret = OTA_DOWNLOAD_INIT_FAIL;
271 goto OVER;
272 }
273 OTA_LOG_I("http request send.\n");
274 ret = ota_httpc_request_send(&client, new_url, &client_data);
275 if (ret < 0) {
276 ret = OTA_DOWNLOAD_REQ_FAIL;
277 goto OVER;
278 }
279 ota_set_upgrade_status(1);
280 OTA_LOG_I("http begin download.\n");
281 while (want_download_size == 0 || ota_rx_size < want_download_size) {
282 ret = ota_httpc_recv_data(&client, &client_data);
283 if (ret < 0) {
284 ret = OTA_DOWNLOAD_RECV_FAIL;
285 break;
286 } else {
287 int tmp_size = client_data.content_block_len;
288 content = (char *)client_data.response_buf;
289 if (ota_header_found == false) {
290 ota_header_found = true;
291 int val_pos, val_len;
292 if (0 == httpclient_get_response_header_value(client_data.header_buf, "Content-Length", (int *)&val_pos, (int *)&val_len)) {
293 sscanf(client_data.header_buf + val_pos, "%d", &want_download_size);
294 }
295 }
296 if (ota_rx_size + tmp_size <= off_size) {
297 #ifdef OTA_CONFIG_LOCAL_RSA
298 if (ota_rx_size + tmp_size <= sizeof(ota_sign_info_t)) {
299 memcpy(sign_info_ptr, content, tmp_size);
300 sign_info_ptr += tmp_size;
301 ota_rx_size += tmp_size;
302 } else {
303 if (ota_rx_size <= sizeof(ota_sign_info_t)) {
304 unsigned int remain_len = sizeof(ota_sign_info_t) - ota_rx_size;
305 memcpy(sign_info_ptr, content, remain_len);
306 sign_info_ptr += remain_len;
307 content += remain_len;
308 memcpy(image_info_ptr, content, tmp_size - remain_len);
309 image_info_ptr += tmp_size - remain_len;
310 ota_rx_size += tmp_size;
311 } else {
312 memcpy(image_info_ptr, content, tmp_size);
313 image_info_ptr += tmp_size;
314 ota_rx_size += tmp_size;
315 }
316 }
317 #else
318 memcpy(image_info_ptr, content, tmp_size);
319 image_info_ptr += tmp_size;
320 ota_rx_size += tmp_size;
321 #endif
322 } else {
323 OTA_LOG_E("image head buf full");
324 ret = OTA_DOWNLOAD_RECV_FAIL;
325 retry_tm = 0;
326 break;
327 }
328 }
329 }
330 OVER:
331 ota_set_upgrade_status(0);
332 ota_httpc_settings_destory(&client);
333 ota_header_found = false;
334 want_download_size = 0;
335 ota_rx_size = 0;
336 }
337 if (new_url != NULL) {
338 ota_free(new_url);
339 new_url = NULL;
340 }
341 OTA_LOG_I("parse image info:%d\n", ret);
342 return ret;
343 }
344
345 /**
346 * ota_download_start OTA download start
347 *
348 * @param[in] char *url download url
349 * @param[in] unsigned int url_len download url length
350 * @param[in] report_func repot_func report http downloading status function
351 * @param[in] void *user_param user's param for repot_func
352 *
353 * @return OTA_SUCCESS OTA success.
354 * @return OTA_DOWNLOAD_INIT_FAIL OTA download init failed.
355 * @return OTA_DOWNLOAD_CON_FAIL OTA download connect failed.
356 * @return OTA_DOWNLOAD_REQ_FAIL OTA download request failed.
357 * @return OTA_DOWNLOAD_RECV_FAIL OTA download receive failed.
358 */
ota_download_start(char * url,unsigned int url_len,report_func repot_func,void * user_param)359 int ota_download_start(char *url, unsigned int url_len, report_func repot_func, void *user_param)
360 {
361 int ret = OTA_DOWNLOAD_INIT_FAIL;
362 unsigned int offset = 0;
363 unsigned int off_size = 0;
364 int j = 0;
365 int ota_rx_size = 0;
366 int ota_file_size = 0;
367 char tmp_header[64] = {0};
368 unsigned char ota_header_found = false;
369 httpclient_t client = {0};
370 httpclient_data_t client_data = {0};
371 char *new_url = NULL;
372 int tmp_url_len = 0;
373 int percent = 0;
374 int divisor = 5;
375 if (url == NULL) {
376 ret = OTA_DOWNLOAD_INIT_FAIL;
377 return ret;
378 }
379 if (ota_get_upgrade_status() == 1) {
380 ret = OTA_DOWNLOAD_INIT_FAIL;
381 return ret;
382 }
383 tmp_url_len = url_len + 1;
384 OTA_LOG_I("URl len = %d\r\n", url_len);
385 new_url = ota_malloc(tmp_url_len);
386 if (new_url == NULL) {
387 ret = OTA_DOWNLOAD_INIT_FAIL;
388 return ret;
389 }
390 memset(new_url, 0, tmp_url_len);
391 if (ota_download_extract_url(url, new_url, tmp_url_len) < 0) {
392 if (new_url != NULL) {
393 ota_free(new_url);
394 }
395 ret = OTA_DOWNLOAD_INIT_FAIL;
396 return ret;
397 }
398 for (j = OTA_DOWNLOAD_RETRY_CNT; (j > 0) && (ret < 0); j--) {
399 memset(&client_data, 0, sizeof(client_data));
400 memset(&client, 0 , sizeof(client));
401 ret = ota_httpc_settings_init(&client, &client_data);
402 if (ret < 0) {
403 ret = OTA_DOWNLOAD_INIT_FAIL;
404 goto EXIT;
405 }
406 memset(tmp_header, 0, sizeof(tmp_header));
407 if (j >= OTA_DOWNLOAD_RETRY_CNT) {
408 strncpy(tmp_header, "Accept: */*\r\n", sizeof(tmp_header));
409 tmp_header[sizeof(tmp_header) - 1] = 0;
410 } else {
411 ota_msleep(6000);
412 OTA_LOG_I("reconnect retry:%d ret:%d rx_size:%d\n", j, ret, off_size);
413 ota_snprintf(tmp_header, sizeof(tmp_header), "Range: bytes=%d-\r\n", off_size);
414 }
415 client.header = tmp_header;
416 ret = httpclient_conn(&client, new_url);
417 if (ret < 0) {
418 ret = OTA_DOWNLOAD_CON_FAIL;
419 goto EXIT;
420 }
421 ret = ota_httpc_request_send(&client, new_url, &client_data);
422 if (ret < 0) {
423 ret = OTA_DOWNLOAD_REQ_FAIL;
424 goto EXIT;
425 }
426 ota_set_upgrade_status(1);
427 while (ota_file_size == 0 || ota_rx_size < ota_file_size) {
428 ret = ota_httpc_recv_data(&client, &client_data);
429 if (ota_get_upgrade_status() == 0) {
430 OTA_LOG_E("download stop.\n");
431 ret = OTA_DOWNLOAD_RECV_FAIL;
432 break;
433 } else if (ret < 0) {
434 ret = OTA_DOWNLOAD_RECV_FAIL;
435 break;
436 } else {
437 if (ota_header_found == false) {
438 int val_pos, val_len;
439 ota_header_found = true;
440 if (0 == httpclient_get_response_header_value(client_data.header_buf, "Content-Length", (int *)&val_pos, (int *)&val_len)) {
441 sscanf(client_data.header_buf + val_pos, "%d", &ota_file_size);
442 printf("ota_file_size %d\r\n", ota_file_size);
443 }
444 }
445 ret = ota_write(&offset, client_data.response_buf, client_data.content_block_len);
446 if (ret < 0) {
447 ret = OTA_UPGRADE_WRITE_FAIL;
448 goto EXIT;
449 }
450 ota_rx_size += client_data.content_block_len;
451 ota_msleep(5);
452 off_size += client_data.content_block_len;
453 OTA_LOG_I("recv size = %d, has recv size = %d\r\n", client_data.content_block_len, off_size);
454 if (ota_file_size) {
455 percent = ((long)(ota_rx_size >> 6) * 100) / (long)(ota_file_size >> 6);
456 if (percent / divisor) {
457 divisor += 5;
458 if (repot_func != NULL) {
459 ret = repot_func(user_param, percent);
460 if (ret != 0) {
461 OTA_LOG_E("report http download process failed ret %d\r\n", ret);
462 }
463 }
464 OTA_LOG_I("ota recv data(%d/%d) off:%d \r\n", ota_rx_size, ota_file_size, off_size);
465 }
466 }
467 }
468 }
469
470 EXIT:
471 ota_set_upgrade_status(0);
472 ota_httpc_settings_destory(&client);
473 ota_header_found = false;
474 ota_file_size = 0;
475 ota_rx_size = 0;
476 }
477 if (new_url != NULL) {
478 ota_free(new_url);
479 new_url = NULL;
480 }
481 OTA_LOG_I("download complete:%d\n", ret);
482 return ret;
483 }
484