/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * Copyright (C) 2013-2021 iopsys Software Solutions AB * Author Omar Kallel */ #include #include #include #include "download.h" #include "ubus_utils.h" #include "cwmp_uci.h" #include "backupSession.h" #include "log.h" #include "event.h" LIST_HEAD(list_download); LIST_HEAD(list_schedule_download); LIST_HEAD(list_apply_schedule_download); pthread_mutex_t mutex_download = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t threshold_download; pthread_mutex_t mutex_schedule_download = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t threshold_schedule_download; pthread_mutex_t mutex_apply_schedule_download = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t threshold_apply_schedule_download; int count_download_queue = 0; /* * Download File */ int download_file(const char *file_path, const char *url, const char *username, const char *password) { if (url == NULL) { CWMP_LOG(ERROR, "download %s: no url specified", __FUNCTION__); return -1; } int res_code = 0; CURL *curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); if (username != NULL && strlen(username) > 0) { char userpass[1024]; snprintf(userpass, sizeof(userpass), "%s:%s", username, password ? password : ""); curl_easy_setopt(curl, CURLOPT_USERPWD, userpass); } if (strncmp(url, "https://", 8) == 0) curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 10000L); curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, 1L); if (file_path == NULL) { file_path = "/tmp/download_file"; } FILE *fp = fopen(file_path, "wb"); if (fp) { curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); curl_easy_perform(curl); fclose(fp); } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_code); curl_easy_cleanup(curl); } return res_code; } /* * Check if the downloaded image can be applied */ void ubus_check_image_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg) { if (msg == NULL) { CWMP_LOG(ERROR, "download %s: msg is null", __FUNCTION__); return; } int *code = (int *)req->priv; const struct blobmsg_policy p[2] = { { "code", BLOBMSG_TYPE_INT32 }, { "stdout", BLOBMSG_TYPE_STRING } }; struct blob_attr *tb[2] = { NULL, NULL }; blobmsg_parse(p, 2, tb, blobmsg_data(msg), blobmsg_len(msg)); *code = tb[0] ? blobmsg_get_u32(tb[0]) : 1; } int cwmp_check_image() { int code = 0, e; struct blob_buf b = { 0 }; memset(&b, 0, sizeof(struct blob_buf)); blob_buf_init(&b, 0); CWMP_LOG(INFO, "Check downloaded image ..."); e = icwmp_ubus_invoke("rpc-sys", "upgrade_test", b.head, ubus_check_image_callback, &code); if (e != 0) { CWMP_LOG(INFO, "rpc-sys upbrade_test ubus method failed: Ubus err code: %d", e); code = 1; } blob_buf_free(&b); return code; } /* * Get available bank */ void ubus_get_available_bank_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg) { if (msg == NULL) { CWMP_LOG(ERROR, "download %s: msg is null", __FUNCTION__); return; } int *bank_id = (int *)req->priv; if (bank_id == NULL) { CWMP_LOG(ERROR, "download %s: bank_id is null", __FUNCTION__); return; } struct blob_attr *banks = NULL; struct blob_attr *cur; int rem; blobmsg_for_each_attr(cur, msg, rem) { if (blobmsg_type(cur) == BLOBMSG_TYPE_ARRAY) { banks = cur; break; } } if (banks == NULL) { CWMP_LOG(ERROR, "download %s: banks is null", __FUNCTION__); return; } const struct blobmsg_policy p[8] = { { "name", BLOBMSG_TYPE_STRING }, { "id", BLOBMSG_TYPE_INT32 }, { "active", BLOBMSG_TYPE_BOOL }, { "upgrade", BLOBMSG_TYPE_BOOL }, { "fwver", BLOBMSG_TYPE_STRING }, { "swver", BLOBMSG_TYPE_STRING }, { "fwver", BLOBMSG_TYPE_STRING }, { "status", BLOBMSG_TYPE_STRING } }; blobmsg_for_each_attr(cur, banks, rem) { struct blob_attr *tb[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; blobmsg_parse(p, 8, tb, blobmsg_data(cur), blobmsg_len(cur)); if (!tb[0]) continue; if (blobmsg_get_bool(tb[2]) == false) { *bank_id = blobmsg_get_u32(tb[1]); break; } } } int get_available_bank_id() { int bank_id = 0, e; struct blob_buf b = { 0 }; memset(&b, 0, sizeof(struct blob_buf)); blob_buf_init(&b, 0); e = icwmp_ubus_invoke("fwbank", "dump", b.head, ubus_get_available_bank_callback, &bank_id); if (e != 0) { CWMP_LOG(INFO, "fwbank dump ubus method failed: Ubus err code: %d", e); } blob_buf_free(&b); return bank_id; } /* * Apply the new firmware */ int cwmp_apply_firmware() { int e; struct blob_buf b = { 0 }; memset(&b, 0, sizeof(struct blob_buf)); blob_buf_init(&b, 0); blobmsg_add_u8(&b, "keep", true); CWMP_LOG(INFO, "Apply downloaded image ..."); e = icwmp_ubus_invoke("rpc-sys", "upgrade_start", b.head, NULL, NULL); if (e != 0) { CWMP_LOG(INFO, "rpc-sys upgrade_start ubus method failed: Ubus err code: %d", e); } blob_buf_free(&b); return e; } int cwmp_apply_multiple_firmware() { int e; int bank_id = get_available_bank_id(); if (bank_id <= 0) return -1; struct blob_buf b = { 0 }; memset(&b, 0, sizeof(struct blob_buf)); blob_buf_init(&b, 0); bb_add_string(&b, "path", FIRMWARE_UPGRADE_IMAGE); blobmsg_add_u8(&b, "auto_activate", false); blobmsg_add_u32(&b, "bank", bank_id); e = icwmp_ubus_invoke("fwbank", "upgrade", b.head, NULL, NULL); blob_buf_free(&b); if (e != 0) { CWMP_LOG(INFO, "fwbank upgrade ubus method failed: Ubus err code: %d", e); return -1; } return CWMP_OK; } int cwmp_launch_download(struct download *pdownload, char *download_file_name, enum load_type ltype, struct transfer_complete **ptransfer_complete) { int error = FAULT_CPE_NO_FAULT; char *download_startTime; struct transfer_complete *p; download_startTime = get_time(time(NULL)); if (pdownload == NULL) { CWMP_LOG(ERROR, "download %s: pdownload is null", __FUNCTION__); error = FAULT_CPE_INTERNAL_ERROR; goto end_download; } ltype == TYPE_DOWNLOAD ? bkp_session_delete_download(pdownload) : bkp_session_delete_schedule_download(pdownload); bkp_session_save(); if (flashsize < pdownload->file_size) { error = FAULT_CPE_DOWNLOAD_FAILURE; goto end_download; } int http_code = download_file(ICWMP_DOWNLOAD_FILE, pdownload->url, pdownload->username, pdownload->password); if (http_code == 404) error = FAULT_CPE_DOWNLOAD_FAIL_CONTACT_SERVER; else if (http_code == 401) error = FAULT_CPE_DOWNLOAD_FAIL_FILE_AUTHENTICATION; else if (http_code != 200) { error = FAULT_CPE_DOWNLOAD_FAILURE; } if (error != FAULT_CPE_NO_FAULT) goto end_download; if (pdownload->file_type == NULL) { CWMP_LOG(ERROR, "download %s: pdownload.file_type is null", __FUNCTION__); error = FAULT_CPE_INVALID_ARGUMENTS; goto end_download; } if (strcmp(pdownload->file_type, FIRMWARE_UPGRADE_IMAGE_FILE_TYPE) == 0 || strcmp(pdownload->file_type, STORED_FIRMWARE_IMAGE_FILE_TYPE) == 0) { rename(ICWMP_DOWNLOAD_FILE, FIRMWARE_UPGRADE_IMAGE); if (cwmp_check_image() == 0) { long int file_size = get_file_size(FIRMWARE_UPGRADE_IMAGE); if (file_size > flashsize) { error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; remove(FIRMWARE_UPGRADE_IMAGE); goto end_download; } else { error = FAULT_CPE_NO_FAULT; goto end_download; } } else { error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; remove(FIRMWARE_UPGRADE_IMAGE); } } else if (strcmp(pdownload->file_type, WEB_CONTENT_FILE_TYPE) == 0) { //TODO Not Supported error = FAULT_CPE_NO_FAULT; } else if (strcmp(pdownload->file_type, VENDOR_CONFIG_FILE_TYPE) == 0) { if (download_file_name != NULL) { char file_path[512]; snprintf(file_path, sizeof(file_path), "/tmp/%s", download_file_name); rename(ICWMP_DOWNLOAD_FILE, file_path); } else rename(ICWMP_DOWNLOAD_FILE, VENDOR_CONFIG_FILE); error = FAULT_CPE_NO_FAULT; } else if (strcmp(pdownload->file_type, TONE_FILE_TYPE) == 0) { //TODO Not Supported error = FAULT_CPE_NO_FAULT; } else if (strcmp(pdownload->file_type, RINGER_FILE_TYPE) == 0) { //TODO Not Supported error = FAULT_CPE_NO_FAULT; } else { remove(ICWMP_DOWNLOAD_FILE); error = FAULT_CPE_INVALID_ARGUMENTS; } end_download: p = calloc(1, sizeof(struct transfer_complete)); if (p == NULL) { error = FAULT_CPE_INTERNAL_ERROR; return error; } p->command_key = pdownload->command_key ? strdup(pdownload->command_key) : strdup(""); p->start_time = strdup(download_startTime ? download_startTime : ""); p->complete_time = strdup(get_time(time(NULL))); p->type = ltype; if (error != FAULT_CPE_NO_FAULT) { p->fault_code = error; } *ptransfer_complete = p; return error; } char *get_file_name_by_download_url(char *url) { if (url == NULL) { CWMP_LOG(ERROR, "download %s: url is null", __FUNCTION__); return NULL; } char *slash = strrchr(url, '/'); if (slash == NULL) return NULL; return slash+1; } int apply_downloaded_file(struct cwmp *cwmp, struct download *pdownload, char *download_file_name, struct transfer_complete *ptransfer_complete) { if (pdownload == NULL) { CWMP_LOG(ERROR, "download %s: pdownload is null", __FUNCTION__); return FAULT_CPE_INTERNAL_ERROR; } if (pdownload->file_type == NULL) { CWMP_LOG(ERROR, "download %s: pdownload filetype is null", __FUNCTION__); return FAULT_CPE_INTERNAL_ERROR; } if (ptransfer_complete== NULL) { CWMP_LOG(ERROR, "download %s: ptransfer_complete is null", __FUNCTION__); return FAULT_CPE_INTERNAL_ERROR; } int error = FAULT_CPE_NO_FAULT; if (pdownload->file_type[0] == '1') { ptransfer_complete->old_software_version = cwmp->deviceid.softwareversion; } bkp_session_insert_transfer_complete(ptransfer_complete); bkp_session_save(); if (strcmp(pdownload->file_type, FIRMWARE_UPGRADE_IMAGE_FILE_TYPE) == 0) { cwmp_uci_set_value("cwmp", "cpe", "exec_download", "1"); cwmp_commit_package("cwmp", UCI_STANDARD_CONFIG); if (cwmp_apply_firmware() != 0) error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; if (error == FAULT_CPE_NO_FAULT) { sleep(70); error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; } } else if (strcmp(pdownload->file_type, WEB_CONTENT_FILE_TYPE) == 0) { //TODO Not Supported error = FAULT_CPE_NO_FAULT; } else if (strcmp(pdownload->file_type, VENDOR_CONFIG_FILE_TYPE) == 0) { cwmp_uci_init(); int err = CWMP_OK; if (download_file_name != NULL) { char file_path[512]; snprintf(file_path, sizeof(file_path), "/tmp/%s", download_file_name); err = cwmp_uci_import(download_file_name, file_path, UCI_STANDARD_CONFIG); remove(file_path); } else { err = cwmp_uci_import("vendor_conf_file", VENDOR_CONFIG_FILE, UCI_STANDARD_CONFIG); remove(VENDOR_CONFIG_FILE); } cwmp_uci_exit(); if (err == CWMP_OK) error = FAULT_CPE_NO_FAULT; else if (err == CWMP_GEN_ERR) error = FAULT_CPE_INTERNAL_ERROR; else if (err == -1) error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; } else if (strcmp(pdownload->file_type, TONE_FILE_TYPE) == 0) { //TODO Not Supported error = FAULT_CPE_NO_FAULT; } else if (strcmp(pdownload->file_type, RINGER_FILE_TYPE) == 0) { //TODO Not Supported error = FAULT_CPE_NO_FAULT; } else if (strcmp(pdownload->file_type, STORED_FIRMWARE_IMAGE_FILE_TYPE) == 0) { int err = cwmp_apply_multiple_firmware(); if (err == CWMP_OK) error = FAULT_CPE_NO_FAULT; else error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; } else error = FAULT_CPE_INVALID_ARGUMENTS; if ((error == FAULT_CPE_NO_FAULT) && (pdownload->file_type[0] == '1' || pdownload->file_type[0] == '3')) { cwmp_uci_set_varstate_value("cwmp", "cpe", "ParameterKey", pdownload->command_key ? pdownload->command_key : ""); cwmp_commit_package("cwmp", UCI_VARSTATE_CONFIG); if (pdownload->file_type[0] == '3') { CWMP_LOG(INFO, "Download and apply new vendor config file is done successfully"); cwmp_root_cause_transfer_complete(cwmp, ptransfer_complete); bkp_session_delete_transfer_complete(ptransfer_complete); } return FAULT_CPE_NO_FAULT; } if (error != FAULT_CPE_NO_FAULT) { bkp_session_delete_transfer_complete(ptransfer_complete); ptransfer_complete->fault_code = error; } bkp_session_insert_transfer_complete(ptransfer_complete); bkp_session_save(); cwmp_root_cause_transfer_complete(cwmp, ptransfer_complete); return error; } struct transfer_complete *set_download_error_transfer_complete(struct cwmp *cwmp, struct download *pdownload, enum load_type ltype) { if (pdownload == NULL) { CWMP_LOG(ERROR, "download %s: pdownload is null", __FUNCTION__); return NULL; } struct transfer_complete *ptransfer_complete; ptransfer_complete = calloc(1, sizeof(struct transfer_complete)); if (ptransfer_complete != NULL) { ptransfer_complete->command_key = strdup(pdownload->command_key ? pdownload->command_key : ""); ptransfer_complete->start_time = strdup(get_time(time(NULL))); ptransfer_complete->complete_time = strdup(ptransfer_complete->start_time ? ptransfer_complete->start_time : ""); ptransfer_complete->fault_code = ltype == TYPE_DOWNLOAD ? FAULT_CPE_DOWNLOAD_FAILURE : FAULT_CPE_DOWNLOAD_FAIL_WITHIN_TIME_WINDOW; ptransfer_complete->type = ltype; bkp_session_insert_transfer_complete(ptransfer_complete); cwmp_root_cause_transfer_complete(cwmp, ptransfer_complete); } return ptransfer_complete; } void *thread_cwmp_rpc_cpe_download(void *v) { struct cwmp *cwmp = (struct cwmp *)v; struct download *pdownload; struct timespec download_timeout = { 0, 0 }; time_t current_time, stime; int error; struct transfer_complete *ptransfer_complete; long int time_of_grace = 3600, timeout; sleep(3); for (;;) { if (thread_end) break; if (list_download.next != &(list_download)) { pdownload = list_entry(list_download.next, struct download, list); stime = pdownload->scheduled_time; current_time = time(NULL); if (pdownload->scheduled_time != 0) timeout = current_time - pdownload->scheduled_time; else timeout = 0; if ((timeout >= 0) && (timeout > time_of_grace)) { pthread_mutex_lock(&mutex_download); bkp_session_delete_download(pdownload); error = FAULT_CPE_DOWNLOAD_FAILURE; ptransfer_complete = set_download_error_transfer_complete(cwmp, pdownload, TYPE_DOWNLOAD); list_del(&(pdownload->list)); if (pdownload->scheduled_time != 0) count_download_queue--; cwmp_free_download_request(pdownload); pthread_mutex_unlock(&mutex_download); continue; } if ((timeout >= 0) && (timeout <= time_of_grace)) { pthread_mutex_lock(&(cwmp->mutex_session_send)); char *download_file_name = get_file_name_by_download_url(pdownload->url); CWMP_LOG(INFO, "Launch download file %s", pdownload->url); error = cwmp_launch_download(pdownload, download_file_name, TYPE_DOWNLOAD, &ptransfer_complete); sleep(3); if (error != FAULT_CPE_NO_FAULT) { bkp_session_insert_transfer_complete(ptransfer_complete); bkp_session_save(); cwmp_root_cause_transfer_complete(cwmp, ptransfer_complete); bkp_session_delete_transfer_complete(ptransfer_complete); } else { error = apply_downloaded_file(cwmp, pdownload, download_file_name, ptransfer_complete); if (error || pdownload->file_type[0] == '6') bkp_session_delete_transfer_complete(ptransfer_complete); } if (pdownload->file_type[0] == '6') sleep(30); pthread_mutex_unlock(&(cwmp->mutex_session_send)); pthread_cond_signal(&(cwmp->threshold_session_send)); pthread_mutex_lock(&mutex_download); list_del(&(pdownload->list)); if (pdownload->scheduled_time != 0) count_download_queue--; cwmp_free_download_request(pdownload); pthread_mutex_unlock(&mutex_download); continue; } pthread_mutex_lock(&mutex_download); download_timeout.tv_sec = stime; pthread_cond_timedwait(&threshold_download, &mutex_download, &download_timeout); pthread_mutex_unlock(&mutex_download); } else { pthread_mutex_lock(&mutex_download); pthread_cond_wait(&threshold_download, &mutex_download); pthread_mutex_unlock(&mutex_download); } } return NULL; } int cwmp_add_apply_schedule_download(struct download *schedule_download, char *start_time) { int i = 0; int error = FAULT_CPE_NO_FAULT; struct apply_schedule_download *apply_schedule_download = NULL; if (schedule_download == NULL) { CWMP_LOG(ERROR, "download %s: pdownload is null", __FUNCTION__); error = FAULT_CPE_INTERNAL_ERROR; goto end; } apply_schedule_download = calloc(1, sizeof(struct apply_schedule_download)); if (apply_schedule_download == NULL) { error = FAULT_CPE_INTERNAL_ERROR; goto end; } if (error == FAULT_CPE_NO_FAULT) { pthread_mutex_lock(&mutex_apply_schedule_download); apply_schedule_download->command_key = strdup(schedule_download->command_key ? schedule_download->command_key : ""); apply_schedule_download->file_type = strdup(schedule_download->file_type ? schedule_download->file_type : ""); apply_schedule_download->start_time = strdup(start_time ? start_time : ""); for (i = 0; i < 2; i++) { apply_schedule_download->timeintervals[i].windowstart = schedule_download->timewindowstruct[i].windowstart; apply_schedule_download->timeintervals[i].windowend = schedule_download->timewindowstruct[i].windowend; apply_schedule_download->timeintervals[i].maxretries = schedule_download->timewindowstruct[i].maxretries; } list_add_tail(&(apply_schedule_download->list), &(list_apply_schedule_download)); bkp_session_insert_apply_schedule_download(apply_schedule_download); bkp_session_save(); pthread_mutex_unlock(&mutex_apply_schedule_download); pthread_cond_signal(&threshold_apply_schedule_download); } end: cwmp_free_apply_schedule_download_request(apply_schedule_download); return 0; } void *thread_cwmp_rpc_cpe_schedule_download(void *v) { struct cwmp *cwmp = (struct cwmp *)v; struct timespec download_timeout = { 0, 0 }; int error = FAULT_CPE_NO_FAULT; struct transfer_complete *ptransfer_complete; int min_time = 0; struct download *current_download = NULL; struct download *p, *_p; for (;;) { time_t current_time; if (thread_end) break; current_time = time(NULL); if (list_schedule_download.next != &(list_schedule_download)) { list_for_each_entry_safe (p, _p, &(list_schedule_download), list) { if (min_time == 0) { if (p->timewindowstruct[0].windowend >= current_time) { min_time = p->timewindowstruct[0].windowstart; current_download = p; } else if (p->timewindowstruct[1].windowend >= current_time) { min_time = p->timewindowstruct[1].windowstart; current_download = p; } else { pthread_mutex_lock(&mutex_schedule_download); bkp_session_delete_schedule_download(p); error = FAULT_CPE_DOWNLOAD_FAIL_WITHIN_TIME_WINDOW; ptransfer_complete = set_download_error_transfer_complete(cwmp, p, TYPE_SCHEDULE_DOWNLOAD); list_del(&(p->list)); if (p->timewindowstruct[0].windowstart != 0) count_download_queue--; cwmp_free_schedule_download_request(p); pthread_mutex_unlock(&mutex_schedule_download); continue; } } else { if (p->timewindowstruct[0].windowend >= current_time) { if (p->timewindowstruct[0].windowstart < min_time) { min_time = p->timewindowstruct[0].windowstart; current_download = p; } } else if (p->timewindowstruct[1].windowend >= current_time) { if (p->timewindowstruct[1].windowstart < min_time) { min_time = p->timewindowstruct[1].windowstart; current_download = p; } } else { pthread_mutex_lock(&mutex_schedule_download); bkp_session_delete_schedule_download(p); error = FAULT_CPE_DOWNLOAD_FAIL_WITHIN_TIME_WINDOW; ptransfer_complete = set_download_error_transfer_complete(cwmp, p, TYPE_SCHEDULE_DOWNLOAD); list_del(&(p->list)); if (p->timewindowstruct[0].windowstart != 0) count_download_queue--; cwmp_free_schedule_download_request(p); pthread_mutex_unlock(&mutex_schedule_download); continue; } } } } else { pthread_mutex_lock(&mutex_schedule_download); pthread_cond_wait(&threshold_schedule_download, &mutex_schedule_download); pthread_mutex_unlock(&mutex_schedule_download); } if (min_time == 0) { continue; } else if (min_time <= current_time) { char *download_file_name = get_file_name_by_download_url(current_download->url); if ((min_time == current_download->timewindowstruct[0].windowstart && (current_download->timewindowstruct[0].windowmode)[0] == '2') || (min_time == current_download->timewindowstruct[1].windowstart && (current_download->timewindowstruct[1].windowmode)[0] == '2')) { pthread_mutex_lock(&mutex_schedule_download); ptransfer_complete = calloc(1, sizeof(struct transfer_complete)); ptransfer_complete->type = TYPE_SCHEDULE_DOWNLOAD; error = cwmp_launch_download(current_download, download_file_name, TYPE_SCHEDULE_DOWNLOAD, &ptransfer_complete); if (error != FAULT_CPE_NO_FAULT) { bkp_session_insert_transfer_complete(ptransfer_complete); bkp_session_save(); cwmp_root_cause_transfer_complete(cwmp, ptransfer_complete); bkp_session_delete_transfer_complete(ptransfer_complete); } else { pthread_mutex_unlock(&mutex_schedule_download); if (pthread_mutex_trylock(&(cwmp->mutex_session_send)) == 0) { pthread_mutex_lock(&mutex_apply_schedule_download); pthread_mutex_lock(&mutex_schedule_download); error = apply_downloaded_file(cwmp, current_download, download_file_name, ptransfer_complete); if (error == FAULT_CPE_NO_FAULT) exit(EXIT_SUCCESS); pthread_mutex_unlock(&mutex_schedule_download); pthread_mutex_unlock(&mutex_apply_schedule_download); pthread_mutex_unlock(&(cwmp->mutex_session_send)); pthread_cond_signal(&(cwmp->threshold_session_send)); } else { cwmp_add_apply_schedule_download(current_download, ptransfer_complete->start_time); } } pthread_mutex_lock(&mutex_schedule_download); bkp_session_delete_schedule_download(current_download); bkp_session_save(); list_del(&(current_download->list)); cwmp_free_schedule_download_request(current_download); pthread_mutex_unlock(&mutex_schedule_download); min_time = 0; current_download = NULL; continue; } //AT ANY TIME OR WHEN IDLE else { pthread_mutex_lock(&(cwmp->mutex_session_send)); CWMP_LOG(INFO, "Launch download file %s", current_download->url); error = cwmp_launch_download(current_download, download_file_name, TYPE_SCHEDULE_DOWNLOAD, &ptransfer_complete); if (error != FAULT_CPE_NO_FAULT) { bkp_session_insert_transfer_complete(ptransfer_complete); bkp_session_save(); cwmp_root_cause_transfer_complete(cwmp, ptransfer_complete); bkp_session_delete_transfer_complete(ptransfer_complete); } else { error = apply_downloaded_file(cwmp, current_download, download_file_name, ptransfer_complete); if (error == FAULT_CPE_NO_FAULT) exit(EXIT_SUCCESS); } pthread_mutex_unlock(&(cwmp->mutex_session_send)); pthread_cond_signal(&(cwmp->threshold_session_send)); pthread_mutex_lock(&mutex_schedule_download); list_del(&(current_download->list)); if (current_download->timewindowstruct[0].windowstart != 0) count_download_queue--; cwmp_free_schedule_download_request(current_download); pthread_mutex_unlock(&mutex_schedule_download); continue; } } else { if (min_time == current_download->timewindowstruct[0].windowstart) { pthread_mutex_lock(&mutex_schedule_download); download_timeout.tv_sec = min_time; pthread_cond_timedwait(&threshold_schedule_download, &mutex_schedule_download, &download_timeout); pthread_mutex_unlock(&mutex_schedule_download); } else if (min_time == current_download->timewindowstruct[1].windowstart) { pthread_mutex_lock(&mutex_schedule_download); download_timeout.tv_sec = min_time; pthread_cond_timedwait(&threshold_schedule_download, &mutex_schedule_download, &download_timeout); pthread_mutex_unlock(&mutex_schedule_download); } } } return NULL; } void *thread_cwmp_rpc_cpe_apply_schedule_download(void *v) { struct cwmp *cwmp = (struct cwmp *)v; struct timespec apply_timeout = { 0, 0 }; int error = FAULT_CPE_NO_FAULT; struct transfer_complete *ptransfer_complete; int min_time = 0; struct apply_schedule_download *apply_download = NULL; struct apply_schedule_download *p, *_p; for (;;) { time_t current_time; if (thread_end) break; current_time = time(NULL); if (list_apply_schedule_download.next != &(list_apply_schedule_download)) { list_for_each_entry_safe (p, _p, &(list_apply_schedule_download), list) { if (min_time == 0) { if (p->timeintervals[0].windowend >= current_time) { min_time = p->timeintervals[0].windowstart; apply_download = p; } else if (p->timeintervals[1].windowend >= current_time) { min_time = p->timeintervals[1].windowstart; apply_download = p; } else { pthread_mutex_lock(&mutex_apply_schedule_download); bkp_session_delete_apply_schedule_download(p); error = FAULT_CPE_DOWNLOAD_FAIL_WITHIN_TIME_WINDOW; ptransfer_complete = set_download_error_transfer_complete(cwmp, (struct download *)p, TYPE_SCHEDULE_DOWNLOAD); list_del(&(p->list)); if (p->timeintervals[0].windowstart != 0) count_download_queue--; cwmp_free_apply_schedule_download_request(p); pthread_mutex_unlock(&mutex_apply_schedule_download); continue; } } else { if (p->timeintervals[0].windowend >= current_time) { if (p->timeintervals[0].windowstart < min_time) { min_time = p->timeintervals[0].windowstart; apply_download = p; } } else if (p->timeintervals[1].windowend >= current_time) { if (p->timeintervals[1].windowstart < min_time) { min_time = p->timeintervals[1].windowstart; apply_download = p; } } else { pthread_mutex_lock(&mutex_apply_schedule_download); bkp_session_delete_apply_schedule_download(p); error = FAULT_CPE_DOWNLOAD_FAIL_WITHIN_TIME_WINDOW; ptransfer_complete = set_download_error_transfer_complete(cwmp, (struct download *)p, TYPE_SCHEDULE_DOWNLOAD); list_del(&(p->list)); /*if(p->timewindowintervals[0].windowstart != 0) count_download_queue--;*/ cwmp_free_apply_schedule_download_request(p); pthread_mutex_unlock(&mutex_apply_schedule_download); continue; } } } } else { pthread_mutex_lock(&mutex_apply_schedule_download); pthread_cond_wait(&threshold_apply_schedule_download, &mutex_apply_schedule_download); pthread_mutex_unlock(&mutex_apply_schedule_download); } if (min_time == 0) { continue; } else if (min_time <= current_time) { pthread_mutex_lock(&(cwmp->mutex_session_send)); pthread_mutex_lock(&mutex_schedule_download); bkp_session_delete_apply_schedule_download(apply_download); bkp_session_save(); ptransfer_complete = calloc(1, sizeof(struct transfer_complete)); if (apply_download->file_type[0] == '1') { ptransfer_complete->old_software_version = cwmp->deviceid.softwareversion; } ptransfer_complete->command_key = strdup(apply_download->command_key); ptransfer_complete->start_time = strdup(apply_download->start_time); ptransfer_complete->complete_time = strdup(get_time(time(NULL))); ptransfer_complete->fault_code = error; ptransfer_complete->type = TYPE_SCHEDULE_DOWNLOAD; bkp_session_insert_transfer_complete(ptransfer_complete); bkp_session_save(); if (strcmp(apply_download->file_type, FIRMWARE_UPGRADE_IMAGE_FILE_TYPE) == 0) { cwmp_uci_set_value("cwmp", "cpe", "exec_download", "1"); cwmp_commit_package("cwmp", UCI_STANDARD_CONFIG); cwmp_apply_firmware(); sleep(70); error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; } else if (strcmp(apply_download->file_type, WEB_CONTENT_FILE_TYPE) == 0) { //TODO Not Supported error = FAULT_CPE_NO_FAULT; } else if (strcmp(apply_download->file_type, VENDOR_CONFIG_FILE_TYPE) == 0) { cwmp_uci_init(); int err = cwmp_uci_import(NULL, VENDOR_CONFIG_FILE, UCI_STANDARD_CONFIG); cwmp_uci_exit(); if (err == CWMP_OK) error = FAULT_CPE_NO_FAULT; else if (err == CWMP_GEN_ERR) error = FAULT_CPE_INTERNAL_ERROR; else if (err == -1) error = FAULT_CPE_DOWNLOAD_FAIL_FILE_CORRUPTED; } if ((error == FAULT_CPE_NO_FAULT) && (apply_download->file_type[0] == '1' || apply_download->file_type[0] == '3')) { if (apply_download->file_type[0] == '3') { CWMP_LOG(INFO, "Download and apply new vendor config file is done successfully"); } exit(EXIT_SUCCESS); } if (error != FAULT_CPE_NO_FAULT) { bkp_session_delete_transfer_complete(ptransfer_complete); ptransfer_complete->fault_code = error; } bkp_session_insert_transfer_complete(ptransfer_complete); bkp_session_save(); cwmp_root_cause_transfer_complete(cwmp, ptransfer_complete); pthread_mutex_unlock(&mutex_schedule_download); pthread_mutex_unlock(&(cwmp->mutex_session_send)); pthread_cond_signal(&(cwmp->threshold_session_send)); pthread_mutex_lock(&mutex_apply_schedule_download); list_del(&(apply_download->list)); /*if(pdownload->timeintervals[0].windowstart != 0) count_download_queue--;*/ cwmp_free_apply_schedule_download_request(apply_download); pthread_mutex_unlock(&mutex_apply_schedule_download); continue; } else { if (min_time == apply_download->timeintervals[0].windowstart) { pthread_mutex_lock(&mutex_apply_schedule_download); apply_timeout.tv_sec = min_time; pthread_cond_timedwait(&threshold_apply_schedule_download, &mutex_schedule_download, &apply_timeout); pthread_mutex_unlock(&mutex_apply_schedule_download); } else if (min_time == apply_download->timeintervals[1].windowstart) { pthread_mutex_lock(&mutex_apply_schedule_download); apply_timeout.tv_sec = min_time; pthread_cond_timedwait(&threshold_schedule_download, &mutex_schedule_download, &apply_timeout); pthread_mutex_unlock(&mutex_schedule_download); } } } return NULL; } int cwmp_free_download_request(struct download *download) { if (download != NULL) { if (download->command_key != NULL) free(download->command_key); if (download->file_type != NULL) free(download->file_type); if (download->url != NULL) free(download->url); if (download->username != NULL) free(download->username); if (download->password != NULL) free(download->password); free(download); } return CWMP_OK; } int cwmp_free_schedule_download_request(struct download *schedule_download) { if (schedule_download != NULL) { if (schedule_download->command_key != NULL) free(schedule_download->command_key); if (schedule_download->file_type != NULL) free(schedule_download->file_type); if (schedule_download->url != NULL) free(schedule_download->url); if (schedule_download->username != NULL) free(schedule_download->username); if (schedule_download->password != NULL) free(schedule_download->password); for (int i = 0; i <= 1; i++) { if (schedule_download->timewindowstruct[i].windowmode != NULL) free(schedule_download->timewindowstruct[i].windowmode); if (schedule_download->timewindowstruct[i].usermessage != NULL) free(schedule_download->timewindowstruct[i].usermessage); } free(schedule_download); } return CWMP_OK; } int cwmp_free_apply_schedule_download_request(struct apply_schedule_download *apply_schedule_download) { if (apply_schedule_download != NULL) { if (apply_schedule_download->command_key != NULL) free(apply_schedule_download->command_key); if (apply_schedule_download->file_type != NULL) free(apply_schedule_download->file_type); if (apply_schedule_download->start_time != NULL) free(apply_schedule_download->start_time); free(apply_schedule_download); } return CWMP_OK; } int cwmp_scheduledDownload_remove_all() { pthread_mutex_lock(&mutex_download); while (list_download.next != &(list_download)) { struct download *download; download = list_entry(list_download.next, struct download, list); list_del(&(download->list)); bkp_session_delete_download(download); if (download->scheduled_time != 0) count_download_queue--; cwmp_free_download_request(download); } pthread_mutex_unlock(&mutex_download); return CWMP_OK; } int cwmp_scheduled_Download_remove_all() { pthread_mutex_lock(&mutex_schedule_download); while (list_schedule_download.next != &(list_schedule_download)) { struct download *schedule_download; schedule_download = list_entry(list_schedule_download.next, struct download, list); list_del(&(schedule_download->list)); bkp_session_delete_schedule_download(schedule_download); if (schedule_download->timewindowstruct[0].windowstart != 0) count_download_queue--; cwmp_free_schedule_download_request(schedule_download); } pthread_mutex_unlock(&mutex_schedule_download); return CWMP_OK; } int cwmp_apply_scheduled_Download_remove_all() { pthread_mutex_lock(&mutex_apply_schedule_download); while (list_apply_schedule_download.next != &(list_apply_schedule_download)) { struct apply_schedule_download *apply_schedule_download; apply_schedule_download = list_entry(list_apply_schedule_download.next, struct apply_schedule_download, list); list_del(&(apply_schedule_download->list)); bkp_session_delete_apply_schedule_download(apply_schedule_download); /*if(apply_schedule_download->timetimeintervals[0].windowstart != 0) count_download_queue--;*/ //TOCK cwmp_free_apply_schedule_download_request(apply_schedule_download); } pthread_mutex_unlock(&mutex_apply_schedule_download); return CWMP_OK; } int cwmp_rpc_acs_destroy_data_transfer_complete(struct session *session __attribute__((unused)), struct rpc *rpc) { if (rpc->extra_data != NULL) { struct transfer_complete *p = (struct transfer_complete *)rpc->extra_data; bkp_session_delete_transfer_complete(p); bkp_session_save(); FREE(p->command_key); FREE(p->start_time); FREE(p->complete_time); FREE(p->old_software_version); } FREE(rpc->extra_data); return 0; }