#include "DSWaylandProtocolTrace.h"
#include "DSWaylandProtocolTracePrivate.h"
+#include <fcntl.h>
+#include <unistd.h>
namespace display_server
{
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()
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;
}
}
-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<strlen(merge); i++)
+ {
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "ADD :: merge[%d] = %c", i, merge[i]);
+ if(merge[i] == '\"' || merge[i] == '\'')
+ {
+ rule[index++] = ' ';
+ if(index > 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; i<argc -1; i++)
+ {
+ remove_idx = argv[i+1];
+ if(!strcasecmp(remove_idx, "all"))
+ {
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "REMOVE :: all");
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "REMOVE :: (before destroy) rc = %d", rc->count);
+ 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; i<message->arguments_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<argc; i++)
+ {
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "argv[i] = %s", argv[i]);
+ len = snprintf(target, target_size, "%s", argv[i]);
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "len = %d", len);
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "target = %s", target);
+ target += len;
+ target_size -= len;
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "target + len = %s", target);
+
+ if(i!=argc-1)
+ {
+ *(target++) = ' ';
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "target = %s", target);
+ target_size--;
+ }
+ }
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "[last]target = %s", target);
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "OUT << protocol_arguments_merge");
+}
+
+char * DSWaylandProtocolTracePrivate::protocol_cmd_get(char *path)
+{
+ DSLOG_DBG("DSWaylandProtocolTracePriv", "IN >> 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