add code for TraceProtocol 61/242761/1
authordyamy-lee <dyamy.lee@samsung.com>
Thu, 20 Aug 2020 03:49:43 +0000 (12:49 +0900)
committerSung-Jin Park <sj76.park@samsung.com>
Tue, 1 Sep 2020 01:29:23 +0000 (10:29 +0900)
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

src/DSWaylandServer/DSWaylandProtocolTrace.cpp
src/DSWaylandServer/DSWaylandProtocolTrace.h
src/DSWaylandServer/DSWaylandProtocolTracePrivate.h

index 0f8c9a6..fe89016 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "DSWaylandProtocolTrace.h"
 #include "DSWaylandProtocolTracePrivate.h"
+#include <fcntl.h>
+#include <unistd.h>
 
 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<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
index b9526df..70a5d6c 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <DSObject.h>
 #include <DSCore.h>
+#include "DSWaylandCompositor.h"
 
 namespace display_server
 {
index d43ed9d..8c22087 100644 (file)
 #define __DS_WAYLAND_PROTOCOL_TRACE_PRIVATE_H__
 
 #include "DSWaylandProtocolTrace.h"
+//#include "DSWaylandProtocolTraceStruct.h"
+#include <wayland-server.h>
+#include <wayland-server-core.h>
+#include <wayland-util.h>
+#include <cstring>
+
+#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);
 };
 
 }