Skip to content
Snippets Groups Projects
event.c 5.34 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*
     * event.c: event handler
     *
     * Copyright (C) 2023 IOPSYS Software Solutions AB. All rights reserved.
     *
     * Author: Iryna Antsyferova <iryna.antsyferova@iopsys.eu>
     *
     * See LICENSE file for license related information.
     */
    #include "libdmtree/dmcommon.h"
    #include "event.h"
    #include <unistd.h>
    
    #include <netinet/in.h>
    
    #define FIREWALL_RULE_DATA_SIP "Device.Services.VoiceService.1.SIP.Network.1.X_RDK_Firewall_Rule_Data"
    #define FIREWALL_RULE_DATA_SIP_PATTERN "Device\\.Services\\.VoiceService\\.[0-9]+\\.SIP\\.Network\\.[0-9]+\\.X_RDK_Firewall_Rule_Data"
    
    #define FIREWALL_RULE_DATA_RTP "Device.Services.VoiceService.1.VoIPProfile.1.RTP.X_RDK_Firewall_Rule_Data"
    #define FIREWALL_RULE_DATA_RTP_PATTERN "Device\\.Services\\.VoiceService\\.[0-9]+\\.VoIPProfile\\.[0-9]+\\.RTP\\.X_RDK_Firewall_Rule_Data"
    
    // 4 IPv6 rules max
    #define FIREWALL_RULE_STR_LEN_MAX 218
    
    struct rule_node {
    	struct list_head list;
    	char ip[INET6_ADDRSTRLEN];
    	uint16_t port;
    };
    
    static struct list_head sip_list, rtp_list;
    
    int subs_event_init()
    {
    	INIT_LIST_HEAD(&sip_list);
    	INIT_LIST_HEAD(&rtp_list);
    
    	return 0;
    }
    
    void subs_event_uninit()
    {
    	struct rule_node *iter = NULL, *node = NULL;
    
    	list_for_each_entry_safe(iter, node, &sip_list, list) {
    		list_del(&iter->list);
    		free(iter);
    	}
    
    	list_for_each_entry_safe(iter, node, &rtp_list, list) {
    		list_del(&iter->list);
    		free(iter);
    	}
    }
    
    
    int subs_event_handler(const json_object *jmsg, int param_count, json_object *jreply)
    {
    	int ret = RETURN_OK;
    	int param_index = 0;
    	hal_subscribe_event_request_t param_request;
    
    	if (jmsg == NULL || jreply == NULL) {
    		ERR("event handler: Invalid memory");
    		return RETURN_ERR;
    	}
    
    	memset(&param_request, 0, sizeof(param_request));
    
    
    	for (param_index = 0; param_index < param_count; param_index++) {
    		/* Unpack the request parameter */
    		if (json_hal_get_subscribe_event_request((json_object *)jmsg,
    			param_index, &param_request) != RETURN_OK) {
    			INFO("Failed to get subscription data from the server");
    			return RETURN_ERR;
    		}
    
    
    		if (!match(param_request.name, FIREWALL_RULE_DATA_SIP_PATTERN, 0, NULL) &&
    
    			!match(param_request.name, FIREWALL_RULE_DATA_RTP_PATTERN, 0, NULL)) {
    			ret = RETURN_ERR;
    			WARNING("Unexpected event [%s][%d]", param_request.name, (int)param_request.type);
    		}
    		else
    			INFO("Subscribed [%s][%d]", param_request.name, (int)param_request.type);
    
    	}
    
    	ret = json_hal_add_result_status(jreply, ret == RETURN_OK ? RESULT_SUCCESS :
    		RESULT_FAILURE);
    
    	INFO("[%s] Replly msg = %s", __FUNCTION__,
    		json_object_to_json_string_ext(jreply, JSON_C_TO_STRING_PRETTY));
    
    	return ret;
    }
    
    
    static int update_fw_rule_list(bool enable, char *ip, int port,
    	struct list_head *rule_list, bool *changed)
    
    	struct rule_node *node = NULL;
    	bool found = false;
    
    	*changed = false;
    
    	list_for_each_entry(node, rule_list, list) {
    		if (DM_STRNCMP(node->ip, ip, sizeof(node->ip)) == 0 &&
    			node->port == port) {
    			found = true;
    			break;
    		}
    	}
    
    	if (enable == found) {
    		return 0;
    	}
    
    	if (!enable && found) {
    		list_del(&node->list);
    		free(node);
    	}
    
    	if (enable && !found) {
    		node = malloc(sizeof(struct rule_node));
    		if (!node) {
    			ERR("failed to allocate memory");
    			return -1;
    		}
    
    		DM_STRNCPY(node->ip, ip, sizeof(node->ip));
    		node->port = port;
    		INIT_LIST_HEAD(&node->list);
    		list_add_tail(&node->list, rule_list);
    	}
    
    	*changed = true;
    
    	return 0;
    
    /* Expected format of rule : ip,port;
       Example: 192.168.0.11,5060;192.168.0.12,5060;
    */
    static int create_fw_rule_payload(struct list_head *rule_list, char *buf, int buf_size)
    
    	struct rule_node *node = NULL;
    	char *pos = buf, *end = buf + buf_size;
    
    	list_for_each_entry(node, rule_list, list) {
    		if (pos < end) {
    			pos += snprintf(pos, end - pos, "%s,%d;", node->ip, node->port);
    		}
    	}
    
    	if (pos == end) {
    		ERR("fw rule string overflow");
    		return -1;
    	}
    
    	return 0;
    }
    
    static int pub_fw_rule_event(bool enable, char *ip, int port,
    	struct list_head *rule_list, const char *param_name)
    {
    	int ret;
    	bool changed = false;
    	char buf[FIREWALL_RULE_STR_LEN_MAX] = {0};
    
    	ret = update_fw_rule_list(enable, ip, port, rule_list, &changed);
    	if (ret) {
    		ERR("failed to create fw rule list");
    		return -1;
    	}
    
    	if (!changed) {
    		return 0;
    	}
    
    	ret = create_fw_rule_payload(rule_list, buf, sizeof(buf));
    	if (ret) {
    		ERR("failed to create fw rule");
    		return -1;
    	}
    
    	ret = json_hal_server_publish_event(param_name, buf);
    	if (ret != RETURN_OK) {
    		ERR("failed to send fw event");
    		return -1;
    	}
    
    	return 0;
    
    int send_fw_rule_event(bool enable, char *protocol, char *ip, int port)
    {
    	if (DM_STRCMP(protocol, "sip") == 0) {
    		return pub_fw_rule_event(enable, ip, port, &sip_list, FIREWALL_RULE_DATA_SIP);
    	}
    
    	if (DM_STRCMP(protocol, "rtp") == 0) {
    		return pub_fw_rule_event(enable, ip, port, &rtp_list, FIREWALL_RULE_DATA_RTP);
    	}
    
    	DEBUG("wrong protocol: %s", protocol);
    	return -1;
    }
    
    int send_fw_rules_clear_event()
    
    {
    	int ret = 0;
    	char fw_rule[] = {0};
    
    	struct rule_node *iter, *node;
    
    	ret = json_hal_server_publish_event(FIREWALL_RULE_DATA_SIP, fw_rule);
    	if (ret != RETURN_OK) {
    		ERR("failed to send fw sip event");
    		return -1;
    	}
    
    	ret = json_hal_server_publish_event(FIREWALL_RULE_DATA_RTP, fw_rule);
    	if (ret != RETURN_OK) {
    		ERR("failed to send fw rtp event");
    		return -1;
    	}
    
    	list_for_each_entry_safe(iter, node, &sip_list, list) {
    		list_del(&iter->list);
    		free(iter);
    	}
    
    	list_for_each_entry_safe(iter, node, &rtp_list, list) {
    		list_del(&iter->list);
    		free(iter);
    	}
    
    	return 0;