123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- /*
- * Copyright (C) 2019-2020 Alibaba Group Holding Limited
- */
- #include <errno.h>
- #include <yoc/fota.h>
- #include <yoc/netio.h>
- #include <aos/kernel.h>
- #include <aos/kv.h>
- #include <aos/version.h>
- #include <ulog/ulog.h>
- #include <yoc/sysinfo.h>
- #define COP_IMG_URL "cop_img_url"
- #define COP_VERSION "cop_version"
- #define TO_URL "flash://misc"
- #define TAG "fotacop"
- static void cop_res_release(fota_info_t *info)
- {
- if (info) {
- if (info->fota_url) {
- aos_free(info->fota_url);
- info->fota_url = NULL;
- }
- if (info->local_changelog) {
- aos_free(info->local_changelog);
- info->local_changelog = NULL;
- }
- if (info->changelog) {
- aos_free(info->changelog);
- info->changelog = NULL;
- }
- if (info->cur_version) {
- aos_free(info->cur_version);
- info->cur_version = NULL;
- }
- if (info->new_version) {
- aos_free(info->new_version);
- info->new_version = NULL;
- }
- }
- }
- #if CONFIG_FOTA_USE_HTTPC == 1
- #include <http_client.h>
- #include <cJSON.h>
- static int cop_get_ota_url(char *ota_url, int len)
- {
- int ret = -1;
- ret = aos_kv_getstring("otaurl", ota_url, len);
- if (ret < 0) {
- strcpy(ota_url, "http://occ.t-head.cn/api/image/ota/pull");
- }
- return ret;
- }
- static int _http_event_handler(http_client_event_t *evt)
- {
- switch(evt->event_id) {
- case HTTP_EVENT_ERROR:
- LOGD(TAG, "HTTP_EVENT_ERROR");
- break;
- case HTTP_EVENT_ON_CONNECTED:
- LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
- break;
- case HTTP_EVENT_HEADER_SENT:
- LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
- break;
- case HTTP_EVENT_ON_HEADER:
- // LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
- break;
- case HTTP_EVENT_ON_DATA:
- // LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
- break;
- case HTTP_EVENT_ON_FINISH:
- LOGD(TAG, "HTTP_EVENT_ON_FINISH");
- break;
- case HTTP_EVENT_DISCONNECTED:
- LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
- break;
- }
- return 0;
- }
- static bool process_again(int status_code)
- {
- switch (status_code) {
- case HttpStatus_MovedPermanently:
- case HttpStatus_Found:
- case HttpStatus_TemporaryRedirect:
- case HttpStatus_Unauthorized:
- return true;
- default:
- return false;
- }
- return false;
- }
- static http_errors_t _http_handle_response_code(http_client_handle_t http_client, int status_code, char *buffer, int buf_size, int data_size)
- {
- http_errors_t err;
- if (status_code == HttpStatus_MovedPermanently || status_code == HttpStatus_Found || status_code == HttpStatus_TemporaryRedirect) {
- err = http_client_set_redirection(http_client);
- if (err != HTTP_CLI_OK) {
- LOGE(TAG, "URL redirection Failed");
- return err;
- }
- } else if (status_code == HttpStatus_Unauthorized) {
- return HTTP_CLI_FAIL;
- } else if(status_code == HttpStatus_NotFound || status_code == HttpStatus_Forbidden) {
- LOGE(TAG, "File not found(%d)", status_code);
- return HTTP_CLI_FAIL;
- } else if (status_code == HttpStatus_InternalError) {
- LOGE(TAG, "Server error occurred(%d)", status_code);
- return HTTP_CLI_FAIL;
- }
- // process_again() returns true only in case of redirection.
- if (data_size > 0 && process_again(status_code)) {
- /*
- * In case of redirection, http_client_read() is called
- * to clear the response buffer of http_client.
- */
- int data_read;
- while (data_size > buf_size) {
- data_read = http_client_read(http_client, buffer, buf_size);
- if (data_read <= 0) {
- return HTTP_CLI_OK;
- }
- data_size -= buf_size;
- }
- data_read = http_client_read(http_client, buffer, data_size);
- if (data_read <= 0) {
- return HTTP_CLI_OK;
- }
- }
- return HTTP_CLI_OK;
- }
- static http_errors_t _http_connect(http_client_handle_t http_client, const char *payload, char *buffer, int buf_size)
- {
- #define MAX_REDIRECTION_COUNT 10
- http_errors_t err = HTTP_CLI_FAIL;
- int status_code = 0, header_ret;
- int redirect_counter = 0;
- do {
- if (redirect_counter++ > MAX_REDIRECTION_COUNT) {
- LOGE(TAG, "redirect_counter is max");
- return HTTP_CLI_FAIL;
- }
- if (process_again(status_code)) {
- LOGD(TAG, "process again,status code:%d", status_code);
- }
- err = http_client_open(http_client, strlen(payload));
- if (err != HTTP_CLI_OK) {
- LOGE(TAG, "Failed to open HTTP connection");
- return err;
- }
- int wlen = http_client_write(http_client, payload, strlen(payload));
- if (wlen < 0) {
- LOGE(TAG, "Write payload failed");
- return HTTP_CLI_FAIL;
- }
- LOGD(TAG, "write payload ok...");
- header_ret = http_client_fetch_headers(http_client);
- if (header_ret < 0) {
- LOGE(TAG, "header_ret:%d", header_ret);
- return header_ret;
- }
- LOGD(TAG, "header_ret:%d", header_ret);
- status_code = http_client_get_status_code(http_client);
- LOGD(TAG, "status code:%d", status_code);
- err = _http_handle_response_code(http_client, status_code, buffer, buf_size, header_ret);
- if (err != HTTP_CLI_OK) {
- LOGE(TAG, "e handle resp code:%d", err);
- return err;
- }
- } while (process_again(status_code));
- return err;
- }
- static void _http_cleanup(http_client_handle_t client)
- {
- if (client) {
- http_client_cleanup(client);
- }
- }
- static int cop_version_check(fota_info_t *info) {
- int ret = 0, rc;
- char *payload = NULL;
- char getvalue[64];
- cJSON *js = NULL;
- char *buffer = NULL;
- http_errors_t err;
- http_client_config_t config = {0};
- http_client_handle_t client = NULL;
- buffer = aos_zalloc(BUFFER_SIZE + 1);
- if (buffer == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- if ((payload = aos_malloc(156)) == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- #if 1
- char * dev_id = aos_get_device_id();
- char * pro_model = (char *)aos_get_product_model();
- char * app_ver = aos_get_app_version();
- snprintf(payload, 156, "{\"cid\":\"%s\",\"model\":\"%s\",\"version\":\"%s\"}",
- dev_id ? dev_id : "null", pro_model ? pro_model : "null", app_ver ? app_ver : "null");
- #else
- //snprintf(payload, 100, "{\"cid\":\"%s\",\"model\":\"%s\",\"version\":\"%s\"}",
- // "00A2C6FB32241D9423F5AF00", "hlb_test", "1.0.0-20181125.1321-R-hlb_tes");
- // FIXME: for test.
- snprintf(payload, 156, "{\"cid\":\"%s\",\"model\":\"%s\",\"version\":\"%s\"}",
- "e6d0d5480440000008376eb1e834a765", "pangu", "1.1.1-20201027.2235-R-pangu");
- #endif
- LOGD(TAG, "check: %s", payload);
- memset(getvalue, 0, sizeof(getvalue));
- cop_get_ota_url(getvalue, sizeof(getvalue));
- LOGD(TAG, "ota url:%s", getvalue);
- config.method = HTTP_METHOD_POST;
- config.url = getvalue;
- config.timeout_ms = 10000;
- config.buffer_size = BUFFER_SIZE;
- config.event_handler = _http_event_handler;
- LOGD(TAG, "http client init start.");
- client = http_client_init(&config);
- if (!client) {
- LOGE(TAG, "Client init e");
- ret = -1;
- goto out;
- }
- LOGD(TAG, "http client init ok.");
- http_client_set_header(client, "Content-Type", "application/json");
- http_client_set_header(client, "Connection", "keep-alive");
- http_client_set_header(client, "Cache-Control", "no-cache");
- err = _http_connect(client, payload, buffer, BUFFER_SIZE);
- if (err != HTTP_CLI_OK) {
- LOGE(TAG, "Client connect e");
- ret = -1;
- goto out;
- }
- int read_len = http_client_read(client, buffer, BUFFER_SIZE);
- if (read_len <= 0) {
- ret = -1;
- goto out;
- }
- buffer[read_len] = 0;
- LOGD(TAG, "resp: %s", buffer);
- js = cJSON_Parse(buffer);
- if (js == NULL) {
- ret = -1;
- LOGW(TAG, "cJSON_Parse failed");
- goto out;
- }
- cJSON *code = cJSON_GetObjectItem(js, "code");
- if (!(code && cJSON_IsNumber(code))) {
- ret = -1;
- LOGW(TAG, "get code failed");
- goto out;
- }
- LOGD(TAG, "code: %d", code->valueint);
- if (code->valueint < 0) {
- ret = -1;
- goto out;
- }
- cJSON *result = cJSON_GetObjectItem(js, "result");
- if (!(result && cJSON_IsObject(result))) {
- LOGW(TAG, "get result failed");
- ret = -1;
- goto out;
- }
- cJSON *version = cJSON_GetObjectItem(result, "version");
- if (!(version && cJSON_IsString(version))) {
- LOGW(TAG, "get version failed");
- ret = -1;
- goto out;
- }
- LOGD(TAG, "version: %s", version->valuestring);
- aos_kv_setstring(COP_VERSION, version->valuestring);
- cJSON *url = cJSON_GetObjectItem(result, "url");
- if (!(url && cJSON_IsString(url))) {
- ret = -1;
- LOGW(TAG, "get url failed");
- goto out;
- }
- LOGD(TAG, "url: %s", url->valuestring);
- char *urlbuf = aos_malloc(156);
- if (urlbuf == NULL) {
- ret = -1;
- goto out;
- }
- rc = aos_kv_getstring(COP_IMG_URL, urlbuf, 156);
- if (rc <= 0) {
- aos_kv_setstring(COP_IMG_URL, url->valuestring);
- } else {
- if (strcmp(url->valuestring, urlbuf) == 0) {
- aos_kv_getint("fota_offset", &rc);
- LOGI(TAG, "continue fota :%d", rc);
- } else {
- aos_kv_setstring(COP_IMG_URL, url->valuestring);
- aos_kv_setint("fota_offset", 0);
- LOGI(TAG, "restart fota");
- }
- }
- aos_free(urlbuf);
- if (info->fota_url) {
- aos_free(info->fota_url);
- info->fota_url = NULL;
- }
- info->fota_url = strdup(url->valuestring);
- LOGD(TAG, "get url: %s", info->fota_url);
- out:
- if (buffer) aos_free(buffer);
- if (payload) aos_free(payload);
- if (js) cJSON_Delete(js);
- _http_cleanup(client);
- return ret;
- }
- #else
- #include "../http/http.h"
- #include "util/network.h"
- char *json_getvalue(char *body, char *key, int *len)
- {
- char key_buf[16];
- char *start_ptr, *end_ptr;
- snprintf(key_buf, 16, "\"%s\":", key);
- start_ptr = strstr(body, key_buf);
- if (start_ptr == NULL || body == start_ptr) {
- LOGD(TAG, "key");
- return NULL;
- }
- start_ptr += strlen(key_buf);
- while ((*start_ptr == ' ') || (*start_ptr == '\"') || (*start_ptr == 0)) {
- start_ptr++;
- }
- end_ptr = start_ptr;
- while (((*end_ptr != ',') && (*end_ptr != '\"')) && (*end_ptr != 0)) {
- end_ptr++;
- }
- if (start_ptr == end_ptr) {
- return NULL;
- }
- if (*end_ptr == '\"') {
- end_ptr --;
- }
- *len = end_ptr - start_ptr + 1;
- return start_ptr;
- }
- static int cop_get_ota_url(char *ota_url, int len)
- {
- int ret = -1;
- ret = aos_kv_getstring("otaurl", ota_url, len);
- if (ret < 0) {
- strcpy(ota_url, "http://occ.t-head.cn/api/image/ota/pull");
- }
- return ret;
- }
- static int cop_version_check(fota_info_t *info) {
- http_t *http;
- char *payload;
- char *body;
- int value_len;
- char *cptr;
- char getvalue[64];
- int rc;
- if ((payload = aos_malloc(156)) == NULL) {
- return -1;
- }
- snprintf(payload, 156, "{\"cid\":\"%s\",\"model\":\"%s\",\"version\":\"%s\"}",
- aos_get_device_id(), aos_get_product_model(), aos_get_app_version());
- //snprintf(payload, 100, "{\"cid\":\"%s\",\"model\":\"%s\",\"version\":\"%s\"}",
- // "00A2C6FB32241D9423F5AF00", "hlb_test", "1.0.0-20181125.1321-R-hlb_tes");
- LOGD(TAG, "check: %s", payload);
- memset(getvalue, 0, sizeof(getvalue));
- cop_get_ota_url(getvalue, sizeof(getvalue));
- if ((http = http_init(getvalue)) == NULL) {
- LOGD(TAG, "e cop http init");
- aos_free(payload);
- return -1;
- }
- memset(http->buffer, 0, BUFFER_SIZE);
- http->buffer_offset = 0;
- http_head_sets(http, "Host", http->host);
- http_head_seti(http, "Content-Length", strlen(payload));
- http_head_sets(http, "Connection", "keep-alive");
- http_head_sets(http, "Content-Type", "application/json");
- http_head_sets(http, "Cache-Control", "no-cache");
- http_post(http, payload, 10000);
- if (http_wait_resp(http, &body, 10000) < 0) {
- http_deinit(http);
- aos_free(payload);
- LOGD(TAG, "recv failed");
- return -1;
- }
- aos_free(payload);
- LOGD(TAG, "resp body: %s", body);
- cptr = json_getvalue(body, "code", &value_len);
- if ((cptr == NULL) || (atoi(cptr) < 0)) {
- LOGW(TAG, "rsp format");
- http_deinit(http);
- return -1;
- }
- cptr = json_getvalue(body, "version", &value_len);
- if (cptr == NULL) {
- LOGD(TAG, "rsp format %s", "version");
- http_deinit(http);
- return -1;
- }
- char *ver = aos_malloc(value_len + 1);
- if (!ver) {
- return -1;
- }
- memcpy(ver, cptr, value_len);
- ver[value_len] = 0;
- LOGD(TAG, "%s: %s", COP_VERSION, ver);
- aos_kv_setstring(COP_VERSION, ver);
- aos_free(ver);
- cptr = json_getvalue(body, "url", &value_len);
- if (cptr == NULL) {
- LOGD(TAG, "rsp format %s", "url");
- http_deinit(http);
- return -1;
- }
- if (http->url) {
- aos_free(http->url);
- http->url = NULL;
- }
- http->url = calloc(value_len + 1, 1);
- if (http->url == NULL) {
- LOGD(TAG, "realloc failed");
- http_deinit(http);
- return -1;
- }
- if (strstr(cptr, "https://")) {
- snprintf(http->url, value_len, "http://%s", cptr + strlen("https://"));
- } else {
- memcpy(http->url, cptr, value_len);
- }
- char *buffer = aos_malloc(156);
- if (buffer == NULL) {
- http_deinit(http);
- return -1;
- }
- rc = aos_kv_getstring(COP_IMG_URL, buffer, 156);
- if (rc <= 0) {
- aos_kv_setstring(COP_IMG_URL, http->url);
- } else {
- if (strcmp(http->url, buffer) == 0) {
- aos_kv_getint("fota_offset", &rc);
- LOGI(TAG, "continue fota :%d", rc);
- } else {
- aos_kv_setstring(COP_IMG_URL, http->url);
- aos_kv_setint("fota_offset", 0);
- LOGI(TAG, "restart fota");
- }
- }
- aos_free(buffer);
- if (info->fota_url) {
- aos_free(info->fota_url);
- info->fota_url = NULL;
- }
- if (info->changelog) {
- aos_free(info->changelog);
- info->changelog = NULL;
- }
- if (info->new_version) {
- aos_free(info->new_version);
- info->new_version = NULL;
- }
- info->fota_url = strdup(http->url);
- LOGD(TAG, "get url: %s", info->fota_url);
- http_deinit(http);
- return 0;
- }
- #endif /* CONFIG_FOTA_USE_HTTPC */
- static int finish(fota_info_t *info)
- {
- cop_res_release(info);
- return 0;
- }
- static int fail(fota_info_t *info)
- {
- cop_res_release(info);
- return 0;
- }
- const fota_cls_t fota_cop_cls = {
- "cop",
- NULL,
- cop_version_check,
- finish,
- fail,
- NULL
- };
- int fota_register_cop(void)
- {
- return fota_register(&fota_cop_cls);
- }
|