1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include "iotx_ota_internal.h"
6 
7 /* ofc, OTA fetch channel */
8 
9 #define OFC_HTTP_HEADER_MAXLEN (128)
10 
11 typedef struct {
12     char *payload;
13     int alread_download;
14     int payload_len;
15 } ota_http_response_t;
16 
17 typedef struct {
18     const char *url;
19     void *http_handle;
20     int fetch_size;
21 } otahttp_Struct_t, *otahttp_Struct_pt;
22 
ofc_Init(char * url,int offset)23 void *ofc_Init(char *url, int offset)
24 {
25     otahttp_Struct_pt h_odc;
26     char *pub_key = NULL;
27     int port = 0;
28     char header[OFC_HTTP_HEADER_MAXLEN] = { 0 };
29     char *header_fmt =
30         "Accept: "
31         "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
32         "Accept-Encoding: gzip, deflate\r\n"
33         "Range: bytes=%d-\r\n";
34     char *protocol_end = NULL, *port_start = NULL, *port_end = NULL;
35     int protocol_len = 0;
36     iotx_http_method_t method = IOTX_HTTP_GET;
37 
38     /* protocol end location */
39     protocol_end = strstr(url, "://");
40     if (protocol_end != NULL) {
41         protocol_len = strlen(url) - strlen(protocol_end);
42 
43         /* check protocol, http or https, and assign default port*/
44         if ((strlen("http") == protocol_len) &&
45             (memcmp("http", url, protocol_len) == 0)) {
46             OTA_LOG_INFO("protocol: http");
47             port = 80;
48         } else if ((strlen("https") == protocol_len) &&
49                    (memcmp("https", url, protocol_len) == 0)) {
50             OTA_LOG_INFO("protocol: https");
51 #ifdef SUPPORT_TLS
52             {
53                 extern const char *iotx_ca_crt;
54                 pub_key = (char *)iotx_ca_crt;
55             }
56             port = 443;
57 #else
58             port = 80;
59 #endif
60 
61         } else {
62             OTA_LOG_ERROR("Invalid URL");
63             return NULL;
64         }
65     } else {
66         OTA_LOG_INFO("protocol: http");
67         protocol_end = url;
68         port = 80;
69     }
70 
71     /* check port, if exist, override port */
72     port_start = strstr(protocol_end + 1, ":");
73     if (port_start != NULL) {
74         port_end = strstr(port_start + 1, "/");
75         if (port_end != NULL) {
76             OTA_LOG_INFO("port exist: %.*s", (int)(port_end - port_start - 1),
77                          port_start + 1);
78             infra_str2int((const char *)(port_start + 1), &port);
79         }
80     }
81 
82     HAL_Snprintf(header, OFC_HTTP_HEADER_MAXLEN, header_fmt, offset);
83 
84     h_odc = OTA_MALLOC(sizeof(otahttp_Struct_t));
85     if (h_odc == NULL) {
86         OTA_LOG_ERROR("allocate for h_odc failed");
87         return NULL;
88     }
89 
90     memset(h_odc, 0, sizeof(otahttp_Struct_t));
91 
92     h_odc->http_handle = wrapper_http_init();
93     if (h_odc->http_handle == NULL) {
94         OTA_FREE(h_odc);
95         return NULL;
96     }
97 
98     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_URL, (void *)url);
99     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_PORT, (void *)&port);
100     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_METHOD,
101                         (void *)&method);
102     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_HEADER,
103                         (void *)header);
104     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_CERT, (void *)pub_key);
105 
106     return h_odc;
107 }
108 
_ota_fetch_callback(char * ptr,int length,int total_length,void * userdata)109 static int _ota_fetch_callback(char *ptr, int length, int total_length,
110                                void *userdata)
111 {
112     ota_http_response_t *response = (ota_http_response_t *)userdata;
113     if (response->alread_download + length > response->payload_len) {
114         return FAIL_RETURN;
115     }
116 
117     memcpy(response->payload + response->alread_download, ptr, length);
118     response->alread_download += length;
119 
120     return length;
121 }
122 
ofc_Fetch(void * handle,char * buf,uint32_t buf_len,uint32_t timeout_s)123 int32_t ofc_Fetch(void *handle, char *buf, uint32_t buf_len, uint32_t timeout_s)
124 {
125     int current_fetch_size = 0;
126     int http_timeout_s = timeout_s * 1000;
127     int http_recv_maxlen = buf_len;
128     otahttp_Struct_pt h_odc = (otahttp_Struct_pt)handle;
129     ota_http_response_t response;
130 
131     memset(&response, 0, sizeof(ota_http_response_t));
132     memset(buf, 0, buf_len);
133     response.payload = buf;
134     response.payload_len = buf_len;
135 
136     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_TIMEOUT,
137                         (void *)&http_timeout_s);
138     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_RECVCALLBACK,
139                         (void *)_ota_fetch_callback);
140     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_RECVMAXLEN,
141                         (void *)&http_recv_maxlen);
142     wrapper_http_setopt(h_odc->http_handle, IOTX_HTTPOPT_RECVCONTEXT,
143                         (void *)&response);
144     current_fetch_size = wrapper_http_perform(h_odc->http_handle, NULL, 0);
145 
146     if (current_fetch_size < 0) {
147         OTA_LOG_ERROR("fetch firmware failed");
148         return current_fetch_size;
149     }
150 
151     h_odc->fetch_size += current_fetch_size;
152 
153     /*     OTA_LOG_ERROR("Download This Time: %d",current_fetch_size);
154         OTA_LOG_ERROR("Download Total    : %d",h_odc->fetch_size); */
155 
156     return current_fetch_size;
157 }
158 
ofc_Deinit(void ** handle)159 int ofc_Deinit(void **handle)
160 {
161     otahttp_Struct_t *h_odc = NULL;
162 
163     if (handle == NULL || *handle == NULL) {
164         return FAIL_RETURN;
165     }
166 
167     h_odc = *(otahttp_Struct_t **)handle;
168     wrapper_http_deinit(&h_odc->http_handle);
169     OTA_FREE(h_odc);
170 
171     *handle = NULL;
172 
173     return 0;
174 }
175