From: dyamy-lee Date: Thu, 20 Aug 2020 03:49:43 +0000 (+0900) Subject: add code for TraceProtocol X-Git-Tag: accepted/tizen/unified/20200901.160655~37 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F61%2F242761%2F1;p=platform%2Fcore%2Fuifw%2Flibds.git add code for TraceProtocol checked rule init with file. logs are alot. -> It should be removed almost for readablilty add rule_print_func as DSLOG_INF -> It should be printed Change-Id: I11985d3e0420758c7f641ec7e4b1ba6187f5afc0 --- diff --git a/src/DSWaylandServer/DSWaylandProtocolTrace.cpp b/src/DSWaylandServer/DSWaylandProtocolTrace.cpp index 0f8c9a6..fe89016 100644 --- a/src/DSWaylandServer/DSWaylandProtocolTrace.cpp +++ b/src/DSWaylandServer/DSWaylandProtocolTrace.cpp @@ -23,6 +23,8 @@ #include "DSWaylandProtocolTrace.h" #include "DSWaylandProtocolTracePrivate.h" +#include +#include namespace display_server { @@ -31,10 +33,69 @@ int DSWaylandProtocolTrace::__refCount { 0 }; std::mutex DSWaylandProtocolTrace::__mutex; DSWaylandProtocolTrace* DSWaylandProtocolTrace::__protocolTrace { nullptr }; +static FILE *log_fp_ptrace = NULL; +static struct wl_protocol_logger *ds_wl_protocol_logger; +static ProtocolTrace_Rule_Checker *rc = nullptr; + +static struct +{ + const char *token_char; + const int token_length; + ProtocolTrace_Token token_name; +} token_table[] = +{ + {"\0", 1, PROTOCOLTRACE_TOKEN_EOS}, + {"\t", 1, PROTOCOLTRACE_TOKEN_SPACE}, + {" ", 1, PROTOCOLTRACE_TOKEN_SPACE}, + {"!=", 2, PROTOCOLTRACE_TOKEN_NOT_EQ}, + {"&", 1, PROTOCOLTRACE_TOKEN_AND}, + {"&&", 2, PROTOCOLTRACE_TOKEN_AND}, + {"(", 1, PROTOCOLTRACE_TOKEN_L_BR}, + {")", 1, PROTOCOLTRACE_TOKEN_R_BR}, + {"<", 1, PROTOCOLTRACE_TOKEN_LSS_THAN}, + {"<=", 2, PROTOCOLTRACE_TOKEN_LSS_EQ}, + {"<>", 2, PROTOCOLTRACE_TOKEN_NOT_EQ}, + {"=", 1, PROTOCOLTRACE_TOKEN_EQUAL}, + {"==", 2, PROTOCOLTRACE_TOKEN_EQUAL}, + {">", 1, PROTOCOLTRACE_TOKEN_GRT_THAN}, + {">=", 2, PROTOCOLTRACE_TOKEN_GRT_EQ}, + {"and", 3, PROTOCOLTRACE_TOKEN_AND}, + {"or", 2, PROTOCOLTRACE_TOKEN_OR}, + {"|", 1, PROTOCOLTRACE_TOKEN_OR}, + {"||", 2, PROTOCOLTRACE_TOKEN_OR}, +}; + +const char *get_next_argument(const char *signature, struct argument_details *details) +{ + details->nullable = 0; + for(; *signature; ++signature) + { + switch(*signature) + { + case 'i': + case 'u': + case 'f': + case 's': + case 'o': + case 'n': + case 'a': + case 'h': + details->type = *signature; + return signature +1; + case '?': + details->nullable = 1; + } + } + details->type = '\0'; + return signature; +} + DSWaylandProtocolTrace::DSWaylandProtocolTrace(DSObject *parent) : DS_INIT_PRIVATE_PTR(DSWaylandProtocolTrace) { //init(); + DS_GET_PRIV(DSWaylandProtocolTrace); + priv->__wlCompositor = DSWaylandCompositor::getInstance(); } DSWaylandProtocolTrace::~DSWaylandProtocolTrace() @@ -74,12 +135,72 @@ void DSWaylandProtocolTrace::releaseInstance() bool DSWaylandProtocolTrace::init(void) { - return false; + DS_GET_PRIV(DSWaylandProtocolTrace); + bool ret = false; + char *env_path = nullptr; + char tmp[PATH_MAX] = {0,}; + + rc = priv->rulechecker_init(); + + // set rule file path + env_path = getenv("E_INFO_RULE_FILE"); + DSLOG_DBG("DSWaylandProtocolTrace", "========================== rule file path = %s", env_path); + ret = priv->protocol_rule_init(env_path); + DSLOG_DBG("DSWaylandProtocolTrace", "result of protocol rule init = %d", ret); + + if(env_path) + { + DSLOG_DBG("DSWaylandProtocolTrace", "delete rule file path = %s", env_path); + //delete env_path; + //free(env_path); + env_path = nullptr; + DSLOG_DBG("DSWaylandProtocolTrace", "delete rule file path done."); + } + if(!ret) return ret; + + // set trace file path + DSLOG_DBG("DSWaylandProtocolTrace", "===================================================="); + env_path = getenv("E_INFO_TRACE_FILE"); + DSLOG_DBG("DSWaylandProtocolTrace", "========================== trace file path = %s", env_path); + ret = priv->protocol_trace_init(env_path); + DSLOG_DBG("DSWaylandProtocolTrace", "result of protocol trace init = %d", ret); + if(env_path) + { + DSLOG_DBG("DSWaylandProtocolTrace", "delete trace file path = %s", env_path); + //delete env_path; + //free(env_path); + env_path = nullptr; + DSLOG_DBG("DSWaylandProtocolTrace", "delete trace file path done."); + } + return ret; } int DSWaylandProtocolTrace::enableProtocolTrace(bool state) { + DS_GET_PRIV(DSWaylandProtocolTrace); //following state : enable, disable trace + DSLOG_DBG("DSWaylandProtocolTrace", "state = %d", state); + + if(log_fp_ptrace != nullptr) + { + fclose(log_fp_ptrace); + log_fp_ptrace = nullptr; + } + + if(state) + { + //TODO: can change trace file path by cmd + DSLOG_DBG("DSWaylandProtocolTrace", "state true == %d", state); + priv->protocol_trace_set(); + return 1; + } + else + { + DSLOG_DBG("DSWaylandProtocolTrace", "state false == %d", state); + priv->protocol_trace_unset(); + return 0; + } + return -1; } @@ -94,20 +215,1325 @@ DSWaylandProtocolTracePrivate::~DSWaylandProtocolTracePrivate() } -void DSWaylandProtocolTracePrivate::protocol_rule_init(char *rule_path) +bool DSWaylandProtocolTracePrivate::protocol_rule_init(char *rule_path) +{ + char *argv[2]; + int argc = 2; + + if(!rule_path || strlen(rule_path) <= 0) + return false; + + argv[0] = "file"; + argv[1] = rule_path; + + DSLOG_DBG("DSWaylandProtocolTracePriv", "rule_path = %s", rule_path); + + protocol_rule_set(argc, (const char**)&(argv[0])); + + return true; +} + +bool DSWaylandProtocolTracePrivate::protocol_trace_init(char *trace_path) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> protocol_trace_init"); + if(!trace_path || strlen(trace_path) <= 0) + return false; + + trace_env_path = trace_path; + DSLOG_DBG("DSWaylandProtocolTracePriv", "saved trace path = %s", trace_env_path); + + //enable + protocol_trace_set(); + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << protocol_trace_init"); + /* + log_fp_ptrace = fopen(trace_path, "a"); + + setvbuf(log_fp_ptrace, NULL, _IOLBF, 512); + + if(ds_wl_protocol_logger) + { + wl_protocol_logger_destroy(ds_wl_protocol_logger); + ds_wl_protocol_logger = NULL; + } + ::wl_display *display; + display = __wlCompositor->display(); + ds_wl_protocol_logger = wl_display_add_protocol_logger(display, protocol_trace_func, nullptr); + */ + return true; +} + +bool DSWaylandProtocolTracePrivate::protocol_rule_set(const int argc, const char **argv) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> protocol_rule_set"); + const char * command; + + if(argc == 0) + { + rulechecker_rule_print(rc); + return true; + } + + command = argv[0]; + + if(!strcasecmp(command, "add")) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD"); + ProtocolTrace_Policy_Type policy_type; + ProtocolTrace_Rule_Set_Result result; + const char * policy = argv[1]; //allow, deny + char merge[8192] = {0,}, rule[8192] = {0,}; + int i, index=0, size_rule, apply = 0; + + if(argc <3) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Error: Too few argumens."); + //REPLY("Error : Too few arguments."); + return false; + } + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: go on"); + + if(!strcasecmp(policy, "ALLOW")) + policy_type = PROTOCOLTRACE_TYPE_ALLOW; + else if(!strcasecmp(policy, "DENY")) + policy_type = PROTOCOLTRACE_TYPE_DENY; + else + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Error : Unknown policy : [%s].\n Policy should be ALLOW or DENY.", policy); + //REPLY; + return false; + } + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: policy_type = %d", policy_type); + + // protocol arguments merge + protocol_arguments_merge(merge, sizeof(merge), argc -2, &(argv[2])); + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: merge = %s", merge); + + size_rule = sizeof(rule) -1; + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: size_rule = %d", size_rule); + + for(i=0; i size_rule) + return false; + continue; + } + if(merge[i] == '+') + { + rule[index++] = ' '; + if(index > size_rule) + return false; + if(apply ==0) + { + const char * plus = "|| type=reply || type=error"; + int len = MIN(size_rule - index, strlen(plus)); + strncat(rule, plus, len); + index += len; + if(index >size_rule) + return false; + apply =1; + } + continue; + } + rule[index++] = merge[i]; + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: rule[%d] = %c", index-1, rule[index-1]); + if(index >size_rule) + return false; + } + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: rule = %s", rule); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: rulechecker_rule_add (before) -> rc %d",rc->count); + result = rulechecker_rule_add(rc, policy_type, rule); + DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: rulechecker_rule_add (after) -> rc %d",rc->count); + + if(result == PROTOCOLTRACE_RULE_SET_ERR_TOO_MANY_RULES) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Error: Too many rules were added."); + return false; + } + else if(result == PROTOCOLTRACE_RULE_SET_ERR_PARSE) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Error: An error occured during parsing the rule [%s]", rule); + return false; + } + DSLOG_INF("DSWaylandProtocolTracePriv", "The rule was successfully added"); + rulechecker_rule_print(rc); + + return true; + } + else if(!strcasecmp(command, "remove")) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "REMOVE"); + const char * remove_idx; + int i; + + if(argc < 2) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Error: Too few arguments"); + return false; + } + + for(i =0; icount); + rulechecker_destroy(rc); + rc = rulechecker_init(); + if(!rc) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Error: rules not removed"); + return false; + } + DSLOG_DBG("DSWaylandProtocolTracePriv", "REMOVE :: (after destroy) rc = %d", rc->count); + DSLOG_INF("DSWaylandProtocolTracePriv", "Every rules were successfully removed"); + } + else + { + int index = atoi(remove_idx); + DSLOG_DBG("DSWaylandProtocolTracePriv", "REMOVE :: remove idx = %d", index); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "REMOVE :: (before rulechecker_rule_remove) rc = %d", rc->count); + if(isdigit(*remove_idx) && rulechecker_rule_remove(rc, index) == 0) + DSLOG_INF("DSWaylandProtocolTracePriv", "The rule [%d] was successfully removed.", index); + else + DSLOG_ERR("DSWaylandProtocolTracePriv", "Rule remove fail : No such rule [%s]", remove_idx); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "REMOVE :: (after rulechecker_rule_remove) rc = %d", rc->count); + } + } + rulechecker_rule_print(rc); + } + else if(!strcasecmp(command, "file")) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "FILE"); + if(argc <2) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Error: Too few argumens."); + //REPLY("Error : Too few arguments."); + return false; + } + if(!protocol_rule_file_set(argv[1])) + return false; + + rulechecker_rule_print(rc); + + return true; + } + else if(!strcasecmp(command, "print")) + { + rulechecker_rule_print(rc); + return true; + } + else if(!strcasecmp(command, "help")) + { + DSLOG_INF("DSWaylandProtocolTracePriv", "%s", rulechecker_usage_print()); + return true; + } + + DSLOG_ERR("DSWaylandProtocolTracePriv", "%s\nUnkown command : [%s] ", rulechecker_usage_print(), command); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << protocol_rule_set"); + + return true; +} + +bool DSWaylandProtocolTracePrivate::protocol_rule_file_set(const char *filename) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> protocol_rule_file_set"); + int fd = -1, rule_len; + char fs[8096], *pfs; + + fd = open(filename, O_RDONLY); + if(fd<0) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "failed: open '%s'", filename); + return false; + } + + rule_len = read(fd, fs, sizeof(fs)); + pfs = fs; + + while(pfs -fs < rule_len) + { + int i, new_argc =3; + char *new_argv[3] = {"add", }; + char policy[64] = {0,}; + char rule[1024] = {0,}; + + if(pfs[0] == ' ' || pfs[0] == '\n') + { + pfs++; + continue; + } + for(i=0; pfs[i] != ' '; i++) + policy[i] = pfs[i]; + + new_argv[1] = policy; + pfs += (strlen(new_argv[1])+1); + + memset(rule, 0, sizeof(rule)); + for(i=0; pfs[i]!='\n'; i++) + rule[i] = pfs[i]; + + new_argv[2] = rule; + + pfs += (strlen(new_argv[2]) +1); + + if(!protocol_rule_set((const int) new_argc, (const char**) new_argv)) + { + close(fd); + return false; + } + } + close(fd); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << protocol_rule_file_set"); + return true; +} + +bool DSWaylandProtocolTracePrivate::protocol_rule_validate(ProtocolTrace_Protocol_Log *log) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> protocol_rule_validate << "); + char *cmd = ""; + + if(!rc) + return false; + + cmd = protocol_cmd_get(log->cmd); + + return rulechecker_rule_validate(rc, log->type, log->target_id, log->name, log->client_pid, cmd); +} + +void DSWaylandProtocolTracePrivate::protocol_trace_set(void) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv","IN >> protocol trace set"); + log_fp_ptrace = fopen(trace_env_path, "a"); + if(!log_fp_ptrace) + { + DSLOG_ERR("DSWaylandProtocolTracePriv","failed open file(%s)", trace_env_path); + return; + } + setvbuf(log_fp_ptrace, NULL, _IOLBF, 512); + DSLOG_DBG("DSWaylandProtocolTracePriv","has log_fp_ptrace"); + + if(ds_wl_protocol_logger) + { + DSLOG_DBG("DSWaylandProtocolTracePriv","if has ds_wl_protocol_logger -> destroy"); + wl_protocol_logger_destroy(ds_wl_protocol_logger); + ds_wl_protocol_logger = NULL; + } + ::wl_display *display; + display = __wlCompositor->display(); + DSLOG_DBG("DSWaylandProtocolTracePriv","get display "); + + ds_wl_protocol_logger = wl_display_add_protocol_logger(display, protocol_trace_func, nullptr); + DSLOG_DBG("DSWaylandProtocolTracePriv","OUT << protocol trace set"); +} + +void DSWaylandProtocolTracePrivate::protocol_trace_unset(void) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv","IN >> protocol_trace_unset"); + if(ds_wl_protocol_logger) + { + wl_protocol_logger_destroy(ds_wl_protocol_logger); + ds_wl_protocol_logger = NULL; + } + DSLOG_DBG("DSWaylandProtocolTracePriv","OUT << protocol_trace_unset"); +} + +void DSWaylandProtocolTracePrivate::wl_protocol_cb_client_destroy(struct wl_listener *listener, void *data) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv","IN >> wl_protocol_cb_client_destroy"); + + struct wl_client *wc = (struct wl_client *)data; + struct timespec tp; + unsigned int time; + pid_t client_pid =-1; + + + char strbuf[512], *str_buff = strbuf; + int str_r, str_l; + + str_buff[0] = '\0'; + str_r = sizeof(strbuf); + + wl_client_get_credentials(wc, &client_pid, nullptr, nullptr); + + clock_gettime(CLOCK_MONOTONIC, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + //TODO: get client name + BUF_SNPRINTF("[%10.3f] Server [PID:%d] client destroying", time/1000.0, client_pid); + + if(log_fp_ptrace) + fprintf(log_fp_ptrace, "%s\n", strbuf); + else + DSLOG_INF("DSWaylandProtocolTracePriv", "%s", strbuf); + + wl_list_remove(&listener->link); + //free(listener); + delete listener; + listener = nullptr; + + DSLOG_DBG("DSWaylandProtocolTracePriv","OUT << wl_protocol_cb_client_destroy"); + +} + +void DSWaylandProtocolTracePrivate::protocol_client_destroy_listener_reg(struct wl_client *client) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv","IN >> protocol_client_destroy_listener_reg"); + + struct wl_listener *destroy_listener; + + destroy_listener = wl_client_get_destroy_listener(client, wl_protocol_cb_client_destroy); + if(destroy_listener) return; + + destroy_listener = (struct wl_listener *)calloc(1, sizeof(wl_listener)); + //EINA_SAFETY_ON_NULL_RETURN(destroy_listener); + + destroy_listener->notify = wl_protocol_cb_client_destroy; + wl_client_add_destroy_listener(client, destroy_listener); + + DSLOG_DBG("DSWaylandProtocolTracePriv","OUT << protocol_client_destroy_listener_reg"); +} + +void DSWaylandProtocolTracePrivate::protocol_trace_func(void *user_data, enum wl_protocol_logger_type direction, const struct wl_protocol_logger_message *message) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv","IN >> protocol_trace_func"); + + int i; + struct argument_details arg; + struct wl_client *wc = wl_resource_get_client(message->resource); + const char *signature = message->message->signature; + pid_t client_pid = -1; + struct timespec tp; + unsigned int time; + + char strbuf[512], *str_buff = strbuf; + int str_r, str_l; + + str_buff[0] = '\0'; + str_r = sizeof(strbuf); + + if(wc) + { + DSLOG_DBG("DSWaylandProtocolTracePriv","has wl_client"); + protocol_client_destroy_listener_reg(wc); + wl_client_get_credentials(wc, &client_pid, nullptr, nullptr); + } + + DSLOG_DBG("DSWaylandProtocolTracePriv","go on"); + + clock_gettime(CLOCK_MONOTONIC, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + ProtocolTrace_Protocol_Log elog = {PROTOCOL_TYPE_REQUEST,}; + DSLOG_DBG("DSWaylandProtocolTracePriv", "before get info protocol log => type: %s, client_pit: %d, target_id: %d, name: %s, cmd: %s", elog.type, elog.client_pid, elog.target_id, elog.name, elog.cmd); + elog.type = (direction == WL_PROTOCOL_LOGGER_EVENT)? PROTOCOL_TYPE_EVENT:PROTOCOL_TYPE_REQUEST; + elog.client_pid = client_pid; + elog.target_id = wl_resource_get_id(message->resource); + snprintf(elog.name, PATH_MAX,"%s:%s", wl_resource_get_class(message->resource), message->message->name); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "after get info protocol log => type: %s, client_pit: %d, target_id: %d, name: %s, cmd: %s", elog.type, elog.client_pid, elog.target_id, elog.name, elog.cmd); + + if(!protocol_rule_validate(&elog)) return; + + BUF_SNPRINTF("[%10.3f] %s%d%s%s@%u.%s(", + time / 1000.0, + elog.type ? "Server->Client [PID:" : "Server<-Client [PID:", + client_pid, "]", + wl_resource_get_class(message->resource), + wl_resource_get_id(message->resource), + message->message->name); + + for (i=0; iarguments_count; i++) + { + signature = get_next_argument(signature, &arg); + if(i>0) BUF_SNPRINTF(", "); + + switch(arg.type) + { + case 'u': + BUF_SNPRINTF("%u", message->arguments[i].u); + break; + case 'i': + BUF_SNPRINTF("%i", message->arguments[i].i); + break; + case 'f': + BUF_SNPRINTF("%f", wl_fixed_to_double(message->arguments[i].f)); + break; + case 's': + BUF_SNPRINTF("\"%s\"", message->arguments[i].s); + break; + case 'o': + if(message->arguments[i].o) + BUF_SNPRINTF("%s@%u", wl_resource_get_class((struct wl_resource*)message->arguments[i].o), + wl_resource_get_id((struct wl_resource*)message->arguments[i].o)); + else + BUF_SNPRINTF("nil"); + break; + case 'n': + BUF_SNPRINTF("new id %s@", (message->message->types[i]) ? message->message->types[i]->name : "[unknown]"); + if(message->arguments[i].n != 0) + BUF_SNPRINTF("%u", message->arguments[i].n); + else + BUF_SNPRINTF("nil"); + break; + case 'a': + BUF_SNPRINTF("array"); + break; + case 'h': + BUF_SNPRINTF("fd %d", message->arguments[i].h); + break; + } + } + + BUF_SNPRINTF("), cmd: %s", elog.cmd ? elog.cmd : "cmd is NULL"); + + if(log_fp_ptrace) + fprintf(log_fp_ptrace, "%s\n", strbuf); + else + DSLOG_INF("DSWaylandProtocolTracePriv","%s", strbuf); + + DSLOG_DBG("DSWaylandProtocolTracePriv","OUT << protocol_trace_func"); + +} + +ProtocolTrace_Tree_Node *DSWaylandProtocolTracePrivate::bintree_create_node(ProtocolTrace_Tree *tree) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv","IN >> bintree_create_node"); + + ProtocolTrace_Tree_Node *node = (ProtocolTrace_Tree_Node*) calloc(1, sizeof(ProtocolTrace_Tree_Node) + tree->size); + // enia safety + + node->left = nullptr; + node->right = nullptr; + + DSLOG_DBG("DSWaylandProtocolTracePriv","OUT << bintree_create_node"); + return node; +} + +ProtocolTrace_Tree *DSWaylandProtocolTracePrivate::bintree_create_tree(int size) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_create_tree"); + + ProtocolTrace_Tree *tree = (ProtocolTrace_Tree *)calloc(1, sizeof(ProtocolTrace_Tree) + size); + // eina safety + + tree->size = size; + tree->head = nullptr; + DSLOG_DBG("DSWaylandProtocolTracePriv", "bintree create treee => size : %d", tree->size); + + DSLOG_DBG("DSWaylandProtocolTracePriv","OUT << bintree_create_tree"); + + return tree; +} + +void DSWaylandProtocolTracePrivate::bintree_destroy_tree(ProtocolTrace_Tree *tree) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_destroy_tree"); + if(tree->head) + bintree_remove_node_recursive(tree->head); + //free(tree); + delete tree; + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_destroy_tree"); +} + +ProtocolTrace_Tree_Node *DSWaylandProtocolTracePrivate::bintree_get_head(ProtocolTrace_Tree *tree) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_get_head >> OUT"); + return tree->head; +} + +ProtocolTrace_Tree_Node *DSWaylandProtocolTracePrivate::bintree_get_left_child(ProtocolTrace_Tree_Node *node) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_get_left_child >> OUT"); + return node->left; +} + +void *DSWaylandProtocolTracePrivate::bintree_get_node_data(ProtocolTrace_Tree_Node *node) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_get_node_data >> OUT"); + return (void*)(node+1); +} + +ProtocolTrace_Tree_Node *DSWaylandProtocolTracePrivate::bintree_get_right_child(ProtocolTrace_Tree_Node *node) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_get_right_child >> OUT"); + return node->right; +} + +void DSWaylandProtocolTracePrivate::bintree_inorder_traverse(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Traverse_Cb func, void *arg) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_inorder_traverse"); + if(tree->head) + bintree_inorder_traverse_recursive(tree, tree->head, tree->head, func, arg); + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_inorder_traverse"); +} + +int DSWaylandProtocolTracePrivate::bintree_inorder_traverse_recursive(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, ProtocolTrace_Tree_Traverse_Cb func, void *arg) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_inorder_traverse_recursive >> "); + if(node->left) + if(bintree_inorder_traverse_recursive(tree, node->left, node, func, arg)!=0) + return 1; + + if(func(tree, node, parent, arg)) + return 1; + + if(node->right) + if(bintree_inorder_traverse_recursive(tree,node->right, node, func, arg)!=0) + return 1; + return 0; +} + +void DSWaylandProtocolTracePrivate::bintree_postorder_traverse(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Traverse_Cb func, void *arg) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_postorder_traverse"); + if(tree->head) + bintree_postorder_traverse_recursive(tree, tree->head, tree->head, func, arg); + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_postorder_traverse"); +} + +int DSWaylandProtocolTracePrivate::bintree_postorder_traverse_recursive(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, ProtocolTrace_Tree_Traverse_Cb func, void *arg) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_postorder_traverse_recursive >> "); + if(node->left) + if(bintree_postorder_traverse_recursive(tree, node->left, node, func, arg)!=0) + return 1; + if(node->right) + if(bintree_postorder_traverse_recursive(tree, node->right, node, func, arg)!=0) + return 1; + + return func(tree, node,parent, arg); +} + +void DSWaylandProtocolTracePrivate::bintree_remove_node(ProtocolTrace_Tree_Node *node) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_remove_node"); + //free(node); + delete node; + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_remove_node"); +} + +void DSWaylandProtocolTracePrivate::bintree_remove_node_recursive(ProtocolTrace_Tree_Node *node) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_remove_node_recursive"); + if(node->left) + bintree_remove_node_recursive(node->left); + if(node->right) + bintree_remove_node_recursive(node->right); + + bintree_remove_node(node); + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_remove_node_recursive"); +} + +void DSWaylandProtocolTracePrivate::bintree_set_head(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *head) { + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_set_head"); + tree->head = head; + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_set_head"); } -void DSWaylandProtocolTracePrivate::protocol_trace_init(char *trace_path) +void DSWaylandProtocolTracePrivate::bintree_set_left_child(ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *child) { + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_set_left_child"); + node->left = child; + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_set_left_child"); +} + +void DSWaylandProtocolTracePrivate::bintree_set_right_child(ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *child) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> bintree_set_right_child"); + node->right = child; + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << bintree_set_right_child"); +} + +ProtocolTrace_Token DSWaylandProtocolTracePrivate::parser_next_token_get(const char **string) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> parser_next_token_get"); + DSLOG_DBG("DSWaylandProtocolTracePriv", "parameter string = %s",*string); + + static int token_cnt = sizeof(token_table) / sizeof(token_table[0]); + int i, compare_res, found =0, first, last; + + first = 0; + last = token_cnt -1; + + i = (first + last) /2; + while(1) + { + compare_res = strncmp(*string, token_table[i].token_char, token_table[i].token_length); + DSLOG_DBG("DSWaylandProtocolTracePriv", "parser_next_token_get:: i = %d// compare string -> string = %s ,vs, token_char = %s",i,*string, token_table[i].token_char); + while(compare_res == 0) + { + found = 1; + i++; + if(i==token_cnt) + break; + compare_res = strncmp(*string, token_table[i].token_char, token_table[i].token_length); + } + + if(found) + { + i--; + DSLOG_DBG("DSWaylandProtocolTracePriv", "parm string (before)=> %s",*string); + *string += token_table[i].token_length; + DSLOG_DBG("DSWaylandProtocolTracePriv", "parm string (after = add token length) => %s",*string); + DSLOG_DBG("DSWaylandProtocolTracePriv", "parser next token => %d, token_table name = %d",i,token_table[i].token_name); + return token_table[i].token_name; + } + + if(first >= last) + break; + + if(compare_res > 0) + first = i+1; + else + last = i-1; + + i = (first + last) /2; + + } + if(isalpha(**string)) + { + (*string)++; + DSLOG_DBG("DSWaylandProtocolTracePriv", "string is alpha >> next? = %c",**string); + while(isalpha(**string) || isdigit(**string) || **string == '_' || **string == '-') + { + (*string)++; + } + DSLOG_DBG("DSWaylandProtocolTracePriv", "string is alpha >> end alpha = %c",**string); + + return PROTOCOLTRACE_TOKEN_SYMBOL; + } + if(isdigit(**string)) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "string is digit = %c",**string); + (*string)++; + while(isdigit(**string)) + (*string)++; + + return PROTOCOLTRACE_TOKEN_NUMBER; + } + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << parser_next_token_get"); + return PROTOCOLTRACE_TOKEN_UNKNOWN; } -void DSWaylandProtocolTracePrivate::protocol_rule_set(void) +ProtocolTrace_Tree *DSWaylandProtocolTracePrivate::protocol_parser_rule_string_parse(const char *string) { + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> protocol_parser_rule_string_parse"); + DSLOG_DBG("DSWaylandProtocolTracePriv", "parameter string = %s", string); + + ProtocolTrace_Tree *tree; + ProtocolTrace_Tree_Node *node; + ProtocolTrace_Token_Data token; + + token.string = &string; + DSLOG_DBG("DSWaylandProtocolTracePriv", "token = %s", *token.string); + parser_token_process(&token); + DSLOG_DBG("DSWaylandProtocolTracePriv", "token(after parser) = %s, %d", *token.string, token.last_token); + + tree = bintree_create_tree(sizeof(ProtocolTrace_Rule_Node)); + if(!tree) return nullptr; + + node = parser_token_parse(tree, &token); + DSLOG_DBG("DSWaylandProtocolTracePriv", "get node"); + + if(!node) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "node is null"); + bintree_destroy_tree(tree); + DSLOG_DBG("DSWaylandProtocolTracePriv", "finish destroy tree & return null"); + return nullptr; + } + + bintree_set_head(tree, node); + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << protocol_parser_rule_string_parse "); + + return tree; } -void DSWaylandProtocolTracePrivate::protocol_rule_file_set(void) +ProtocolTrace_Tree_Node *DSWaylandProtocolTracePrivate::parser_statement_parse(ProtocolTrace_Tree *tree, ProtocolTrace_Token_Data *token) { + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> parser_statement_parse"); + DSLOG_DBG("DSWaylandProtocolTracePriv", "(parameter) token->string = %s, token->last symbol =%s", *token->string, token->last_symbol); + DSLOG_DBG("DSWaylandProtocolTracePriv", "(parameter) tree_size = %d", tree->size); + + ProtocolTrace_Tree_Node *node = nullptr; + ProtocolTrace_Rule_Node *data; + + if(token->last_token == PROTOCOLTRACE_TOKEN_L_BR) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "last token = %d", PROTOCOLTRACE_TOKEN_L_BR); + parser_token_process(token); + + node = parser_token_parse(tree, token); + if(!node) + return nullptr; + + if(token->last_token != PROTOCOLTRACE_TOKEN_R_BR) + goto fail; + + DSLOG_DBG("DSWaylandProtocolTracePriv", "not fail"); + parser_token_process(token); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << parser_statement_parse"); + return node; + } + + if(token->last_token != PROTOCOLTRACE_TOKEN_SYMBOL) + goto fail; + + node = bintree_create_node(tree); + //eina safty + + data = (ProtocolTrace_Rule_Node *) bintree_get_node_data(node); + + strncpy(data->variable_name, token->last_symbol, token->symbol_len); + data->variable_name[token->symbol_len] = '\0'; + + if(!strcasecmp(data->variable_name, "all")) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "data = all"); + data->node_type = PROTOCOLTRACE_NODE_TYPE_ALL; + parser_token_process(token); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << parser_statement_parse"); + return node; + } + + data->node_type = PROTOCOLTRACE_NODE_TYPE_DATA; + + parser_token_process(token); + + switch(token->last_token) + { + case PROTOCOLTRACE_TOKEN_NOT_EQ: + data->comparer = PROTOCOLTRACE_COMPARER_NOT_EQ; + break; + case PROTOCOLTRACE_TOKEN_EQUAL: + data->comparer = PROTOCOLTRACE_COMPARER_EQUAL; + break; + case PROTOCOLTRACE_TOKEN_LSS_THAN: + data->comparer = PROTOCOLTRACE_COMPARER_LESS_EQ; + break; + case PROTOCOLTRACE_TOKEN_GRT_THAN: + data->comparer = PROTOCOLTRACE_COMPARER_GREATER; + break; + case PROTOCOLTRACE_TOKEN_GRT_EQ: + data->comparer = PROTOCOLTRACE_COMPARER_GREATE_EQ; + break; + default: + goto fail; + } + + parser_token_process(token); + + if(token->last_token == PROTOCOLTRACE_TOKEN_NUMBER) + { + data->value_type = PROTOCOLTRACE_DATA_TYPE_INTEGER; + data->value.integer = atoi(token->last_symbol); + } + else if (token->last_token == PROTOCOLTRACE_TOKEN_SYMBOL) + { + data->value_type = PROTOCOLTRACE_DATA_TYPE_STRING; + strncpy(data->value.string, token->last_symbol, token->symbol_len); + data->value.string[token->symbol_len] = '\0'; + } + else + { + goto fail; + } + + parser_token_process(token); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << parser_statement_parse"); + return node; + fail: + if(node) + bintree_remove_node_recursive(node); + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << parser_statement_parse"); + return nullptr; +} + +ProtocolTrace_Tree_Node *DSWaylandProtocolTracePrivate::parser_token_parse(ProtocolTrace_Tree *tree, ProtocolTrace_Token_Data *token) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> parser_token_parse"); + DSLOG_DBG("DSWaylandProtocolTracePriv", "(parameter) string = %s, last token = %d, last symbol = %s", *token->string, token->last_token, token->last_symbol); + + ProtocolTrace_Tree_Node *node, *left = nullptr, *right = nullptr; + ProtocolTrace_Rule_Node *data; + + node = parser_statement_parse(tree,token); + + if(!node) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "PARSE statement error\n"); + goto fail; + } + + while(token->last_token == PROTOCOLTRACE_TOKEN_AND) + { + left = node; + node = nullptr; + + parser_token_process(token); + + right = parser_statement_parse(tree, token); + if(!right) + goto fail; + + node = bintree_create_node(tree); + // eina safety + + data = (ProtocolTrace_Rule_Node *) bintree_get_node_data(node); + data->node_type = PROTOCOLTRACE_NODE_TYPE_AND; + bintree_set_left_child(node, left); + bintree_set_right_child(node, right); + } + + if(token->last_token == PROTOCOLTRACE_TOKEN_OR) + { + left = node; + node = nullptr; + + parser_token_process(token); + + right = parser_token_parse(tree, token); + if(!right) + goto fail; + + node = bintree_create_node(tree); + //eina safety + + data = (ProtocolTrace_Rule_Node *) bintree_get_node_data(node); + data->node_type = PROTOCOLTRACE_NODE_TYPE_OR; + bintree_set_left_child(node, left); + bintree_set_right_child(node, right); + } + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << parser_token_parse"); + return node; + + fail: + DSLOG_DBG("DSWaylandProtocolTracePriv", "[fail] recursive remove node"); + if(left) + bintree_remove_node_recursive(left); + DSLOG_DBG("DSWaylandProtocolTracePriv", "return null"); + return nullptr; +} + +void DSWaylandProtocolTracePrivate::parser_token_process(ProtocolTrace_Token_Data *token) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> parser_token_process"); + do + { + token->last_symbol = *(token->string); + DSLOG_DBG("DSWaylandProtocolTracePriv", "last symbol = %c", token->last_symbol); + token->last_token = parser_next_token_get(token->string); + DSLOG_DBG("DSWaylandProtocolTracePriv", "last token = %d", token->last_token); + token->symbol_len = *(token->string) - token->last_symbol; + DSLOG_DBG("DSWaylandProtocolTracePriv", "last_symbol : %s , last_token : %d, symbol_len : %d", token->last_symbol, token->last_token, token->symbol_len); + } while (token->last_token == PROTOCOLTRACE_TOKEN_SPACE); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << parser_token_process"); +} + +void DSWaylandProtocolTracePrivate::protocol_arguments_merge(char *target, int target_size, int argc, const char **argv) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> protocol_arguments_merge"); + DSLOG_DBG("DSWaylandProtocolTracePriv", "(parameter) target = %s", target); + DSLOG_DBG("DSWaylandProtocolTracePriv", "(parameter) target size= %d", target_size); + + int i, len; + + for(i=0; i> protocol_cmd_get"); + char *p; + if(!path) return nullptr; + + p = strrchr(path, '/'); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << protocol_cmd_get"); + return (p)?p+1:path; +} + +void DSWaylandProtocolTracePrivate::rulechecker_destroy(ProtocolTrace_Rule_Checker *rc) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rulechecker_destroy"); + + int i; + for(i=rc->count-1; i>=0; i--) + rulechecker_rule_remove(rc,i); + + //free(rc); + delete rc; + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rulechecker_destroy"); +} + +ProtocolTrace_Rule_Checker *DSWaylandProtocolTracePrivate::rulechecker_init() +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rulechecker_init"); + + ProtocolTrace_Rule_Checker *rc = (ProtocolTrace_Rule_Checker *) calloc(1, sizeof(ProtocolTrace_Rule_Checker)); + if (!rc) + return nullptr; + + rc->count = 0; + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rulechecker_init"); + + return rc; +} + +int DSWaylandProtocolTracePrivate::rulechecker_int_compare(ProtocolTrace_Comparer comparer, int int2, int int1) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rulechecker_int_compare >> "); + + switch (comparer) + { + case PROTOCOLTRACE_COMPARER_EQUAL: + return int1 == int2; + case PROTOCOLTRACE_COMPARER_LESS: + return int1 < int2; + case PROTOCOLTRACE_COMPARER_GREATER: + return int1 > int2; + case PROTOCOLTRACE_COMPARER_LESS_EQ: + return int1 <= int2; + case PROTOCOLTRACE_COMPARER_GREATE_EQ: + return int1 >= int2; + case PROTOCOLTRACE_COMPARER_NOT_EQ: + return int1 != int2; + } + return 0; +} + +ProtocolTrace_Rule_Set_Result DSWaylandProtocolTracePrivate::rulechecker_rule_add(ProtocolTrace_Rule_Checker *rc, ProtocolTrace_Policy_Type policy, const char *rule_string) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rulechecker_rule_add"); + DSLOG_DBG("DSWaylandProtocolTracePriv", "rc->count = %d", rc->count); + + if(rc->count == MAX_RULE) + return PROTOCOLTRACE_RULE_SET_ERR_TOO_MANY_RULES; + + rc->rules[rc->count].tree = protocol_parser_rule_string_parse(rule_string); + if(!rc->rules[rc->count].tree) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "parse error"); + return PROTOCOLTRACE_RULE_SET_ERR_PARSE; + } + + rc->rules[rc->count].policy = policy; + rc->count++; + DSLOG_DBG("DSWaylandProtocolTracePriv", "rc->rules[rc->count].policy = %d", rc->rules[rc->count -1].policy); + DSLOG_DBG("DSWaylandProtocolTracePriv", "rc->count = %d", rc->count -1); + + return PROTOCOLTRACE_RULE_SET_OK; +} + +void DSWaylandProtocolTracePrivate::rulechecker_rule_print(ProtocolTrace_Rule_Checker *rc) +{ + char *reply; + int *len; + ProtocolTrace_Reply_Buffer buffer = {&reply, len}; + int i; + + DSLOG_INF("DSWaylandProtocolTracePriv"," --------------------------[ Protocol Filter Rules ]--------------------------\n"); + DSLOG_INF("DSWaylandProtocolTracePriv"," No Policy Rule\n"); + DSLOG_INF("DSWaylandProtocolTracePriv"," -----------------------------------------------------------------------------\n"); + + for(i =0; i < rc->count; i++) + { + DSLOG_INF("DSWaylandProtocolTracePriv"," %3d %10s \"", i, rc->rules[i].policy == PROTOCOLTRACE_TYPE_ALLOW ? "ALLOW" : "DENY"); + bintree_inorder_traverse(rc->rules[i].tree, rule_print_func, (void*) & buffer); + DSLOG_INF("DSWaylandProtocolTracePriv","\"\n"); + + } +} + +ProtocolTrace_Rule_Set_Result DSWaylandProtocolTracePrivate::rulechecker_rule_remove(ProtocolTrace_Rule_Checker *rc, int index) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rulechecker_rule_remove"); + + if(index <0 || index >= rc->count) + return PROTOCOLTRACE_RULE_SET_ERR_NO_RULE; + + bintree_destroy_tree(rc->rules[index].tree); + rc->count--; + if(index!=rc->count) + memmove(&rc->rules[index], &rc->rules[index+1], sizeof(ProtocolTrace_Rule)*(rc->count - index)); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rulechecker_rule_remove"); + + return PROTOCOLTRACE_RULE_SET_OK; +} + +int DSWaylandProtocolTracePrivate::rulechecker_rule_validate(ProtocolTrace_Rule_Checker *rc, int type, int target_id, const char *name, int pid, char *cmd) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rulechecker_rule_validate"); + + ProtocolTrace_Validate_Args args = {type, target_id, name, pid, cmd}; + ProtocolTrace_Tree_Node *node; + ProtocolTrace_Rule_Node *data; + ProtocolTrace_Policy_Type default_policy = PROTOCOLTRACE_TYPE_DENY; + int i; + + for(i=rc->count-1; i>=0; i--) + { + bintree_postorder_traverse(rc->rules[i].tree, rule_validate_func, &args); + node = (ProtocolTrace_Tree_Node *) bintree_get_head(rc->rules[i].tree); + data = (ProtocolTrace_Rule_Node *) bintree_get_node_data(node); + + if(data->result == PROTOCOLTRACE_RESULT_TRUE) + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rulechecker_rule_validate"); + return rc->rules[i].policy == PROTOCOLTRACE_TYPE_ALLOW; + } + } + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rulechecker_rule_validate"); + return default_policy == PROTOCOLTRACE_TYPE_ALLOW; +} + +int DSWaylandProtocolTracePrivate::rulechecker_string_compare(ProtocolTrace_Comparer comparer, char *str2, char *str1) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rulechecker_string_compare >> "); + + int result = strcasecmp(str2, str1); + + switch (comparer) + { + case PROTOCOLTRACE_COMPARER_EQUAL: + return result == 0; + case PROTOCOLTRACE_COMPARER_LESS: + return result < 0; + case PROTOCOLTRACE_COMPARER_GREATER: + return result > 0; + case PROTOCOLTRACE_COMPARER_LESS_EQ: + return result <= 0; + case PROTOCOLTRACE_COMPARER_GREATE_EQ: + return result >= 0; + case PROTOCOLTRACE_COMPARER_NOT_EQ: + return result != 0; + } + return 0; +} + +const char * DSWaylandProtocolTracePrivate::rulechecker_usage_print() +{ + return + "##########################################################\n" + "### Enlightenment Protocol Log filtering. ###\n" + "##########################################################\n" + "\n" + "-----------------------------------------------------------------\n" + "How to read enlightenment_info protocol messages :\n" + "[timestamp] Server --> Client [PID: [pid]] interface@id.message(arguments..) cmd: CMD\n" + " ex)\n" + "[1476930.145] Server --> Client [PID: 103] wl_touch@10.down(758, 6769315, wl_surface@23, 0, 408.000, 831.000) cmd: /usr/bin/launchpad-loader\n" + " ==> type = event && pid = 103 && cmd = launchpad-loader && iface = wl_touch && msg = up\n" + "[4234234.123] Server <-- Client [PID: 123] wl_seat@32.get_touch(new id wl_touch@22) cmd: /usr/bin/launchpad-loader\n" + " ==> type = request && pid = 123 && cmd = launchpad-loader && iface = wl_seat && msg = get_touch\n" + "-----------------------------------------------------------------\n" + "Usage : enlightenment_info -protocol_rule add [POLICY] [RULE]\n" + " enlightenment_info -protocol_rule remove [INDEX]\n" + " enlightenment_info -protocol_rule file [RULE_FILE]\n" + " enlightenment_info -protocol_rule print\n" + " enlightenment_info -protocol_rule help\n" + " [POLICY] : allow / deny \n" + " [RULE] : C Language-style boolean expression syntax. [VARIABLE] [COMPAROTOR] [VALUE]\n" + " [VARIABLE] : type / iface / msg / cmd(command) / pid\n" + " [COMPARATOR] : & / && / and / | / || / or / = / == / != / > / >= / < / <=\n" + " [VALUE] : string / number \n" + " ex)\n" + " enlightenment_info -protocol_rule add allow \"(type=request) && (iface == wl_pointer and (msg = down or msg = up))\"\n" + " enlightenment_info -protocol_rule add deny cmd!= launch-loader\n" + " enlightenment_info -protocol_rule remove all\n" + " enlightenment_info -protocol_rule remove 3\n" + "\n"; +} + +int DSWaylandProtocolTracePrivate::rule_print_func(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, void *arg) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rule_print_func"); + ProtocolTrace_Reply_Buffer *buffer = (ProtocolTrace_Reply_Buffer *)arg; + char *reply = *buffer->reply; + int *len = buffer->len; + char *operators[] = {"==", "<", ">", "<=", ">=", "!=" }; + ProtocolTrace_Rule_Node *data; + + data = (ProtocolTrace_Rule_Node *)bintree_get_node_data(node); + + if(data->node_type == PROTOCOLTRACE_NODE_TYPE_ALL) + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- ALL"); + else if(data->node_type == PROTOCOLTRACE_NODE_TYPE_AND) + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- AND"); + else if(data->node_type == PROTOCOLTRACE_NODE_TYPE_OR) + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- OR"); + else // data->node_type == PROTOCOLTRACE_NODE_TYPE_DATA + { + if(node == bintree_get_left_child(parent)) + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- ("); + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- %s %s ", data->variable_name, operators[data->comparer]); + + if(data->value_type == PROTOCOLTRACE_DATA_TYPE_INTEGER) + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- %d", data->value.integer); + else + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- %s", data->value.string); + + if(node == bintree_get_right_child(parent)) + DSLOG_INF("DSWaylandProtocolTracePriv", "------------------------------------------------- )"); + } + + *buffer->reply = reply; + DSLOG_DBG("DSWaylandProtocolTracePriv", "buffer->reply = %s", reply); + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rule_print_func"); + return 0; +} + +int DSWaylandProtocolTracePrivate::rule_validate_func(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, void *arg) +{ + DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> rule_validate_func "); + + ProtocolTrace_Validate_Args *args = (ProtocolTrace_Validate_Args *)arg; + ProtocolTrace_Tree_Node *left, *right; + ProtocolTrace_Rule_Node *data, *left_data =nullptr, *right_data = nullptr; + + data = (ProtocolTrace_Rule_Node *)bintree_get_node_data(node); + data->result = PROTOCOLTRACE_RESULT_UNKNOWN; + + if(data->node_type == PROTOCOLTRACE_NODE_TYPE_AND || data->node_type == PROTOCOLTRACE_NODE_TYPE_OR) + { + left = bintree_get_left_child(node); + right = bintree_get_right_child(node); + if(!left || !right) + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Node error"); + return -1; + } + + left_data = (ProtocolTrace_Rule_Node *)bintree_get_node_data(left); + right_data = (ProtocolTrace_Rule_Node *)bintree_get_node_data(right); + } + + if(data->node_type == PROTOCOLTRACE_NODE_TYPE_ALL) + { + data->result = PROTOCOLTRACE_RESULT_TRUE; + } + else if(data->node_type == PROTOCOLTRACE_NODE_TYPE_DATA) + { + char iface[64]; + char *msg = nullptr; + + if(args->name) + msg = ":";//index(args->name, ":"); + if(msg) + { + int min = MIN(sizeof(iface)-1, msg-args->name); + strncpy(iface, args->name, min); + iface[min] = '\0'; + msg++; + } + if(!strcasecmp(data->variable_name, "TYPE")) + { + char *type_string; + if(args->type == 0) + type_string = "REQUEST"; + else if(args->type == 1) + type_string = "EVENT"; + else + { + DSLOG_ERR("DSWaylandProtocolTracePriv", "Invalid type %d", args->type); + return -1; + } + + if(rulechecker_string_compare(data->comparer, data->value.string, type_string)) + data->result = PROTOCOLTRACE_RESULT_TRUE; + else + data->result = PROTOCOLTRACE_RESULT_FALSE; + } + else if(!strcasecmp(data->variable_name, "IFACE")) + { + if(msg && rulechecker_string_compare(data->comparer, data->value.string, iface)) + data->result = PROTOCOLTRACE_RESULT_TRUE; + else + data->result = PROTOCOLTRACE_RESULT_FALSE; + } + else if(!strcasecmp(data->variable_name, "MSG")) + { + if(msg && rulechecker_string_compare(data->comparer, data->value.string, msg)) + data->result = PROTOCOLTRACE_RESULT_TRUE; + else + data->result = PROTOCOLTRACE_RESULT_FALSE; + } + else if(!strcasecmp(data->variable_name, "PID")) + { + if(rulechecker_int_compare(data->comparer, data->value.integer, args->pid)) + data->result = PROTOCOLTRACE_RESULT_TRUE; + else + data->result = PROTOCOLTRACE_RESULT_FALSE; + } + else if(!strcasecmp(data->variable_name, "CMD") || !strcasecmp(data->variable_name, "COMMAND")) + { + if(msg && rulechecker_string_compare(data->comparer, data->value.string, args->cmd)) + data->result = PROTOCOLTRACE_RESULT_TRUE; + else + data->result = PROTOCOLTRACE_RESULT_FALSE; + } + } + else if(data->node_type == PROTOCOLTRACE_NODE_TYPE_AND) + { + if(left_data->result == PROTOCOLTRACE_RESULT_TRUE && right_data->result == PROTOCOLTRACE_RESULT_TRUE) + data->result = PROTOCOLTRACE_RESULT_TRUE; + else + data->result = PROTOCOLTRACE_RESULT_FALSE; + } + else if(data->node_type == PROTOCOLTRACE_NODE_TYPE_OR) + { + if(left_data->result == PROTOCOLTRACE_RESULT_TRUE || right_data->result == PROTOCOLTRACE_RESULT_TRUE) + data->result = PROTOCOLTRACE_RESULT_TRUE; + else + data->result = PROTOCOLTRACE_RESULT_FALSE; + } + else + { + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rule_validate_func "); + return -1; + } + + DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << rule_validate_func "); + return 0; } } // namespace display_server \ No newline at end of file diff --git a/src/DSWaylandServer/DSWaylandProtocolTrace.h b/src/DSWaylandServer/DSWaylandProtocolTrace.h index b9526df..70a5d6c 100644 --- a/src/DSWaylandServer/DSWaylandProtocolTrace.h +++ b/src/DSWaylandServer/DSWaylandProtocolTrace.h @@ -26,6 +26,7 @@ #include #include +#include "DSWaylandCompositor.h" namespace display_server { diff --git a/src/DSWaylandServer/DSWaylandProtocolTracePrivate.h b/src/DSWaylandServer/DSWaylandProtocolTracePrivate.h index d43ed9d..8c22087 100644 --- a/src/DSWaylandServer/DSWaylandProtocolTracePrivate.h +++ b/src/DSWaylandServer/DSWaylandProtocolTracePrivate.h @@ -25,9 +25,199 @@ #define __DS_WAYLAND_PROTOCOL_TRACE_PRIVATE_H__ #include "DSWaylandProtocolTrace.h" +//#include "DSWaylandProtocolTraceStruct.h" +#include +#include +#include +#include + +#define PATH_MAX 255 //tmp 255 + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#define BUF_SNPRINTF(fmt, ARG...) do { \ + str_l = snprintf(str_buff, str_r, fmt, ##ARG); \ + str_buff += str_l; \ + str_r -= str_l; \ +} while(0) + + +/* +#ifndef REPLY + #define REPLY(fmt, ARG...) \ + do { \ + if (reply && len && *len > 0) \ + { \ + int s = snprintf(reply, *len, fmt, ##ARG); \ + reply += s; \ + *len -= s; \ + } \ + } while (0) +#endif +*/ +#define MAX_RULE 64 +#define STRING_MAX 64 namespace display_server { +typedef struct _ProtocolTrace_Tree_Node ProtocolTrace_Tree_Node; +typedef struct _ProtocolTrace_Tree ProtocolTrace_Tree; +typedef struct _ProtocolTrace_Token_Data ProtocolTrace_Token_Data; +typedef struct _ProtocolTrace_Rule_Node ProtocolTrace_Rule_Node; +typedef struct _ProtocolTrace_Rule ProtocolTrace_Rule; +typedef struct _ProtocolTrace_Rule_Checker ProtocolTrace_Rule_Checker; +typedef struct _ProtocolTrace_Protocol_Log ProtocolTrace_Protocol_Log; + +typedef int (*ProtocolTrace_Tree_Traverse_Cb) (ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, void *arg); + +struct _ProtocolTrace_Tree_Node +{ + ProtocolTrace_Tree_Node *left; + ProtocolTrace_Tree_Node *right; +}; + +struct _ProtocolTrace_Tree +{ + int size; + ProtocolTrace_Tree_Node *head; +}; + +typedef enum +{ + PROTOCOLTRACE_TOKEN_UNKNOWN = 0, + PROTOCOLTRACE_TOKEN_L_BR =1, + PROTOCOLTRACE_TOKEN_R_BR =2, + PROTOCOLTRACE_TOKEN_NOT_EQ=3, + PROTOCOLTRACE_TOKEN_EQUAL=4, + PROTOCOLTRACE_TOKEN_LSS_THAN=5, + PROTOCOLTRACE_TOKEN_LSS_EQ =6, + PROTOCOLTRACE_TOKEN_GRT_THAN=7, + PROTOCOLTRACE_TOKEN_GRT_EQ =8, + PROTOCOLTRACE_TOKEN_AND=9, + PROTOCOLTRACE_TOKEN_OR=10, + PROTOCOLTRACE_TOKEN_SPACE=11, + PROTOCOLTRACE_TOKEN_SYMBOL=12, + PROTOCOLTRACE_TOKEN_NUMBER=13, + PROTOCOLTRACE_TOKEN_EOS=14, +} ProtocolTrace_Token; + +struct _ProtocolTrace_Token_Data +{ + const char **string; + ProtocolTrace_Token last_token; + const char *last_symbol; + int symbol_len; +}; +typedef enum +{ + PROTOCOLTRACE_NODE_TYPE_NONE, + PROTOCOLTRACE_NODE_TYPE_AND, + PROTOCOLTRACE_NODE_TYPE_OR, + PROTOCOLTRACE_NODE_TYPE_DATA, + PROTOCOLTRACE_NODE_TYPE_ALL +} ProtocolTrace_Node_Type; + +typedef enum +{ + PROTOCOLTRACE_COMPARER_EQUAL, + PROTOCOLTRACE_COMPARER_LESS, + PROTOCOLTRACE_COMPARER_GREATER, + PROTOCOLTRACE_COMPARER_LESS_EQ, + PROTOCOLTRACE_COMPARER_GREATE_EQ, + PROTOCOLTRACE_COMPARER_NOT_EQ +} ProtocolTrace_Comparer; + +typedef enum +{ + PROTOCOLTRACE_DATA_TYPE_INTEGER, + PROTOCOLTRACE_DATA_TYPE_STRING +} ProtocolTrace_Data_Type; + +typedef enum +{ + PROTOCOLTRACE_RESULT_UNKNOWN, + PROTOCOLTRACE_RESULT_TRUE, + PROTOCOLTRACE_RESULT_FALSE +} ProtocolTrace_Result_Type; + +struct _ProtocolTrace_Rule_Node +{ + ProtocolTrace_Node_Type node_type; + char variable_name[STRING_MAX]; + ProtocolTrace_Comparer comparer; + ProtocolTrace_Data_Type value_type; + + union + { + char string[STRING_MAX]; + int integer; + }value; + + ProtocolTrace_Result_Type result; +}; + +typedef enum +{ + PROTOCOLTRACE_POLICY_TYPE_UNDEFINED, + PROTOCOLTRACE_TYPE_ALLOW, + PROTOCOLTRACE_TYPE_DENY +} ProtocolTrace_Policy_Type; + +struct _ProtocolTrace_Rule +{ + ProtocolTrace_Policy_Type policy; + ProtocolTrace_Tree *tree; +}; + +struct _ProtocolTrace_Rule_Checker +{ + ProtocolTrace_Rule rules[MAX_RULE]; + int count; +}; +typedef enum +{ + PROTOCOLTRACE_RULE_SET_OK, + PROTOCOLTRACE_RULE_SET_ERR_TOO_MANY_RULES, + PROTOCOLTRACE_RULE_SET_ERR_PARSE, + PROTOCOLTRACE_RULE_SET_ERR_NO_RULE + } ProtocolTrace_Rule_Set_Result; +typedef enum{ + PROTOCOL_TYPE_REQUEST, + PROTOCOL_TYPE_EVENT +} ProtocolTrace_Protocol_Type; +struct _ProtocolTrace_Protocol_Log +{ + ProtocolTrace_Protocol_Type type; + int client_pid; + int target_id; + char name[PATH_MAX +1]; + char cmd[PATH_MAX +1]; +}; +struct argument_details { + char type; + int nullable; +}; + +typedef struct +{ + int type; + int target_id; + const char *name; + int pid; + char *cmd; +} ProtocolTrace_Validate_Args; + +typedef struct +{ + char **reply; + int *len; +} ProtocolTrace_Reply_Buffer; class DSWaylandProtocolTracePrivate : public DSObjectPrivate { @@ -40,11 +230,59 @@ public: protected: - void protocol_rule_init(char *rule_path); - void protocol_trace_init(char *trace_path); - void protocol_rule_set(void); - void protocol_rule_file_set(void); + bool protocol_rule_init(char *rule_path); + bool protocol_trace_init(char *trace_path); + + bool protocol_rule_set(const int argc, const char **argv); + bool protocol_rule_file_set(const char *filename); + static bool protocol_rule_validate(ProtocolTrace_Protocol_Log *log); + + void protocol_trace_set(void); + void protocol_trace_unset(void); + +private: + DSWaylandCompositor *__wlCompositor; + char *trace_env_path = nullptr; + + static void wl_protocol_cb_client_destroy(struct wl_listener *listener, void *data); + static void protocol_client_destroy_listener_reg(struct wl_client *client); + static void protocol_trace_func(void *user_data, enum wl_protocol_logger_type direction, const struct wl_protocol_logger_message *message); + + ProtocolTrace_Tree_Node *bintree_create_node(ProtocolTrace_Tree *tree); + ProtocolTrace_Tree *bintree_create_tree(int size); + void bintree_destroy_tree(ProtocolTrace_Tree *tree); + static ProtocolTrace_Tree_Node *bintree_get_head(ProtocolTrace_Tree *tree); + static ProtocolTrace_Tree_Node *bintree_get_left_child(ProtocolTrace_Tree_Node *node); + static void * bintree_get_node_data(ProtocolTrace_Tree_Node *node); + static ProtocolTrace_Tree_Node *bintree_get_right_child(ProtocolTrace_Tree_Node *node); + void bintree_inorder_traverse(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Traverse_Cb func, void *arg); + int bintree_inorder_traverse_recursive(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, ProtocolTrace_Tree_Traverse_Cb func, void *arg); + static void bintree_postorder_traverse(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Traverse_Cb func, void *arg); + static int bintree_postorder_traverse_recursive(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, ProtocolTrace_Tree_Traverse_Cb func, void *arg); + void bintree_remove_node(ProtocolTrace_Tree_Node *node); + void bintree_remove_node_recursive(ProtocolTrace_Tree_Node *node); + void bintree_set_head(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *head); + void bintree_set_left_child(ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *child); + void bintree_set_right_child(ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *child); + ProtocolTrace_Token parser_next_token_get(const char **string); + ProtocolTrace_Tree *protocol_parser_rule_string_parse(const char *string); + ProtocolTrace_Tree_Node *parser_statement_parse(ProtocolTrace_Tree *tree, ProtocolTrace_Token_Data *token); + ProtocolTrace_Tree_Node *parser_token_parse(ProtocolTrace_Tree *tree, ProtocolTrace_Token_Data *token); + void parser_token_process(ProtocolTrace_Token_Data *token); + static void protocol_arguments_merge(char *target, int target_size, int argc, const char **argv); + static char * protocol_cmd_get(char *path); + void rulechecker_destroy(ProtocolTrace_Rule_Checker *rc); + ProtocolTrace_Rule_Checker *rulechecker_init(); + static int rulechecker_int_compare(ProtocolTrace_Comparer comparer, int int2, int int1); + ProtocolTrace_Rule_Set_Result rulechecker_rule_add(_ProtocolTrace_Rule_Checker *rc, ProtocolTrace_Policy_Type policy, const char *rule_string); + void rulechecker_rule_print(ProtocolTrace_Rule_Checker *rc); + ProtocolTrace_Rule_Set_Result rulechecker_rule_remove(ProtocolTrace_Rule_Checker *rc, int index); + static int rulechecker_rule_validate(ProtocolTrace_Rule_Checker *rc, int type, int target_id, const char *name, int pid, char *cmd); + static int rulechecker_string_compare(ProtocolTrace_Comparer comparer, char *str2, char *str1); + const char * rulechecker_usage_print(); + static int rule_print_func(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, void *arg); + static int rule_validate_func(ProtocolTrace_Tree *tree, ProtocolTrace_Tree_Node *node, ProtocolTrace_Tree_Node *parent, void *arg); }; }