Ticket refs #7896: icwmp: Implement Heartbeat event

This commit is contained in:
Omar Kallel 2022-04-27 14:35:09 +01:00
parent 712cb443c1
commit 491957b998
12 changed files with 264 additions and 15 deletions

View file

@ -28,6 +28,7 @@ icwmpd_SOURCES = \
./rpc_soap.c \
./diagnostic.c \
./reboot.c \
./heartbeat.c \
./cwmp.c \
./ssl_utils.c

View file

@ -17,6 +17,7 @@
#include "reboot.h"
#include "ssl_utils.h"
#include "datamodel_interface.h"
#include "heartbeat.h"
pthread_mutex_t mutex_config_load = PTHREAD_MUTEX_INITIALIZER;
@ -571,6 +572,50 @@ int get_global_config(struct config *conf)
CWMP_LOG(DEBUG, "CWMP CONFIG - cpe json custom notify file: %s", conf->custom_notify_json);
}
}
if ((error = uci_get_value(UCI_ACS_HEARTBEAT_ENABLE, &value)) == CWMP_OK) {
if (value != NULL) {
if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
conf->heart_beat_enable = true;
} else {
conf->heart_beat_enable = false;
}
FREE(value);
} else {
conf->heart_beat_enable = false;
}
CWMP_LOG(DEBUG, "CWMP CONFIG - heart beat enable: %d ", conf->heart_beat_enable);
} else {
return error;
}
if ((error = uci_get_value(UCI_ACS_HEARTBEAT_INTERVAL, &value)) == CWMP_OK) {
int a = 30;
if (value != NULL) {
a = atoi(value);
FREE(value);
}
conf->heartbeat_interval = a;
CWMP_LOG(DEBUG, "CWMP CONFIG - heart beat interval: %d ", conf->heartbeat_interval);
} else {
return error;
}
if ((error = uci_get_value(UCI_ACS_HEARTBEAT_TIME, &value)) == CWMP_OK) {
if (value != NULL) {
conf->heart_time = convert_datetime_to_timestamp(value);
FREE(value);
} else {
conf->heart_time = 0;
}
CWMP_LOG(DEBUG, "CWMP CONFIG - heart beat time: %d ", conf->heart_time);
} else {
return error;
}
return CWMP_OK;
}

31
cwmp.c
View file

@ -37,6 +37,7 @@
#include "sched_inform.h"
#include "datamodel_interface.h"
#include "cwmp_du_state.h"
#include "heartbeat.h"
#include "netlink.h"
static pthread_t periodic_event_thread;
@ -49,17 +50,22 @@ static pthread_t upload_thread;
static pthread_t ubus_thread;
static pthread_t http_cr_server_thread;
static pthread_t periodic_check_notify;
static pthread_t heart_beat_session_thread;
bool g_firewall_restart = false;
static struct ubus_context *ctx = NULL;
static int cwmp_get_retry_interval(struct cwmp *cwmp)
int cwmp_get_retry_interval(struct cwmp *cwmp, bool heart_beat)
{
unsigned int retry_count = 0;
double min = 0;
double max = 0;
int m = cwmp->conf.retry_min_wait_interval;
int k = cwmp->conf.retry_interval_multiplier;
int exp = cwmp->retry_count_session;
int exp;
if (heart_beat)
exp = heart_beat_retry_count_session;
else
exp = cwmp->retry_count_session;
if (exp == 0)
return MAX_INT32;
if (exp > 10)
@ -145,7 +151,7 @@ void check_firewall_restart_state()
}
}
static int cwmp_schedule_rpc(struct cwmp *cwmp, struct session *session)
int cwmp_schedule_rpc(struct cwmp *cwmp, struct session *session)
{
struct list_head *ilist;
struct rpc *rpc_acs, *rpc_cpe;
@ -263,6 +269,7 @@ int run_session_end_func(void)
CWMP_LOG(INFO, "Config reload: end session request");
cwmp_uci_reinit();
cwmp_apply_acs_changes();
check_trigger_heartbeat_session();
}
if (end_session_flag & END_SESSION_INIT_NOTIFY) {
@ -350,7 +357,7 @@ static void cwmp_schedule_session(struct cwmp *cwmp)
pthread_mutex_lock(&(cwmp->mutex_session_send));
ilist = (&(cwmp->head_session_queue))->next;
while ((ilist == &(cwmp->head_session_queue)) || retry) {
t = cwmp_get_retry_interval(cwmp);
t = cwmp_get_retry_interval(cwmp, 0);
time_to_wait.tv_sec = time(NULL) + t;
CWMP_LOG(INFO, "Waiting the next session");
@ -369,6 +376,7 @@ static void cwmp_schedule_session(struct cwmp *cwmp)
ilist = (&(cwmp->head_session_queue))->next;
retry = false;
}
pthread_mutex_lock(&mutex_heartbeat_session);
cwmp_uci_init();
if (cwmp->session_status.last_status == SESSION_FAILURE)
reload_networking_config();
@ -419,12 +427,13 @@ static void cwmp_schedule_session(struct cwmp *cwmp)
reload_networking_config();
run_session_end_func();
error = cwmp_move_session_to_session_queue(cwmp, session);
CWMP_LOG(INFO, "Retry session, retry count = %d, retry in %ds", cwmp->retry_count_session, cwmp_get_retry_interval(cwmp));
CWMP_LOG(INFO, "Retry session, retry count = %d, retry in %ds", cwmp->retry_count_session, cwmp_get_retry_interval(cwmp, 0));
retry = true;
cwmp->session_status.last_end_time = time(NULL);
cwmp->session_status.last_status = SESSION_FAILURE;
cwmp->session_status.next_retry = time(NULL) + cwmp_get_retry_interval(cwmp);
cwmp->session_status.next_retry = time(NULL) + cwmp_get_retry_interval(cwmp, 0);
cwmp->session_status.failure_session++;
pthread_mutex_unlock(&mutex_heartbeat_session);
pthread_mutex_unlock(&(cwmp->mutex_session_send));
continue;
}
@ -437,6 +446,8 @@ static void cwmp_schedule_session(struct cwmp *cwmp)
cwmp->session_status.last_status = SESSION_SUCCESS;
cwmp->session_status.next_retry = 0;
cwmp->session_status.success_session++;
pthread_cond_signal(&threasheld_retry_session);
pthread_mutex_unlock(&mutex_heartbeat_session);
pthread_mutex_unlock(&(cwmp->mutex_session_send));
}
}
@ -747,6 +758,8 @@ static int cwmp_init(int argc, char **argv, struct cwmp *cwmp)
pthread_mutex_init(&cwmp->mutex_periodic, NULL);
pthread_mutex_init(&cwmp->mutex_session_queue, NULL);
pthread_mutex_init(&cwmp->mutex_session_send, NULL);
pthread_mutex_init(&mutex_heartbeat_session, NULL);
pthread_mutex_init(&mutex_heartbeat, NULL);
memcpy(&(cwmp->env), &env, sizeof(struct env));
INIT_LIST_HEAD(&(cwmp->head_session_queue));
@ -889,6 +902,11 @@ int main(int argc, char **argv)
if (error < 0) {
CWMP_LOG(ERROR, "Error when creating the periodic check notify thread!");
}
error = pthread_create(&heart_beat_session_thread, NULL, &thread_heartbeat_session, (void *)cwmp);
if (error < 0) {
CWMP_LOG(ERROR, "Error when creating heartbeat session thread!");
}
error = pthread_create(&scheduleInform_thread, NULL, &thread_cwmp_rpc_cpe_scheduleInform, (void *)cwmp);
if (error < 0) {
CWMP_LOG(ERROR, "Error when creating the scheduled inform thread!");
@ -932,6 +950,7 @@ int main(int argc, char **argv)
pthread_join(change_du_state_thread, NULL);
pthread_join(http_cr_server_thread, NULL);
pthread_join(ubus_thread, NULL);
pthread_join(heart_beat_session_thread, NULL);
/* Free all memory allocation */
cwmp_free(cwmp);

View file

@ -35,7 +35,8 @@ const struct EVENT_CONST_STRUCT EVENT_CONST[] = {[EVENT_IDX_0BOOTSTRAP] = { "0 B
[EVENT_IDX_M_Download] = { "M Download", EVENT_TYPE_MULTIPLE, EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT },
[EVENT_IDX_M_Schedule_Download] = { "M ScheduleDownload", EVENT_TYPE_MULTIPLE, EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT },
[EVENT_IDX_M_Upload] = { "M Upload", EVENT_TYPE_MULTIPLE, EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT },
[EVENT_IDX_M_ChangeDUState] = { "M ChangeDUState", EVENT_TYPE_MULTIPLE, EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT } };
[EVENT_IDX_M_ChangeDUState] = { "M ChangeDUState", EVENT_TYPE_MULTIPLE, EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT },
[EVENT_IDX_14HEARTBEAT] = { "14 HEARTBEAT", EVENT_TYPE_SINGLE, EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT } };
void cwmp_save_event_container(struct event_container *event_container) //to be moved to backupsession
{

154
heartbeat.c Normal file
View file

@ -0,0 +1,154 @@
#include <pthread.h>
#include <unistd.h>
#include "heartbeat.h"
#include "common.h"
#include "config.h"
#include "session.h"
#include "cwmp_uci.h"
#include "backupSession.h"
#include "log.h"
#include "event.h"
#include "http.h"
pthread_cond_t threshold_heartbeat_session;
pthread_cond_t threasheld_retry_session;
pthread_mutex_t mutex_heartbeat;
pthread_mutex_t mutex_heartbeat_session;
bool old_heartbeat_enable = false;
int heart_beat_retry_count_session = 0;
static struct session_status heart_beat_session_status = {0};
void check_trigger_heartbeat_session()
{
if (cwmp_main.conf.heart_beat_enable && !old_heartbeat_enable)
pthread_cond_signal(&threshold_heartbeat_session);
}
int add_heart_beat_event(struct session *heartbeat_session)
{
struct event_container *event_container;
event_container = calloc(1, sizeof(struct event_container));
if (event_container == NULL) {
return -1;
}
INIT_LIST_HEAD(&(event_container->head_dm_parameter));
list_add(&(event_container->list), heartbeat_session->head_event_container.prev);
event_container->code = EVENT_IDX_14HEARTBEAT;
event_container->command_key = strdup("");
event_container->id = 1;
/*
* event_container will be freed in the destruction of the session heartbeat_session
*/
// cppcheck-suppress memleak
return 0;
}
void *thread_heartbeat_session(void *v __attribute__((unused)))
{
static struct timespec heartbeat_interval = { 0, 0 };
sleep(2);
for (;;) {
if (cwmp_main.conf.heart_beat_enable) {
heartbeat_interval.tv_sec = time(NULL) + cwmp_main.conf.heartbeat_interval;
pthread_mutex_lock(&mutex_heartbeat);
pthread_cond_timedwait(&threshold_heartbeat_session, &mutex_heartbeat, &heartbeat_interval);
if (thread_end)
break;
if (cwmp_main.session_status.last_status == SESSION_FAILURE) {
CWMP_LOG(WARNING, "Not able to start HEARTBEAT Session for this period: CWMP Session is retrying");
pthread_cond_wait(&threasheld_retry_session, &mutex_heartbeat);
//continue;
}
pthread_mutex_lock(&mutex_heartbeat_session);
struct session *heartbeat_session = NULL;
heartbeat_session = calloc(1, sizeof(struct session));
if (heartbeat_session == NULL) {
pthread_mutex_unlock(&mutex_heartbeat_session);
pthread_mutex_unlock(&mutex_heartbeat);
continue;
}
INIT_LIST_HEAD(&(heartbeat_session->head_event_container));
INIT_LIST_HEAD(&(heartbeat_session->head_rpc_acs));
INIT_LIST_HEAD(&(heartbeat_session->head_rpc_cpe));
struct rpc *rpc_acs;
rpc_acs = cwmp_add_session_rpc_acs_head(heartbeat_session, RPC_ACS_INFORM);
if (rpc_acs == NULL) {
cwmp_session_destructor(heartbeat_session);
pthread_mutex_unlock(&mutex_heartbeat_session);
pthread_mutex_unlock(&mutex_heartbeat);
continue;
}
if (add_heart_beat_event(heartbeat_session) != 0) {
cwmp_session_destructor(heartbeat_session);
pthread_mutex_unlock(&mutex_heartbeat_session);
pthread_mutex_unlock(&mutex_heartbeat);
continue;
}
cwmp_uci_init();
if (heart_beat_session_status.last_status == SESSION_FAILURE)
reload_networking_config();
heart_beat_session_status.last_end_time = 0;
heart_beat_session_status.last_start_time = time(NULL);
heart_beat_session_status.last_status = SESSION_RUNNING;
heart_beat_session_status.next_retry = 0;
if (file_exists(fc_cookies))
remove(fc_cookies);
CWMP_LOG(INFO, "Start HEARTBEAT session");
int error = cwmp_schedule_rpc(&cwmp_main, heartbeat_session);
CWMP_LOG(INFO, "End HEARTBEAT session");
if (thread_end) {
event_remove_all_event_container(heartbeat_session, RPC_SEND);
run_session_end_func();
cwmp_session_destructor(heartbeat_session);
cwmp_uci_exit();
pthread_mutex_unlock(&(cwmp_main.mutex_session_send));
pthread_mutex_unlock(&mutex_heartbeat);
break;
}
if (error || heartbeat_session->error == CWMP_RETRY_SESSION) {
heart_beat_retry_count_session++;
reload_networking_config();
run_session_end_func();
CWMP_LOG(INFO, "Retry HEARTBEAT session, retry count = %d, retry in %ds", cwmp_main.retry_count_session, cwmp_get_retry_interval(&cwmp_main, 1));
heart_beat_session_status.last_end_time = time(NULL);
heart_beat_session_status.last_status = SESSION_FAILURE;
heart_beat_session_status.next_retry = time(NULL) + cwmp_get_retry_interval(&cwmp_main, 1);
heartbeat_interval.tv_sec = time(NULL) + cwmp_get_retry_interval(&cwmp_main, 1);
heart_beat_session_status.failure_session++;
cwmp_uci_exit();
pthread_mutex_unlock(&mutex_heartbeat_session);
pthread_mutex_unlock(&mutex_heartbeat);
continue;
}
event_remove_all_event_container(heartbeat_session, RPC_SEND);
run_session_end_func();
cwmp_session_destructor(heartbeat_session);
heart_beat_retry_count_session = 0;
heart_beat_session_status.last_end_time = time(NULL);
heart_beat_session_status.last_status = SESSION_SUCCESS;
heart_beat_session_status.next_retry = 0;
heart_beat_session_status.success_session++;
heartbeat_interval.tv_sec = time(NULL) + cwmp_main.conf.heartbeat_interval;
cwmp_uci_exit();
pthread_mutex_unlock(&mutex_heartbeat_session);
pthread_mutex_unlock(&mutex_heartbeat);
if (thread_end)
break;
} else {
pthread_mutex_lock(&mutex_heartbeat);
pthread_cond_wait(&threshold_heartbeat_session, &mutex_heartbeat);
pthread_mutex_unlock(&mutex_heartbeat);
}
}
return NULL;
}

View file

@ -91,13 +91,16 @@ typedef struct config {
int periodic_notify_interval;
int compression;
int delay_reboot;
int heartbeat_interval;
time_t schedule_reboot;
time_t time;
time_t heart_time;
unsigned int periodic_entropy;
bool periodic_enable;
bool periodic_notify_enable;
bool insecure_enable;
bool ipv6_enable;
bool heart_beat_enable;
int retry_min_wait_interval;
int retry_interval_multiplier;
bool lw_notification_enable;
@ -529,5 +532,8 @@ int get_connection_interface();
char *get_time(time_t t_time);
bool is_obj_excluded(const char *object_name);
time_t convert_datetime_to_timestamp(char *value);
int cwmp_get_retry_interval(struct cwmp *cwmp, bool heart_beat);
int cwmp_schedule_rpc(struct cwmp *cwmp, struct session *session);
int run_session_end_func(void);
#endif

View file

@ -58,6 +58,9 @@
#define LW_NOTIFICATION_HOSTNAME "cwmp.lwn.hostname"
#define LW_NOTIFICATION_PORT "cwmp.lwn.port"
#define UCI_DHCP_ACS_URL "cwmp.acs.dhcp_url"
#define UCI_ACS_HEARTBEAT_ENABLE "cwmp.acs.heartbeat_enable"
#define UCI_ACS_HEARTBEAT_INTERVAL "cwmp.acs.heartbeat_interval"
#define UCI_ACS_HEARTBEAT_TIME "cwmp.acs.heartbeat_time"
#define UCI_CPE_FIREWALL_RESTART_STATE "cwmp.cpe.firewall_restart"

View file

@ -63,6 +63,7 @@ enum event_idx_enum
EVENT_IDX_M_Schedule_Download,
EVENT_IDX_M_Upload,
EVENT_IDX_M_ChangeDUState,
EVENT_IDX_14HEARTBEAT,
__EVENT_IDX_MAX
};

14
inc/heartbeat.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef HEARTBEAT_H
#define HEARTBEAT_H
#include <stdbool.h>
extern pthread_mutex_t mutex_heartbeat;
extern pthread_mutex_t mutex_heartbeat_session;
extern pthread_cond_t threshold_heartbeat_session;
extern pthread_cond_t threasheld_retry_session;
extern int heart_beat_retry_count_session;
extern bool old_heartbeat_enable;
void *thread_heartbeat_session(void *v);
void check_trigger_heartbeat_session();
#endif

View file

@ -14,7 +14,7 @@
extern char *fc_cookies;
#define HTTP_TIMEOUT 30
#define HTTP_TIMEOUT 60
struct http_client {
struct curl_slist *header_list;

View file

@ -16,6 +16,7 @@
#include "event.h"
#include "rpc_soap.h"
#include "backupSession.h"
#include "heartbeat.h"
unsigned int end_session_flag = 0;
@ -54,6 +55,8 @@ int cwmp_apply_acs_changes(void)
{
int error;
old_heartbeat_enable = cwmp_main.conf.heart_beat_enable;
if ((error = cwmp_config_reload(&cwmp_main)))
return error;

View file

@ -281,13 +281,15 @@ static void icwmp_inform_event(struct ubus_context *ctx, struct ubus_request_dat
pthread_mutex_lock(&(cwmp_main.mutex_session_queue));
cwmp_add_event_container(&cwmp_main, event_code, "");
pthread_mutex_unlock(&(cwmp_main.mutex_session_queue));
pthread_cond_signal(&(cwmp_main.threshold_session_send));
if (cwmp_main.session_status.last_status == SESSION_RUNNING) {
blobmsg_add_u32(&bb, "status", -1);
blobmsg_add_string(&bb, "info", "Session already running, event will be sent at the end of the session");
} else {
blobmsg_add_u32(&bb, "status", 1);
blobmsg_add_string(&bb, "info", "Session started");
if (event_code != EVENT_IDX_14HEARTBEAT) {
pthread_cond_signal(&(cwmp_main.threshold_session_send));
if (cwmp_main.session_status.last_status == SESSION_RUNNING) {
blobmsg_add_u32(&bb, "status", -1);
blobmsg_add_string(&bb, "info", "Session already running, event will be sent at the end of the session");
} else {
blobmsg_add_u32(&bb, "status", 1);
blobmsg_add_string(&bb, "info", "Session started");
}
}
ubus_send_reply(ctx, req, bb.head);