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 }