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