Ticket #6702: icwmp: migrate from multithreading to uloop (Download/Upload)

This commit is contained in:
Omar Kallel 2022-01-18 16:22:46 +01:00
parent de3f2b2f7e
commit 63d713ea85
26 changed files with 543 additions and 216 deletions

View file

@ -862,6 +862,7 @@ void load_download(mxml_node_t *tree)
.file_size = &download_request->file_size,
.time = &download_request->scheduled_time };
load_specific_backup_attributes(tree, &bkp_attrs);
download_request->handler_timer.cb = cwmp_start_download;
list_for_each (ilist, &(list_download)) {
idownload_request = list_entry(ilist, struct download, list);
@ -872,6 +873,7 @@ void load_download(mxml_node_t *tree)
list_add(&(download_request->list), ilist->prev);
if (download_request->scheduled_time != 0)
count_download_queue++;
cwmp_set_end_session(END_SESSION_DOWNLOAD);
}
void load_schedule_download(mxml_node_t *tree)

View file

@ -21,6 +21,7 @@ icwmpd_SOURCES = \
../notifications.c \
../cwmp_zlib.c \
../cwmp_du_state.c \
../subprocess.c \
../download.c \
../upload.c \
../sched_inform.c \

View file

@ -628,11 +628,11 @@ end:
int cwmp_get_deviceid()
{
cwmp_get_leaf_value("Device.DeviceInfo.Manufacturer", &cwmp->deviceid.manufacturer);
cwmp_get_leaf_value("Device.DeviceInfo.SerialNumber", &cwmp->deviceid.serialnumber);
cwmp_get_leaf_value("Device.DeviceInfo.ProductClass", &cwmp->deviceid.productclass);
cwmp_get_leaf_value("Device.DeviceInfo.ManufacturerOUI", &cwmp->deviceid.oui);
cwmp_get_leaf_value("Device.DeviceInfo.SoftwareVersion", &cwmp->deviceid.softwareversion);
cwmp_get_leaf_value("Device.DeviceInfo.Manufacturer", &cwmp_main->deviceid.manufacturer);
cwmp_get_leaf_value("Device.DeviceInfo.SerialNumber", &cwmp_main->deviceid.serialnumber);
cwmp_get_leaf_value("Device.DeviceInfo.ProductClass", &cwmp_main->deviceid.productclass);
cwmp_get_leaf_value("Device.DeviceInfo.ManufacturerOUI", &cwmp_main->deviceid.oui);
cwmp_get_leaf_value("Device.DeviceInfo.SoftwareVersion", &cwmp_main->deviceid.softwareversion);
return CWMP_OK;
}

11
cwmp.c
View file

@ -387,16 +387,7 @@ static void cwmp_exit()
void cwmp_end_handler(int signal_num __attribute__((unused)))
{
cwmp_stop = true;
if (cwmp_main->session->session_status.last_status == SESSION_RUNNING)
http_set_timeout();
uloop_timeout_cancel(&retry_session_timer);
uloop_timeout_cancel(&priodic_session_timer);
uloop_timeout_cancel(&session_timer);
uloop_end();
shutdown(cwmp_main->cr_socket_desc, SHUT_RDWR);
cwmp_ubus_call("tr069", "exit", CWMP_UBUS_ARGS{ {} }, 0, NULL, NULL);
}
int main(int argc, char **argv)

View file

@ -9,6 +9,7 @@
*/
#include <curl/curl.h>
#include <libubox/blobmsg_json.h>
#include "common.h"
#include "download.h"
@ -19,13 +20,14 @@
#include "cwmp_time.h"
#include "event.h"
#include "cwmp_uci.h"
#include "session.h"
#include "subprocess.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;
@ -70,6 +72,57 @@ int download_file(const char *file_path, const char *url, const char *username,
return res_code;
}
char *download_file_task_function(char *task)
{
struct blob_buf bbuf;
memset(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
if (blobmsg_add_json_from_string(&bbuf, task) == false) {
blob_buf_free(&bbuf);
return NULL;
}
const struct blobmsg_policy p[5] = { { "task", BLOBMSG_TYPE_STRING }, { "file_path", BLOBMSG_TYPE_STRING }, { "url", BLOBMSG_TYPE_STRING }, { "username", BLOBMSG_TYPE_STRING }, { "password", BLOBMSG_TYPE_STRING } };
struct blob_attr *tb[5] = { NULL, NULL, NULL, NULL, NULL};
blobmsg_parse(p, 5, tb, blobmsg_data(bbuf.head), blobmsg_len(bbuf.head));
char *task_name = blobmsg_get_string(tb[0]);
if (!task_name || strcmp(task_name, "download") != 0)
return NULL;
char *file_path = blobmsg_get_string(tb[1]);
char *url = blobmsg_get_string(tb[2]);
char *username = blobmsg_get_string(tb[3]);
char *password = blobmsg_get_string(tb[4]);
int http_code = download_file(file_path, url, username, password);
char *http_ret = (char *)malloc(4 * sizeof(char));
snprintf(http_ret, 4, "%d", http_code);
http_ret[3] = 0;
return http_ret;
}
int download_file_in_subprocess(const char *file_path, const char *url, const char *username, const char *password)
{
subprocess_start(download_file_task_function);
struct blob_buf bbuf;
memset(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
blobmsg_add_string(&bbuf, "task", "download");
blobmsg_add_string(&bbuf, "file_path", file_path ? file_path : "");
blobmsg_add_string(&bbuf, "url", url ? url : "");
blobmsg_add_string(&bbuf, "username", username ? username : "");
blobmsg_add_string(&bbuf, "password", password ? password : "");
char *download_task = blobmsg_format_json(bbuf.head, true);
blob_buf_free(&bbuf);
if (download_task != NULL) {
char *ret = execute_task_in_subprocess(download_task);
return atoi(ret);
}
return 500;
}
/*
* Check if the downloaded image can be applied
*/
@ -140,6 +193,58 @@ int get_available_bank_id()
return bank_id;
}
/*
* Get Bank Status
*/
void ubus_get_bank_status_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
int *bank_id = (int *)req->priv;
int *status = bank_id;
bool bank_found = false;
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;
}
}
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_u32(tb[1]) == (uint32_t)*bank_id) {
bank_found = true;
if (strcmp(blobmsg_get_string(tb[7]), "Available") == 0 || strcmp(blobmsg_get_string(tb[7]), "Active"))
*status = 1;
else
*status = 0;
}
}
if (bank_found == false)
*status = 0;
}
int get_applied_firmware_status(int *bank_id_status)
{
int e;
e = cwmp_ubus_call("fwbank", "dump", CWMP_UBUS_ARGS{ {} }, 0, ubus_get_bank_status_callback, &bank_id_status);
if (e != 0) {
CWMP_LOG(INFO, "fwbank dump ubus method failed: Ubus err code: %d", e);
}
return e;
}
/*
* Apply the new firmware
*/
@ -154,6 +259,24 @@ int cwmp_apply_firmware()
return e;
}
void wait_firmware_to_be_applied(int bank_id)
{
int count = 0;
do {
int bank_id_status = bank_id;
if (get_applied_firmware_status(&bank_id_status) != CWMP_OK)
break;
if (bank_id_status == 1)
break;
usleep(1000 * 1000);
count++;
} while(count < 15);
}
int cwmp_apply_multiple_firmware()
{
int e;
@ -166,9 +289,28 @@ int cwmp_apply_multiple_firmware()
CWMP_LOG(INFO, "fwbank upgrade ubus method failed: Ubus err code: %d", e);
return -1;
}
//wait until the apply completes
wait_firmware_to_be_applied(bank_id);
return CWMP_OK;
}
char *apply_multiple_firmware_task_function(char *task __attribute__((unused)))
{
int ret = cwmp_apply_multiple_firmware();
char *ret_str = (char *)malloc(2 * sizeof(char));
snprintf(ret_str, 2, "%d", ret);
ret_str[1] = 0;
return ret_str;
}
int cwmp_apply_multiple_firmware_in_subprocess()
{
subprocess_start(apply_multiple_firmware_task_function);
char *ret = execute_task_in_subprocess("{}"); //empty json object
return atoi(ret);
}
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;
@ -185,7 +327,7 @@ int cwmp_launch_download(struct download *pdownload, char *download_file_name, e
goto end_download;
}
int http_code = download_file(ICWMP_DOWNLOAD_FILE, pdownload->url, pdownload->username, pdownload->password);
int http_code = download_file_in_subprocess(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)
@ -314,7 +456,7 @@ int apply_downloaded_file(struct download *pdownload, char *download_file_name,
error = FAULT_CPE_NO_FAULT;
} else if (strcmp(pdownload->file_type, STORED_FIRMWARE_IMAGE_FILE_TYPE) == 0) {
int err = cwmp_apply_multiple_firmware();
int err = cwmp_apply_multiple_firmware_in_subprocess();
if (err == CWMP_OK)
error = FAULT_CPE_NO_FAULT;
else
@ -330,10 +472,12 @@ int apply_downloaded_file(struct download *pdownload, char *download_file_name,
}
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(ptransfer_complete);
@ -356,78 +500,6 @@ struct transfer_complete *set_download_error_transfer_complete(struct download *
return ptransfer_complete;
}
void *thread_cwmp_rpc_cpe_download(void *v __attribute__((unused)))
{
struct download *pdownload;
struct timespec download_timeout = { 0, 0 };
time_t current_time, stime;
int error = FAULT_CPE_NO_FAULT;
struct transfer_complete *ptransfer_complete;
long int time_of_grace = 3600, timeout;
for (;;) {
if (cwmp_stop)
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(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)) {
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(ptransfer_complete);
bkp_session_delete_transfer_complete(ptransfer_complete);
} else {
error = apply_downloaded_file(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_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;
@ -889,3 +961,45 @@ int cwmp_rpc_acs_destroy_data_transfer_complete(struct rpc *rpc)
FREE(rpc->extra_data);
return 0;
}
void cwmp_start_download(struct uloop_timeout *timeout)
{
struct download *pdownload;
int error = FAULT_CPE_NO_FAULT;
struct transfer_complete *ptransfer_complete;
pdownload = container_of(timeout, struct download, handler_timer);
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) {
CWMP_LOG(ERROR, "Error while downloading the file: %s", pdownload->url);
bkp_session_insert_transfer_complete(ptransfer_complete);
bkp_session_save();
cwmp_root_cause_transfer_complete(ptransfer_complete);
bkp_session_delete_transfer_complete(ptransfer_complete);
} else {
error = apply_downloaded_file(pdownload, download_file_name, ptransfer_complete);
if (error != FAULT_CPE_NO_FAULT) {
CWMP_LOG(ERROR, "Error while applying the downloaded file: %s", download_file_name);
bkp_session_insert_transfer_complete(ptransfer_complete);
bkp_session_save();
cwmp_root_cause_transfer_complete(ptransfer_complete);
bkp_session_delete_transfer_complete(ptransfer_complete);
}
}
if (error == FAULT_CPE_NO_FAULT && pdownload->file_type[0] == '3') {
cwmp_root_cause_transfer_complete(ptransfer_complete);
bkp_session_delete_download(pdownload);
bkp_session_delete_transfer_complete(ptransfer_complete);
bkp_session_save();
}
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);
trigger_cwmp_session_timer();
}

View file

@ -218,6 +218,9 @@ int cwmp_root_cause_transfer_complete(struct transfer_complete *p)
if (event_container == NULL) {
return CWMP_MEM_ERR;
}
if ((rpc_acs = cwmp_add_session_rpc_acs(RPC_ACS_TRANSFER_COMPLETE)) == NULL) {
return CWMP_MEM_ERR;
}
switch (p->type) {
case TYPE_DOWNLOAD:
event_container = cwmp_add_event_container(EVENT_IDX_M_Download, p->command_key ? p->command_key : "");
@ -238,9 +241,7 @@ int cwmp_root_cause_transfer_complete(struct transfer_complete *p)
}
break;
}
if ((rpc_acs = cwmp_add_session_rpc_acs(RPC_ACS_TRANSFER_COMPLETE)) == NULL) {
return CWMP_MEM_ERR;
}
rpc_acs->extra_data = (void *)p;
return CWMP_OK;
}

View file

@ -24,6 +24,8 @@ configure_genieacs
echo "Checking cwmp status"
check_cwmp_status
mkdir -p /var/run/icwmpd
[ -f funl-test-result.log ] && rm -f funl-test-result.log
echo "## Running script verification of functionalities ##"

View file

@ -46,6 +46,12 @@ startretries=0
priority=8
command=/bin/bash -c "/usr/sbin/genieacs-ui --ui-jwt-secret secret"
[program:lighttpd]
autorestart=false
startretries=0
priority=9
command=service lighttpd restart
[program:icwmpd]
autorestart=false
startretries=0

View file

@ -7,6 +7,16 @@ source ./gitlab-ci/shared.sh
trap cleanup EXIT
trap cleanup SIGINT
echo "Install lighttpd"
apt-get update
apt-get install -y lighttpd
exec_cmd dd if=/dev/zero of=/builds/iopsys/icwmp/firmware_v1.0.bin bs=25MB count=1
echo "Valid" > /builds/iopsys/icwmp/firmware_v1.0.bin
exec_cmd cp /builds/iopsys/icwmp/firmware_v1.0.bin /var/www/html
exec_cmd dd if=/dev/zero of=/builds/iopsys/icwmp/invalid_firmware_v1.0.bin bs=25MB count=1
echo "Invalid" > /builds/iopsys/icwmp/invalid_firmware_v1.0.bin
exec_cmd cp /builds/iopsys/icwmp/invalid_firmware_v1.0.bin /var/www/html
echo "Install Inform json files"
exec_cmd mkdir -p /etc/icwmpd
exec_cmd cp /builds/iopsys/icwmp/test/files/etc/icwmpd/* /etc/icwmpd

View file

@ -344,6 +344,7 @@ typedef struct timewindow {
typedef struct download {
struct list_head list;
struct uloop_timeout handler_timer ;
time_t scheduled_time;
int file_size;
char *command_key;
@ -388,6 +389,7 @@ typedef struct operations {
typedef struct upload {
struct list_head list;
struct uloop_timeout handler_timer ;
time_t scheduled_time;
char *command_key;
char *file_type;

View file

@ -23,7 +23,6 @@ extern struct list_head list_schedule_download;
extern struct list_head list_apply_schedule_download;
extern pthread_mutex_t mutex_download;
extern pthread_cond_t threshold_download;
extern pthread_mutex_t mutex_schedule_download;
extern pthread_cond_t threshold_schedule_download;
extern pthread_mutex_t mutex_apply_schedule_download;
@ -38,8 +37,8 @@ int cwmp_scheduledDownload_remove_all();
int cwmp_scheduled_Download_remove_all();
int cwmp_apply_scheduled_Download_remove_all();
int cwmp_rpc_acs_destroy_data_transfer_complete(struct rpc *rpc);
void *thread_cwmp_rpc_cpe_download(void *v);
void *thread_cwmp_rpc_cpe_schedule_download(void *v);
void *thread_cwmp_rpc_cpe_apply_schedule_download(void *v);
int cwmp_launch_download(struct download *pdownload, char *download_file_name, enum load_type ltype, struct transfer_complete **ptransfer_complete);
void cwmp_start_download(struct uloop_timeout *timeout);
#endif

View file

@ -58,7 +58,9 @@ enum end_session_enum
END_SESSION_SERVERSELECTION_DIAGNOSTIC = 1 << 11,
END_SESSION_SET_NOTIFICATION_UPDATE = 1 << 12,
END_SESSION_RESTART_SERVICES = 1 << 13,
END_SESSION_INIT_NOTIFY = 1 << 14
END_SESSION_INIT_NOTIFY = 1 << 14,
END_SESSION_DOWNLOAD = 1 << 15,
END_SESSION_UPLOAD = 1 << 16
};
enum enum_session_status

View file

@ -19,6 +19,10 @@
#include "session.h"
#include "xml.h"
#define PROCESSING_DELAY (1) // In download/upload the message enqueued before sending the response, which cause the download/upload
// to start just before the time. This delay is to compensate the time lapsed during the message enqueue and response
#define MAX_NBRE_CUSTOM_INFORM 256
extern char *custom_forced_inform_parameters[MAX_NBRE_CUSTOM_INFORM];
extern char *boot_inform_parameters[MAX_NBRE_CUSTOM_INFORM];

7
inc/subprocess.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef SUB_PROC_H
#define SUB_PROC_H
typedef char* (*task_function)(char *task_arg);
int subprocess_start(task_function task_fun);
char *execute_task_in_subprocess(char *task);
#endif

View file

@ -13,10 +13,10 @@
extern struct list_head list_upload;
extern pthread_mutex_t mutex_upload;
extern pthread_cond_t threshold_upload;
int cwmp_launch_upload(struct upload *pupload, struct transfer_complete **ptransfer_complete);
void *thread_cwmp_rpc_cpe_upload(void *v);
int cwmp_scheduledUpload_remove_all();
int cwmp_free_upload_request(struct upload *upload);
void cwmp_start_upload(struct uloop_timeout *timeout);
#endif

View file

@ -570,7 +570,6 @@ void sotfware_version_value_change(struct transfer_complete *p)
void periodic_check_notifiy(struct uloop_timeout *timeout __attribute__((unused)))
{
int periodic_interval = cwmp_main->conf.periodic_notify_interval;
int is_notify = 0;
if (cwmp_stop)
return;

View file

@ -20,6 +20,8 @@
#include "diagnostic.h"
#include "soap.h"
#include "ubus.h"
#include "download.h"
#include "upload.h"
pthread_mutex_t start_session_mutext = PTHREAD_MUTEX_INITIALIZER;
static void cwmp_priodic_session_timer(struct uloop_timeout *timeout);
@ -71,23 +73,6 @@ int cwmp_session_rpc_destructor(struct rpc *rpc)
int cwmp_session_exit()
{
struct rpc *rpc;
while (cwmp_main->session->head_rpc_acs.next != &(cwmp_main->session->head_rpc_acs)) {
rpc = list_entry(cwmp_main->session->head_rpc_acs.next, struct rpc, list);
if (!rpc)
break;
if (rpc_acs_methods[rpc->type].extra_clean != NULL)
rpc_acs_methods[rpc->type].extra_clean(rpc);
cwmp_session_rpc_destructor(rpc);
}
while (cwmp_main->session->head_rpc_cpe.next != &(cwmp_main->session->head_rpc_cpe)) {
rpc = list_entry(cwmp_main->session->head_rpc_cpe.next, struct rpc, list);
if (!rpc)
break;
cwmp_session_rpc_destructor(rpc);
}
cwmp_uci_exit();
icwmp_cleanmem();
return CWMP_OK;
@ -97,17 +82,14 @@ static int cwmp_rpc_cpe_handle_message(struct rpc *rpc_cpe)
{
if (xml_prepare_msg_out())
return -1;
if (rpc_cpe_methods[rpc_cpe->type].handler(rpc_cpe))
return -1;
if (xml_set_cwmp_id_rpc_cpe())
return -1;
return 0;
}
static int cwmp_schedule_rpc()
{
struct list_head *ilist;
@ -231,6 +213,26 @@ void set_cwmp_session_status(int status, int retry_time)
}
}
void rpc_exit()
{
struct rpc *rpc;
while (cwmp_main->session->head_rpc_acs.next != &(cwmp_main->session->head_rpc_acs)) {
rpc = list_entry(cwmp_main->session->head_rpc_acs.next, struct rpc, list);
if (!rpc)
break;
if (rpc_acs_methods[rpc->type].extra_clean != NULL)
rpc_acs_methods[rpc->type].extra_clean(rpc);
cwmp_session_rpc_destructor(rpc);
}
while (cwmp_main->session->head_rpc_cpe.next != &(cwmp_main->session->head_rpc_cpe)) {
rpc = list_entry(cwmp_main->session->head_rpc_cpe.next, struct rpc, list);
if (!rpc)
break;
cwmp_session_rpc_destructor(rpc);
}
}
void start_cwmp_session()
{
int t, error;
@ -286,6 +288,8 @@ void start_cwmp_session()
event_remove_all_event_container(RPC_SEND);
event_remove_all_event_container(RPC_QUEUE);
run_session_end_func();
cwmp_session_exit();
rpc_exit();
return;
}
@ -300,6 +304,7 @@ void start_cwmp_session()
//event_remove_all_event_container(RPC_QUEUE);
cwmp_main->retry_count_session = 0;
set_cwmp_session_status(SESSION_SUCCESS, 0);
rpc_exit();
}
run_session_end_func();
cwmp_session_exit();
@ -506,6 +511,34 @@ int run_session_end_func(void)
cwmp_factory_reset();
exit(EXIT_SUCCESS);
}
if (end_session_flag & END_SESSION_DOWNLOAD) {
CWMP_LOG(INFO, "Trigger Uloop Downaload Calls");
struct list_head *ilist;
list_for_each (ilist, &(list_download)) {
struct download *download = list_entry(ilist, struct download, list);
int download_delay = 0;
if (download->scheduled_time > time(NULL)) {
download_delay = download->scheduled_time - time(NULL);
}
uloop_timeout_set(&download->handler_timer, 1000 * download_delay);
}
}
if (end_session_flag & END_SESSION_UPLOAD) {
CWMP_LOG(INFO, "Trigger Uloop Upload Calls");
struct list_head *ilist;
list_for_each (ilist, &(list_upload)) {
struct download *upload = list_entry(ilist, struct download, list);
int upload_delay = 0;
if (upload->scheduled_time > time(NULL)) {
upload_delay = upload->scheduled_time - time(NULL);
}
uloop_timeout_set(&upload->handler_timer, 1000 * upload_delay);
}
}
end_session_flag = 0;
return CWMP_OK;
}

18
soap.c
View file

@ -32,8 +32,6 @@
#include "upload.h"
#include "sched_inform.h"
#define PROCESSING_DELAY (1) // In download/upload the message enqueued before sending the response, which cause the download/upload
// to start just before the time. This delay is to compensate the time lapsed during the message enqueue and response
#define DM_CONN_REQ_URL "Device.ManagementServer.ConnectionRequestURL"
struct cwmp_namespaces ns;
@ -533,7 +531,6 @@ int cwmp_rpc_acs_prepare_transfer_complete(struct rpc *rpc)
{
mxml_node_t *tree, *n;
struct transfer_complete *p;
p = (struct transfer_complete *)rpc->extra_data;
tree = mxmlLoadString(NULL, CWMP_RESPONSE_MESSAGE, MXML_OPAQUE_CALLBACK);
n = mxmlFindElement(tree, tree, "soap_env:Envelope", NULL, NULL, MXML_DESCEND);
@ -2064,6 +2061,7 @@ int cwmp_handle_rpc_cpe_download(struct rpc *rpc)
count_download_queue++;
download->scheduled_time = scheduled_time;
}
download->handler_timer.cb = cwmp_start_download;
bkp_session_insert_download(download);
bkp_session_save();
if (download_delay != 0) {
@ -2071,9 +2069,9 @@ int cwmp_handle_rpc_cpe_download(struct rpc *rpc)
} else {
CWMP_LOG(INFO, "Download will start at the end of session");
}
cwmp_set_end_session(END_SESSION_DOWNLOAD);
pthread_mutex_unlock(&mutex_download);
pthread_cond_signal(&threshold_download);
}
return 0;
@ -2409,15 +2407,17 @@ int cwmp_handle_rpc_cpe_upload(struct rpc *rpc)
count_download_queue++;
upload->scheduled_time = scheduled_time;
}
bkp_session_insert_upload(upload);
upload->handler_timer.cb = cwmp_start_upload;
bkp_session_save(upload);
bkp_session_save();
if (upload_delay != 0) {
CWMP_LOG(INFO, "Upload will start in %us", upload_delay);
CWMP_LOG(INFO, "Download will start in %us", upload_delay);
} else {
CWMP_LOG(INFO, "Upload will start at the end of session");
CWMP_LOG(INFO, "Download will start at the end of session");
}
cwmp_set_end_session(END_SESSION_UPLOAD);
pthread_mutex_unlock(&mutex_upload);
pthread_cond_signal(&threshold_upload);
}
return 0;

136
subprocess.c Normal file
View file

@ -0,0 +1,136 @@
#include <libubox/blobmsg_json.h>
#include <stdbool.h>
#include "common.h"
#include "subprocess.h"
#include "log.h"
#define END_TASK "{\"task\":\"end\"}"
#define EXIT_TASK "{\"task\":\"exit\"}"
static int pipefd1[2], pipefd2[2];
bool check_task_name(char *task, char *name)
{
struct blob_buf bbuf;
if (strcmp(task, "{}") == 0)
return false;
memset(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
if (blobmsg_add_json_from_string(&bbuf, task) == false) {
blob_buf_free(&bbuf);
return false;
}
const struct blobmsg_policy p[1] = { { "task", BLOBMSG_TYPE_STRING } };
struct blob_attr *tb[1] = { NULL };
blobmsg_parse(p, 1, tb, blobmsg_data(bbuf.head), blobmsg_len(bbuf.head));
if (tb[0] == NULL)
return false;
char *task_name = blobmsg_get_string(tb[0]);
if (strcmp(task_name, name) == 0) {
blob_buf_free(&bbuf);
return true;
}
blob_buf_free(&bbuf);
return false;
}
bool check_task_is_end(char *task)
{
return check_task_name(task, "end");
}
bool check_task_is_exit(char *task)
{
return check_task_name(task, "exit");
}
int subprocess_start(task_function task_fun)
{
if(task_fun == NULL)
return CWMP_GEN_ERR;
pid_t p;
if (pipe(pipefd1) == -1) {
CWMP_LOG(ERROR, "pipefd1 failed\n");
return CWMP_GEN_ERR;
}
if (pipe(pipefd2) == -1) {
CWMP_LOG(ERROR, "pipefd2 failed\n");
return CWMP_GEN_ERR;
}
p = fork();
if (p == 0) {
while(1) {
char from_parent[512];
read(pipefd1[0], from_parent, 512); //The received string should has the form {"task":"TaskName", "arg1_name":"xxx", "arg2_name":"xxxx"}
if (strlen(from_parent) == 0)
continue;
//get the task name
//if the task name is end
if (check_task_is_end(from_parent)){
write(pipefd2[1], EXIT_TASK, strlen(EXIT_TASK)+1);
exit(EXIT_SUCCESS);
}
char *to_child = task_fun(from_parent);
struct blob_buf bbuf;
memset(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
blobmsg_add_string(&bbuf, "ret", to_child);
char *to_child_json = blobmsg_format_json(bbuf.head, true);
write(pipefd2[1], to_child_json, strlen(to_child_json)+1);
blob_buf_free(&bbuf);
}
}
return CWMP_OK;
}
char *execute_task_in_subprocess(char *task)
{
char *ret = NULL;
write(pipefd1[1], task, strlen(task) + 1);
while(1) {
char from_child[512];
read(pipefd2[0], from_child, 512);
if(strlen(from_child) == 0)
continue;
//The received string from the child should has the format {"task":"exit"} or {"ret":"exit"}
if (check_task_is_exit(from_child)){
close(pipefd2[1]);
close(pipefd2[0]);
break;
}
struct blob_buf bbuf;
memset(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
if (blobmsg_add_json_from_string(&bbuf, from_child) == false) {
blob_buf_free(&bbuf);
continue;
}
const struct blobmsg_policy p[1] = { { "ret", BLOBMSG_TYPE_STRING } };
struct blob_attr *tb[1] = { NULL };
blobmsg_parse(p, 1, tb, blobmsg_data(bbuf.head), blobmsg_len(bbuf.head));
if (tb[0] == NULL) {
blob_buf_free(&bbuf);
continue;
}
ret = blobmsg_get_string(tb[0]);
write(pipefd1[1], END_TASK, strlen(END_TASK) +1);
}
close(pipefd1[0]);
close(pipefd1[1]);
return ret;
}

View file

@ -10,7 +10,7 @@ UNIT_TESTS = icwmp_datamodel_interface_unit_testd icwmp_soap_msg_unit_testd icwm
VALGRIND = valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all
libobj:
$(CC) $(LIBCFLAGS) ../../download.c ../../upload.c ../../log.c ../../md5.c ../../digestauth.c ../../netlink.c ../../cwmp_cli.c ../../cwmp_du_state.c ../../sched_inform.c \
$(CC) $(LIBCFLAGS) ../../subprocess.c ../../download.c ../../upload.c ../../log.c ../../md5.c ../../digestauth.c ../../netlink.c ../../cwmp_cli.c ../../cwmp_du_state.c ../../sched_inform.c \
../../diagnostic.c ../../reboot.c ../../notifications.c ../../cwmp_zlib.c ../../datamodel_interface.c ../../http.c ../../backupSession.c \
../../cwmp_time.c ../../config.c ../../event.c ../../session.c ../../ubus.c ../../common.c ../../xml.c ../../soap.c ../../cwmp_uci.c ../../cwmp.c $(LDFLAGS)

View file

@ -2,4 +2,5 @@ verify_add_method.sh
verify_delete_method.sh
verify_get_method.sh
verify_set_method.sh
verify_download_method.sh
verify_cmd_line.sh

View file

@ -19,11 +19,15 @@ if [ "$status" != "1" ]; then
exit 1
fi
rm /etc/icwmpd/dm_enabled_notify
rm /var/run/icwmpd/dm_enabled_notify
remove_icwmp_log
echo "Restarting icwmpd in order to apply the new firmware" >> ./funl-test-debug.log
supervisorctl restart icwmpd >> ./funl-test-debug.log
sleep 5
echo "Restarting icwmpd in order to apply the new firmware" >> ./funl-test-debug.log
#/builds/iopsys/icwmp/bin/icwmpd -b &
supervisorctl stop icwmpd
sleep 3
supervisorctl start icwmpd >> ./funl-test-debug.log
sleep 10
check_session "TransferComplete"
received_command_key=$(print_tag_value "cwmp:TransferComplete" "CommandKey")
if [ "$sent_command_key" != "$received_command_key" ]; then

11
ubus.c
View file

@ -97,7 +97,16 @@ static int cwmp_handle_command(struct ubus_context *ctx, struct ubus_object *obj
if (snprintf(info, sizeof(info), "icwmpd daemon stopped") == -1)
return -1;
cwmp_end_handler(SIGTERM);
cwmp_stop = true;
if (cwmp_main->session->session_status.last_status == SESSION_RUNNING)
http_set_timeout();
uloop_timeout_cancel(&retry_session_timer);
uloop_timeout_cancel(&priodic_session_timer);
uloop_timeout_cancel(&session_timer);
uloop_end();
shutdown(cwmp_main->cr_socket_desc, SHUT_RDWR);
} else {
blobmsg_add_u32(&b, "status", -1);

166
upload.c
View file

@ -10,6 +10,7 @@
#include <pthread.h>
#include <curl/curl.h>
#include <libubox/blobmsg_json.h>
#include "common.h"
#include "upload.h"
@ -20,12 +21,13 @@
#include "backupSession.h"
#include "cwmp_uci.h"
#include "event.h"
#include "subprocess.h"
#include "session.h"
#define CURL_TIMEOUT 20
LIST_HEAD(list_upload);
pthread_cond_t threshold_upload;
pthread_mutex_t mutex_upload = PTHREAD_MUTEX_INITIALIZER;
int lookup_vcf_name(char *instance, char **value)
@ -62,6 +64,9 @@ int lookup_vlf_name(char *instance, char **value)
return 0;
}
/*
* Upload file
*/
int upload_file(const char *file_path, const char *url, const char *username, const char *password)
{
int res_code = 0;
@ -92,6 +97,58 @@ int upload_file(const char *file_path, const char *url, const char *username, co
return res_code;
}
char *upload_file_task_function(char *task)
{
struct blob_buf bbuf;
memset(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
if (blobmsg_add_json_from_string(&bbuf, task) == false) {
blob_buf_free(&bbuf);
return NULL;
}
const struct blobmsg_policy p[5] = { { "task", BLOBMSG_TYPE_STRING }, { "file_path", BLOBMSG_TYPE_STRING }, { "url", BLOBMSG_TYPE_STRING }, { "username", BLOBMSG_TYPE_STRING }, { "password", BLOBMSG_TYPE_STRING } };
struct blob_attr *tb[5] = { NULL, NULL, NULL, NULL, NULL};
blobmsg_parse(p, 5, tb, blobmsg_data(bbuf.head), blobmsg_len(bbuf.head));
char *task_name = blobmsg_get_string(tb[0]);
if (!task_name || strcmp(task_name, "upload") != 0)
return NULL;
char *file_path = blobmsg_get_string(tb[1]);
char *url = blobmsg_get_string(tb[2]);
char *username = blobmsg_get_string(tb[3]);
char *password = blobmsg_get_string(tb[4]);
int http_code = upload_file(file_path, url, username, password);
char *http_ret = (char *)malloc(4 * sizeof(char));
snprintf(http_ret, 4, "%d", http_code);
http_ret[3] = 0;
return http_ret;
}
int upload_file_in_subprocess(const char *file_path, const char *url, const char *username, const char *password)
{
subprocess_start(upload_file_task_function);
struct blob_buf bbuf;
memset(&bbuf, 0, sizeof(struct blob_buf));
blob_buf_init(&bbuf, 0);
blobmsg_add_string(&bbuf, "task", "upload");
blobmsg_add_string(&bbuf, "file_path", file_path);
blobmsg_add_string(&bbuf, "url", url);
blobmsg_add_string(&bbuf, "username", username);
blobmsg_add_string(&bbuf, "password", password);
char *upload_task = blobmsg_format_json(bbuf.head, true);
blob_buf_free(&bbuf);
if (upload_task != NULL) {
char *ret = execute_task_in_subprocess(upload_task);
return atoi(ret);
}
return 500;
}
int cwmp_launch_upload(struct upload *pupload, struct transfer_complete **ptransfer_complete)
{
int error = FAULT_CPE_NO_FAULT;
@ -160,86 +217,6 @@ end_upload:
return error;
}
void *thread_cwmp_rpc_cpe_upload(void *v __attribute__((unused)))
{
struct upload *pupload;
struct timespec upload_timeout = { 0, 0 };
time_t current_time, stime;
int error = FAULT_CPE_NO_FAULT;
struct transfer_complete *ptransfer_complete;
long int time_of_grace = 3600, timeout;
for (;;) {
if (cwmp_stop)
break;
if (list_upload.next != &(list_upload)) {
pupload = list_entry(list_upload.next, struct upload, list);
stime = pupload->scheduled_time;
current_time = time(NULL);
if (pupload->scheduled_time != 0)
timeout = current_time - pupload->scheduled_time;
else
timeout = 0;
if ((timeout >= 0) && (timeout > time_of_grace)) {
pthread_mutex_lock(&mutex_upload);
bkp_session_delete_upload(pupload);
ptransfer_complete = calloc(1, sizeof(struct transfer_complete));
if (ptransfer_complete != NULL) {
error = FAULT_CPE_DOWNLOAD_FAILURE;
ptransfer_complete->command_key = strdup(pupload->command_key);
ptransfer_complete->start_time = strdup(mix_get_time());
ptransfer_complete->complete_time = strdup(ptransfer_complete->start_time);
ptransfer_complete->fault_code = error;
ptransfer_complete->type = TYPE_UPLOAD;
bkp_session_insert_transfer_complete(ptransfer_complete);
cwmp_root_cause_transfer_complete(ptransfer_complete);
}
list_del(&(pupload->list));
if (pupload->scheduled_time != 0)
count_download_queue--;
cwmp_free_upload_request(pupload);
pthread_mutex_unlock(&mutex_download);
continue;
}
if ((timeout >= 0) && (timeout <= time_of_grace)) {
CWMP_LOG(INFO, "Launch upload file %s", pupload->url);
error = cwmp_launch_upload(pupload, &ptransfer_complete);
if (error != FAULT_CPE_NO_FAULT) {
bkp_session_insert_transfer_complete(ptransfer_complete);
bkp_session_save();
cwmp_root_cause_transfer_complete(ptransfer_complete);
bkp_session_delete_transfer_complete(ptransfer_complete);
} else {
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(ptransfer_complete);
}
pthread_mutex_lock(&mutex_upload);
list_del(&(pupload->list));
if (pupload->scheduled_time != 0)
count_download_queue--;
cwmp_free_upload_request(pupload);
pthread_mutex_unlock(&mutex_upload);
continue;
}
pthread_mutex_lock(&mutex_upload);
upload_timeout.tv_sec = stime;
pthread_cond_timedwait(&threshold_upload, &mutex_upload, &upload_timeout);
pthread_mutex_unlock(&mutex_upload);
} else {
pthread_mutex_lock(&mutex_upload);
pthread_cond_wait(&threshold_upload, &mutex_upload);
pthread_mutex_unlock(&mutex_upload);
}
}
return NULL;
}
int cwmp_free_upload_request(struct upload *upload)
{
if (upload != NULL) {
@ -282,3 +259,30 @@ int cwmp_scheduledUpload_remove_all()
return CWMP_OK;
}
void cwmp_start_upload(struct uloop_timeout *timeout)
{
struct upload *pupload;
int error = FAULT_CPE_NO_FAULT;
struct transfer_complete *ptransfer_complete;
pupload = container_of(timeout, struct upload, handler_timer);
CWMP_LOG(INFO, "Launch download file %s", pupload->url);
error = cwmp_launch_upload(pupload, &ptransfer_complete);
sleep(3);
if (error != FAULT_CPE_NO_FAULT) {
CWMP_LOG(ERROR, "Error while uploading the file: %s", pupload->url);
}
bkp_session_insert_transfer_complete(ptransfer_complete);
bkp_session_save();
cwmp_root_cause_transfer_complete(ptransfer_complete);
pthread_mutex_lock(&mutex_upload);
list_del(&(pupload->list));
if (pupload->scheduled_time != 0)
count_download_queue--;
cwmp_free_upload_request(pupload);
pthread_mutex_unlock(&mutex_upload);
trigger_cwmp_session_timer();
}

4
xml.c
View file

@ -182,7 +182,7 @@ int xml_send_message(struct rpc *rpc)
if (b) {
b = mxmlWalkNext(b, cwmp_main->session->tree_in, MXML_DESCEND_FIRST);
if (b && b->type == MXML_OPAQUE && b->value.opaque)
cwmp_main->session->hold_request = atoi(b->value.opaque);
cwmp_main->session->hold_request = (atoi(b->value.opaque)) ? true : false;
} else {
if (snprintf(c, sizeof(c), "%s:%s", ns.cwmp, "HoldRequests") == -1)
goto error;
@ -191,7 +191,7 @@ int xml_send_message(struct rpc *rpc)
if (b) {
b = mxmlWalkNext(b, cwmp_main->session->tree_in, MXML_DESCEND_FIRST);
if (b && b->type == MXML_OPAQUE && b->value.opaque)
cwmp_main->session->hold_request = atoi(b->value.opaque);
cwmp_main->session->hold_request = (atoi(b->value.opaque)) ? true : false;
}
}