From 6fcb7c9e471269c9256efdc0f38c4c579eb7f4bd Mon Sep 17 00:00:00 2001
From: PshySimon <caixiaomeng2@huawei.com>
Date: Fri, 7 Feb 2025 10:45:14 +0800
Subject: [PATCH] add bidirectional communication for xalarm

---
 src/libs/libxalarm/register_xalarm.c | 154 +++++++++++++++++++++++++++
 src/libs/libxalarm/register_xalarm.h |  21 +++-
 2 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/src/libs/libxalarm/register_xalarm.c b/src/libs/libxalarm/register_xalarm.c
index deca575..9ff0f7c 100644
--- a/src/libs/libxalarm/register_xalarm.c
+++ b/src/libs/libxalarm/register_xalarm.c
@@ -655,3 +655,157 @@ 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;
+    // check whether id_filter is valid
+    if (register_info == NULL || !alarm_subscription_verify(id_filter)) {
+        return -EINVAL;
+    }
+
+    *register_info = (struct alarm_register *)malloc(sizeof(struct alarm_register));
+    // failed to malloc memory for register_info struct
+    if (*register_info == NULL) {
+        return -ENOMEM;
+    }
+
+    // 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) {
+        free(*register_info);
+        return -ENOTCONN;
+    }
+
+    return 0;
+}
+
+void xalarm_unregister_event(struct alarm_register *register_info)  
+{
+    if (register_info == NULL) {
+        return;
+    }
+    // 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)
+{
+    struct alarm_info info;
+    
+    if (msg == NULL || register_info == NULL) {
+        return -EINVAL;
+    }
+
+    while (true) {
+        int recvlen = recv(register_info->register_fd, &info, sizeof(struct alarm_info), 0);
+
+        // recvlen < 0 means that we meet with error when recv.
+        if (recvlen < 0) {
+            // 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;
+            }
+        }
+        // recvlen == 0 means the connection has been properly closed, 
+        // and the remote end has no more data to send.
+        if (recvlen == 0) {
+            close(register_info->register_fd);
+            return -ENOTCONN;
+        }
+        // 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, alarm id reciecved which is not registered by this program
+            // will be ignored and continue to wait for next msg
+            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);
+            // no need to close fd because get_event() can be reused after recv one msg
+            return 0;
+        }
+        // if recvlen > 0 but not equal to sizeof alarm_info, loop to wait for msg
+    }
+}
+
+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;
+    }
+
+    memset(&info, 0, sizeof(struct alarm_info));
+    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 errno == EINTR means sendto has been interrupted by system, should retry
+        if (ret < 0 && errno == EINTR) {
+            continue;
+        }
+        break;
+    }
+
+    close(fd);
+
+    if (ret != (int)sizeof(struct alarm_info)) {
+        return -ECOMM;
+    }
+    return (ret > 0) ? 0 : -errno;
+}
+
+
diff --git a/src/libs/libxalarm/register_xalarm.h b/src/libs/libxalarm/register_xalarm.h
index c56561a..7a485ff 100644
--- a/src/libs/libxalarm/register_xalarm.h
+++ b/src/libs/libxalarm/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);
@@ -118,4 +137,4 @@ extern int report_result(const char *task_name,
 
 extern int send_data_to_socket(const char *socket_path, const char *message);
 
-#endif
\ No newline at end of file
+#endif
-- 
2.27.0

