From 21456b49f87da0f4937fa568a8a8767048d8908d Mon Sep 17 00:00:00 2001 From: root Date: Thu, 6 Feb 2025 19:27:29 +0800 Subject: [PATCH] add support for bidirectional communication --- src/libso/xalarm/register_xalarm.c | 163 +++++++++++++++++++++++++++-- src/libso/xalarm/register_xalarm.h | 19 ++++ 2 files changed, 176 insertions(+), 6 deletions(-) diff --git a/src/libso/xalarm/register_xalarm.c b/src/libso/xalarm/register_xalarm.c index aa0645d..44c4bc4 100644 --- a/src/libso/xalarm/register_xalarm.c +++ b/src/libso/xalarm/register_xalarm.c @@ -352,11 +352,6 @@ int xalarm_Report(unsigned short usAlarmId, unsigned char ucAlarmLevel, return -1; } - if (pucParas == NULL || (int)strlen(pucParas) > MAX_PARAS_LEN) { - fprintf(stderr, "%s: alarm info invalid\n", __func__); - return -1; - } - if (memset(&info, 0, sizeof(struct alarm_info)) == NULL) { fprintf(stderr, "%s: memset info failed, ret: %d\n", __func__, ret); return -1; @@ -610,7 +605,7 @@ static bool is_valid_task_name(const char *task_name) int report_result(const char *task_name, enum RESULT_LEVEL result_level, const char *report_data) { if (result_level < 0 || result_level >= RESULT_LEVEL_NUM) { - fprintf(stderr, "result_level (%u) is invaild, it must be in [0-5]\n", result_level); + fprintf(stderr, "result_level (%u) is invalid, it must be in [0-5]\n", result_level); return RETURE_CODE_FAIL; } @@ -660,4 +655,160 @@ int report_result(const char *task_name, enum RESULT_LEVEL result_level, const c return RETURE_CODE_SUCCESS; } +int xalarm_register_event(struct alarm_register **register_info, struct alarm_subscription_info id_filter) +{ + int i; + *register_info = (struct alarm_register *)malloc(sizeof(struct alarm_register)); + // failed to malloc memory for register_info struct + if (*register_info == NULL) { + return -ENOMEM; + } + + // check whether id_filter is valid + if (!alarm_subscription_verify(id_filter)) { + return -EINVAL; + } + + // transform id_filter(eg:[1001, 1002]) into bitmap(eg:[true, true, false, ..., false]) + memset((*register_info)->alarm_enable_bitmap, 0, MAX_NUM_OF_ALARM_ID * sizeof(char)); + for (i = 0; i < id_filter.len; i++) { + (*register_info)->alarm_enable_bitmap[id_filter.id_list[i] - MIN_ALARM_ID] = ALARM_ENABLED; + } + + // establish connection between xalarmd and this program + (*register_info)->register_fd = create_unix_socket(PATH_REG_ALARM); + if ((*register_info)->register_fd == -1) { + return -ENOTCONN; + } + + return 0; +} + +void xalarm_unregister_event(struct alarm_register *register_info) +{ + // close client fd socket connection resource + if (register_info->register_fd != -1) { + (void)close(register_info->register_fd); + register_info->register_fd = -1; + } + + free(register_info); +} + +int xalarm_get_event(struct alarm_msg* msg, struct alarm_register *register_info) +{ + int recvlen = 0; + struct alarm_info info; + + if (msg == NULL || register_info == NULL) { + return -EINVAL; + } + + while (true) { + recvlen = recv(register_info->register_fd, &info, sizeof(struct alarm_info), 0); + // if recvlen == sizeof(alarm_info), that means we recieved data correctlly + // why use alarm_info rather than alarm_msg? alarm_info is used for old + // api, it's a communication protocol between xalarmd service and libxalarm. + // to be compatible with old api and reduce modification to xalarmd, use + // alarm_info for communication and return alarm_msg(alarm_msg is subset of + // alarm_info). + if (recvlen == (int)sizeof(struct alarm_info)) { + // filter alarm id + if (info.usAlarmId < MIN_ALARM_ID || info.usAlarmId > MAX_ALARM_ID || + register_info->alarm_enable_bitmap[info.usAlarmId - MIN_ALARM_ID] != ALARM_ENABLED) { + continue; + } + msg->usAlarmId = info.usAlarmId; + msg->AlarmTime = info.AlarmTime; + strncpy((char *)msg->pucParas, (char *)info.pucParas, MAX_PARAS_LEN - 1); + return 0; + } else if (recvlen < 0) { + // recvlen < 0 means that we meet with error when recv. + // when recv EINTR or EAGAIN or EWOULDBLOCK signal, we should try again. + // EINTR means recv func interrupted by signal + // EAGIAN and EWOULDBLOCK means recv has been blocked(in nonblock mode) + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { + usleep(RECV_DELAY_MSEC * TIME_UNIT_MILLISECONDS); + continue; + } else { + // otherwise means we meet up with some unrecoverable error + // ECONNRESET means server closed the connection for some error + // EBADF means this filr descriptor is invalid + // ENOMEM means out of memory + // EFAULT means invalid buffer address + close(register_info->register_fd); + return -errno; + } + } else if (recvlen == 0) { + // recvlen == 0 means the connection has been properly closed, + // and the remote end has no more data to send. + close(register_info->register_fd); + return -ENOTCONN; + } else { + // recv data but not we want, continue to read data + continue; + } + } +} + +int xalarm_report_event(unsigned short usAlarmId, char *pucParas) +{ + int ret, fd; + struct alarm_info info; + struct sockaddr_un alarm_addr; + + if (usAlarmId < MIN_ALARM_ID || usAlarmId > MAX_ALARM_ID) { + return -EINVAL; + } + + if (pucParas == NULL || (int)strlen(pucParas) > MAX_PARAS_LEN) { + return -EINVAL; + } + + if (memset(&info, 0, sizeof(struct alarm_info)) == NULL) { + return -EINVAL; + } + info.usAlarmId = usAlarmId; + info.ucAlarmLevel = MINOR_ALM; + info.ucAlarmType = ALARM_TYPE_OCCUR; + gettimeofday(&info.AlarmTime, NULL); + strncpy((char *)info.pucParas, (char *)pucParas, MAX_PARAS_LEN - 1); + + + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) { + return -ENOTCONN; + } + + ret = init_report_addr(&alarm_addr, PATH_REPORT_ALARM); + if (ret == -1) { + close(fd); + return -ENOTCONN; + } + + while (true) { + ret = sendto(fd, &info, sizeof(struct alarm_info), 0, (struct sockaddr *)&alarm_addr, + sizeof(alarm_addr.sun_family) + strlen(alarm_addr.sun_path)); + if (ret < 0) { + // if errno == EINTR means sendto has been interrupted by system, should retry + if (errno == EINTR) { + /* interrupted by signal, ignore */ + continue; + } else { + fprintf(stderr, "%s: sendto failed errno: %d\n", __func__, errno); + } + } else if (ret == 0) { + fprintf(stderr, "%s: sendto failed, ret is 0\n", __func__); + } else { + // if ret not eaual to sizeof alarm_info, means sendto failed + if (ret != (int)sizeof(struct alarm_info)) { + fprintf(stderr, "%s sendto failed, ret:%d, len:%u\n", __func__, ret, sizeof(struct alarm_info)); + } + } + break; + } + close(fd); + + return (ret > 0) ? 0 : -ECOMM; +} diff --git a/src/libso/xalarm/register_xalarm.h b/src/libso/xalarm/register_xalarm.h index dcf4f03..dfcd04d 100644 --- a/src/libso/xalarm/register_xalarm.h +++ b/src/libso/xalarm/register_xalarm.h @@ -19,6 +19,9 @@ #define MEMORY_ALARM_ID 1001 +#define ALARM_REBOOT_EVENT 1003 +#define ALARM_REBOOT_ACK_EVENT 1004 + #define MINOR_ALM 1 #define MAJOR_ALM 2 #define CRITICAL_ALM 3 @@ -77,6 +80,22 @@ struct alarm_subscription_info { unsigned int len; }; +struct alarm_msg { + unsigned short usAlarmId; + struct timeval AlarmTime; + char pucParas[ALARM_INFO_MAX_PARAS_LEN]; +}; + +struct alarm_register { + int register_fd; + char alarm_enable_bitmap[MAX_NUM_OF_ALARM_ID]; +}; + +int xalarm_report_event(unsigned short usAlarmId, char *pucParas); +int xalarm_register_event(struct alarm_register** register_info, struct alarm_subscription_info id_filter); +int xalarm_get_event(struct alarm_msg* msg, struct alarm_register *register_info); +void xalarm_unregister_event(struct alarm_register *register_info); + int xalarm_Register(alarm_callback_func callback, struct alarm_subscription_info id_filter); void xalarm_UnRegister(int client_id); bool xalarm_Upgrade(struct alarm_subscription_info id_filter, int client_id); -- Gitee