#include "frpc_proxy.h"
#include "../mqtt_emms2/mqtt_emms2.h"
#include "string.h"
#include "tcp_server.h"
#include "../proto_forward.h"
#include "frpc_config.h"
#include <fcntl.h>
#include <stdatomic.h>
#include <stdio.h>
#include <string.h>
#include <sys/syslog.h>
#include <unistd.h>
#include <sys/file.h>

extern proto_forward_t* get_proto_forward_var(void);

static int frpc_admin_port = 7400;

frpc_server_t*  head            = NULL;
pthread_mutex_t frpc_list_mutex = PTHREAD_MUTEX_INITIALIZER;

static int frpc_cfg_init(frpc_server_t* frpc_cfg, cJSON* json, char* dev_no)
{
    if (frpc_cfg == NULL || json == NULL)
    {
        return -1;
    }

    cJSON*      obj = NULL;
    frpc_cfg_t* cfg = &frpc_cfg->frpc_cfg;
    memset(cfg, 0, sizeof(frpc_cfg_t));

    obj = cJSON_GetObjectItem(json, "server_addr");
    if (obj && obj->valuestring && obj->valuestring[0])
        local_strlcpy(cfg->server_addr, obj->valuestring, sizeof(cfg->server_addr));
    else
        local_strlcpy(cfg->server_addr, DEFINE_SERVER_ADDR, sizeof(cfg->server_addr));

    obj = cJSON_GetObjectItem(json, "server_port");
    if (obj && obj->valueint)
        cfg->server_port = obj->valueint;
    else
        cfg->server_port = DEFINE_SERVER_PORT;

    obj = cJSON_GetObjectItem(json, "privilege_token");
    if (obj && obj->valuestring && obj->valuestring[0])
        local_strlcpy(cfg->token, obj->valuestring, sizeof(cfg->token));
    else
        local_strlcpy(cfg->token, DEFINE_TOKEN, sizeof(cfg->token));

    get_board_sn(cfg->user);
    // private
    obj = cJSON_GetObjectItem(json, "tls_enable");
    if (obj)
        cfg->tls_enable = obj->valueint;
    else
        cfg->tls_enable = 1;

    obj = cJSON_GetObjectItem(json, "name");
    if (obj && obj->valuestring && obj->valuestring[0])
        local_strlcpy(cfg->name, obj->valuestring, sizeof(cfg->name));
    else if(strlen(dev_no) > 0)
        local_strlcpy(cfg->name, dev_no, sizeof(cfg->name));
    else
        return -1;

    obj = cJSON_GetObjectItem(json, "frpc_type");
    if (obj && obj->valuestring && obj->valuestring[0] && strcmp(obj->valuestring, "udp") == 0)
        cfg->type = FRPC_TYPE_UDP;
    else
        cfg->type = FRPC_TYPE_TCP;

    obj = cJSON_GetObjectItem(json, "local_ip");
    if (obj && obj->valuestring && obj->valuestring[0])
        local_strlcpy(cfg->local_ip, obj->valuestring, sizeof(cfg->local_ip));
    else
        local_strlcpy(cfg->local_ip, DEFINE_LOCAL_IP, sizeof(cfg->local_ip));

    obj = cJSON_GetObjectItem(json, "local_port");
    if (obj && obj->valueint)
        cfg->local_port = obj->valueint;
    else
        cfg->local_port = 0;

    obj = cJSON_GetObjectItem(json, "remote_port");
    if (obj && obj->valueint)
        cfg->remote_port = obj->valueint;
    else
        cfg->remote_port = 0;

    obj = cJSON_GetObjectItem(json, "use_compress");
    if (obj)
        cfg->use_compress = obj->valueint;
    else
        cfg->use_compress = 1;

    return 0;
}

static int destroy_frpc_cfg(frpc_server_t* cfg)
{
    if (cfg == NULL) return -1;
    if (cfg->trans) tcp_server_task_destroy(cfg->trans);
    free(cfg);
    return 0;
}

int frpc_set_cfg_file(frpc_cfg_t* cfg, char* dev_no, int tcp_port, char* cfg_path)
{
    if (cfg == NULL) return -1;

    FILE* fp = fopen(cfg_path, "w+");
    if (fp == NULL)
    {
        char tmp[256];
        snprintf(tmp, sizeof(tmp), "%s", cfg_path);
        for (char* p = strchr(tmp + 1, '/'); p; p = strchr(p + 1, '/'))
        {
            *p = '\0';
            mkdir(tmp, 0777);
            *p = '/';
        }
        fp = fopen(cfg_path, "w+");
    }
    if (fp == NULL)
    {
        return -1;
    }

    int len = fprintf(fp,
                      "[common]\nserver_addr = %s\nserver_port = %d\nprivilege_token = %s\nadmin_addr = %s\nadmin_port = %d\nadmin_user = %s\nadmin_pwd = %s\nuser = %s\ntls_enable = %s\n[%s]\ntype = %s\nlocal_ip = %s\nlocal_port = %d\nremote_port = %d\nuse_compress = %d\n",
                      cfg->server_addr,
                      cfg->server_port,
                      cfg->token,
                      DEFINE_ADMIN_ADDR,
                      ++frpc_admin_port,
                      DEFINE_ADMIN_USER,
                      DEFINE_ADMIN_PWD,
                      cfg->user,
                      cfg->tls_enable ? "true" : "false",
                      cfg->name,
                      cfg->type == FRPC_TYPE_UDP ? "udp" : "tcp",
                      cfg->local_ip,
                      cfg->local_port == 0 ? tcp_port : cfg->local_port,
                      cfg->remote_port,
                      cfg->use_compress);

    if (frpc_admin_port > 30000)
    {
        frpc_admin_port = 7400;
    }
    fflush(fp);
    fclose(fp);
    return len > 0 ? 0 : -1;
}

static int frpc_server_get_channel_cfg(frpc_server_t* cfg, cJSON* channel)
{
    if (channel == NULL || cfg == NULL) return -1;
    proto_forward_t* pro_pr  = get_proto_forward_var();
    channel_t*       chan_pr = NULL;
    device_t*        dev_pr  = NULL;


    cJSON* dev_no = cJSON_GetObjectItem(channel, "dev_no");
    if (dev_no == NULL || dev_no->valuestring == NULL || dev_no->valuestring[0] == '\0') return -1;
    local_strlcpy(cfg->dev_no, dev_no->valuestring, sizeof(cfg->dev_no));

    if (find_dev_channel_pr_by_dev_no(pro_pr, cfg->dev_no, &chan_pr, &dev_pr) < 0)
    {
        ems_syslog(LOG_ERR, "Can not find dev_no[%s] channel!", cfg->dev_no);
        return -1;
    }
    cfg->trans->chan_pr = chan_pr;

    if (chan_pr->proxy_state != PROXY_MODE_NONE)
    {
        ems_syslog(LOG_ERR, "Dev_no[%s] channel proxy state error!", cfg->dev_no);
        return -1;
    }

    cJSON* timeout = cJSON_GetObjectItem(channel, "timeout");
    if (timeout == NULL || timeout->valueint <= 200)
        cfg->trans->timeout = CHANNEL_READ_TIMEOUT;
    else
        cfg->trans->timeout = timeout->valueint;

    cJSON* keep_alive = cJSON_GetObjectItem(channel, "keep_alive");
    if (keep_alive == NULL || keep_alive->valueint <= 0)
        cfg->trans->keepalive = PROXY_SERVER_KEEPALIVE;
    else
        cfg->trans->keepalive = keep_alive->valueint;

    chan_pr->proxy_state = cfg->mode;
    return 0;
}


static frpc_server_t* create_frpc_proxy_cfg(cJSON* info)
{
    if (info == NULL) return NULL;

    frpc_server_t* cfg = (frpc_server_t*)malloc(sizeof(frpc_server_t));
    if (cfg == NULL) return NULL;
    memset(cfg, 0, sizeof(frpc_server_t));

    cfg->trans = malloc(sizeof(tcp_trans_t));
    if (cfg->trans == NULL) goto ERROR;
    memset(cfg->trans, 0, sizeof(tcp_trans_t));

    cJSON* obj = cJSON_GetObjectItem(info, "protocol");
    if (obj == NULL || obj->valuestring == NULL || obj->valuestring[0] == '\0') goto ERROR;
    if (strncmp(obj->valuestring, "stream", 6) == 0)
    {
        cfg->trans->mode = PROXY_MODE_STREAM;
        cfg->mode        = PROXY_MODE_STREAM;
    }
    else if (strncmp(obj->valuestring, "frame", 5) == 0)
    {
        cfg->trans->mode = PROXY_MODE_FRAME;
        cfg->mode        = PROXY_MODE_FRAME;
    }
    else if (strncmp(obj->valuestring, "otherport", 9) == 0)
    {
        cfg->trans->mode = PROXY_MODE_OTHERPORT;
        cfg->mode        = PROXY_MODE_OTHERPORT;
    }
    else if (strncmp(obj->valuestring, "tcp2rtu", 7) == 0)
    {
        cfg->trans->mode = PROXY_MODE_TCP2RTU;
        cfg->mode        = PROXY_MODE_TCP2RTU;
    }
    else
    {
        ems_syslog(LOG_ERR, "Frp Proxy: unknow mode, %s", obj->valuestring);
        goto ERROR;
    }

    cfg->start = time(0);
    obj        = cJSON_GetObjectItem(info, "duration");
    if (obj == NULL || obj->valueint <= 0)
        cfg->stop = cfg->start + PROXY_SERVER_MAX_TIME;
    else
        cfg->stop = cfg->start + obj->valueint * 60;

    if (cfg->mode == PROXY_MODE_STREAM || cfg->mode == PROXY_MODE_FRAME || cfg->mode == PROXY_MODE_TCP2RTU)
    {
        obj = cJSON_GetObjectItem(info, "channel");
        if (obj == NULL || frpc_server_get_channel_cfg(cfg, obj) < 0)
        {
            goto ERROR;
        }
    }
    else if (cfg->mode == PROXY_MODE_OTHERPORT)
    {
        obj = cJSON_GetObjectItem(info, "channel");
        if (obj != NULL)
        {
            if(frpc_server_get_channel_cfg(cfg, obj) < 0)
            {
                ems_syslog(LOG_NOTICE, "Frp Proxy: in PROXY_MODE_OTHERPORT mode, Get channel cfg error!");
            }
        }
    }
    
    obj = cJSON_GetObjectItem(info, "frpc");
    if (obj == NULL) goto ERROR;
    if (frpc_cfg_init(cfg, obj, cfg->dev_no) < 0) goto ERROR;

    cfg->trans->local_ip = cfg->frpc_cfg.local_ip;
    cfg->trans->local_port = cfg->frpc_cfg.local_port;
    cfg->trans->local_type = cfg->frpc_cfg.type;

    snprintf(cfg->ini_path, sizeof(cfg->ini_path), "%s/%s/%s", FRPC_CONFIG_DIR, cfg->frpc_cfg.name, FRPC_INI_FILE_NAME);
    snprintf(cfg->pid_path, sizeof(cfg->pid_path), "%s/%s/%s", FRPC_CONFIG_DIR, cfg->frpc_cfg.name, FRPC_PID_FILE_NAME);
    snprintf(cfg->log_path, sizeof(cfg->log_path), "%s/%s/%s", FRPC_CONFIG_DIR, cfg->frpc_cfg.name, FRPC_LOG_FILE_NAME);
    snprintf(cfg->info_path, sizeof(cfg->info_path), "%s/%s/%s", FRPC_CONFIG_DIR, cfg->frpc_cfg.name, FRPC_INFO_FILE_NAME);
    // 日志文件
    FILE* fp = fopen(cfg->log_path, "w+");
    if (fp == NULL)
    {
        char tmp[256];
        snprintf(tmp, sizeof(tmp), "%s", cfg->log_path);
        for (char* p = strchr(tmp + 1, '/'); p; p = strchr(p + 1, '/'))
        {
            *p = '\0';
            mkdir(tmp, 0777);
            *p = '/';
        }
        fp = fopen(cfg->log_path, "w+");
    }
    if (fp != NULL)
    {
        cfg->trans->log_fp = fp;
    }
    return cfg;
ERROR:
    if (cfg != NULL) destroy_frpc_cfg(cfg);
    return NULL;
}

static int notify_the_frpc_process(frpc_server_t* cfg, time_t stop)
{
    // 写入配置文件
    if (cfg == NULL) return -1;
    char info[256] = {0};
    int  len       = snprintf(info, sizeof(info), "{\"name\":\"%s\", \"stop\":%lu}\n", cfg->frpc_cfg.name, stop);
    cfg->last      = time(0);
    int ret        = 0;
    int fd  = open(FRPC_CONFIG_FIFO, O_WRONLY | O_APPEND | O_CREAT, 0666);
    if (fd < 0)
    {
        char tmp[256];
        snprintf(tmp, sizeof(tmp), "%s", FRPC_CONFIG_FIFO);
        for (char* p = strchr(tmp + 1, '/'); p; p = strchr(p + 1, '/'))
        {
            *p = '\0';
            mkdir(tmp, 0777);
            *p = '/';
        }
        fd = open(FRPC_CONFIG_FIFO, O_WRONLY | O_CREAT, 0666);
    }
    if (fd > 0)
    {
        flock(fd, LOCK_EX); // 获取排他锁
        ret = write(fd, info, len);
        flock(fd, LOCK_UN); // 释放锁
        close(fd);
    }

    return ret > 0 ? 0 : -1;
}

static int frpc_proxy_monitor_start();
static int add_frpc_server_to_list(frpc_server_t* cfg)
{
    pthread_mutex_lock(&frpc_list_mutex);
    if (head == NULL)
    {
        head = cfg;
        frpc_proxy_monitor_start();
    }
    else
    {
        frpc_server_t* tmp = head;
        while (tmp->next != NULL)
        {
            tmp = tmp->next;
        }
        tmp->next = cfg;
    }
    pthread_mutex_unlock(&frpc_list_mutex);
    return 0;
}

extern int mqtt_publish_message(const mqtt_emms2_var_t* var, char* pub_topic, char* data, int data_len);
static int frpc_porxy_mqtt_answer(mqtt_emms2_var_t* var, int result, int seq, cJSON* info)
{
    const int size    = 1024;
    char*     payload = malloc(size);
    int       len     = snprintf(payload,
                       size,
                       "{\"funcId\":\"ProxyFrpc\", \"lcSN\":\"%s\", \"seq\" : %d, \"result\":%d",
                       var->topic_sn,
                       seq,
                       result);
    if (info != NULL)
    {
        char* tmp = cJSON_PrintUnformatted(info);
        len += snprintf(payload + len, size - len, ", \"info\":%s", tmp);
        free(tmp);
    }
    len += snprintf(payload + len, size - len, "}");
    char* topic = malloc(512);
    snprintf(topic, 512, "emms2/SetResp/%s/ProxyFrpc", var->topic_sn);
    int ret = mqtt_publish_message(var, topic, payload, len);
    free(topic);
    free(payload);
    return ret;
}

static int frpc_proxy_mqtt_report_errcode(mqtt_emms2_var_t* var, int seq, int errcode)
{
    const int size    = 512;
    char*     payload = malloc(size);
    int       len     = snprintf(payload,
                       size,
                       "{\"funcId\":\"ProxyFrpc\", \"lcSN\":\"%s\", \"seq\" : %d, \"time\" : %ld, \"info\":{\"code\": %d}}",
                       var->topic_sn,
                       seq,
                       time(NULL),
                       errcode);

    char* topic = malloc(512);
    snprintf(topic, 512, "emms2/LcPost/%s/ProxyFrpc", var->topic_sn);
    int ret = mqtt_publish_message(var, topic, payload, len);
    free(topic);
    free(payload);
    return ret;
}

static int frpc_porxy_start(mqtt_emms2_var_t* var, cJSON* info, int seq)
{
    if (var == NULL || info == NULL) return -1;

    frpc_server_t* cfg = create_frpc_proxy_cfg(info);
    if(cfg == NULL) goto ERROR;
    cfg->var           = var;
    cfg->sep           = seq;
    if (tcp_server_task_start(cfg->trans) < 0) goto ERROR;
    if (frpc_set_cfg_file(&cfg->frpc_cfg, cfg->dev_no, cfg->trans->port, cfg->ini_path) < 0) goto ERROR;
    if (notify_the_frpc_process(cfg, cfg->start + PROXY_SERVER_KEEPALIVE) < 0) goto ERROR;
    if (add_frpc_server_to_list(cfg) < 0) goto ERROR;
    return 0;

ERROR:
    destroy_frpc_cfg(cfg);
    frpc_porxy_mqtt_answer(var, -1, seq, NULL);
    return -1;
}

static int frpc_porxy_stop(mqtt_emms2_var_t* var, cJSON* info, int seq)
{
    if (var == NULL || info == NULL) return -1;
    cJSON* dev = cJSON_GetObjectItem(info, "dev_no");
    if (dev == NULL || dev->valuestring == NULL || dev->valuestring[0] == '\0') return -1;
    pthread_mutex_lock(&frpc_list_mutex);
    frpc_server_t* tmp    = head;
    int            finded = 0;
    while (tmp != NULL)
    {
        if (strcmp(tmp->dev_no, dev->valuestring) == 0)
        {
            atomic_store(&tmp->state, FRPC_SERVER_STOPING);
            finded = 1;
            break;
        }
        tmp = tmp->next;
    }
    pthread_mutex_unlock(&frpc_list_mutex);
    frpc_porxy_mqtt_answer(var, finded == 1 ? 0 : -1, seq, NULL);
    return 0;
}

static int frpc_porxy_relet(mqtt_emms2_var_t* var, cJSON* info, int seq)
{
    if (var == NULL || info == NULL) return -1;

    cJSON* dev = cJSON_GetObjectItem(info, "dev_no");
    if (dev == NULL || dev->valuestring == NULL || dev->valuestring[0] == '\0') return -1;
    cJSON* duration = cJSON_GetObjectItem(info, "duration");
    if (duration == NULL || duration->valueint <= 0) return -1;

    pthread_mutex_lock(&frpc_list_mutex);
    frpc_server_t* tmp    = head;
    int            finded = 0;
    while (tmp != NULL)
    {
        if (strcmp(tmp->dev_no, dev->valuestring) == 0)
        {
            time_t stop = time(NULL) + duration->valueint * 60;
            if (stop > tmp->stop)
            {
                tmp->stop = stop;
                notify_the_frpc_process(tmp, stop);
            }
            finded = 1;
            break;
        }
        tmp = tmp->next;
    }
    pthread_mutex_unlock(&frpc_list_mutex);
    frpc_porxy_mqtt_answer(var, finded == 1 ? 0 : -1, seq, NULL);
    return 0;
}

int frpc_proxy_cmd(mqtt_emms2_var_t* var, cJSON* root, int seq)
{
    if (var == NULL || root == NULL) return -1;

    cJSON* cmd = cJSON_GetObjectItem(root, "cmd");
    if (cmd == NULL) return -1;

    if (strcmp(cmd->valuestring, "start") == 0)
    {
        cJSON* info = cJSON_GetObjectItem(root, "info");
        if (info == NULL) return -1;
        frpc_porxy_start(var, info, seq);
    }
    else if (strcmp(cmd->valuestring, "stop") == 0)
    {
        cJSON* info = cJSON_GetObjectItem(root, "info");
        if (info == NULL) return -1;
        frpc_porxy_stop(var, info, seq);
    }
    else if (strcmp(cmd->valuestring, "relet") == 0)
    {
        cJSON* info = cJSON_GetObjectItem(root, "info");
        if (info == NULL) return -1;
        frpc_porxy_relet(var, info, seq);
    }
    else
    {
        return -1;
    }

    return 0;
}

int get_frpc_server_info(frpc_server_t* tmp)
{
    char*  info_file = tmp->info_path;
    char*  info      = NULL;
    cJSON* root      = NULL;
    int    ret       = -1;
    if (access(info_file, F_OK) < 0)
    {
        ems_syslog(LOG_NOTICE, "Can not find dev_no[%s] frpc info file!", tmp->dev_no);
        goto END;
    }
    info = read_file_data(info_file);
    if (info == NULL)
    {
        ems_syslog(LOG_NOTICE, "Can not read dev_no[%s] frpc info file!", tmp->dev_no);
        goto END;
    }
    root = cJSON_Parse(info);
    if (root == NULL)
    {
        ems_syslog(LOG_NOTICE, "Can not parse dev_no[%s] frpc info file!", tmp->dev_no);
        goto END;
    }

    cJSON* status     = cJSON_GetObjectItem(root, "status");
    cJSON* remoteIp   = cJSON_GetObjectItem(root, "remoteIp");
    cJSON* remotePort = cJSON_GetObjectItem(root, "remotePort");
    cJSON* localIp    = cJSON_GetObjectItem(root, "localIp");
    cJSON* localPort  = cJSON_GetObjectItem(root, "localPort");
    if (status == NULL || remoteIp == NULL || remotePort == NULL || localIp == NULL || localPort == NULL)
    {
        ems_syslog(LOG_NOTICE, "Can not parse dev_no[%s] frpc info file with info!", tmp->dev_no);
        goto END;
    }

    local_strlcpy(tmp->info.status, status->valuestring, sizeof(tmp->info.status));
    local_strlcpy(tmp->info.remote_ip, remoteIp->valuestring, sizeof(tmp->info.remote_ip));
    tmp->info.remote_port = remotePort->valueint;
    local_strlcpy(tmp->info.local_ip, localIp->valuestring, sizeof(tmp->info.local_ip));
    tmp->info.local_port = localPort->valueint;
    ret                  = 0;

END:
    if (root) cJSON_Delete(root);
    if (info) free(info);
    return ret;
}
static int frpc_proxy_server_stop(frpc_server_t* cfg)
{
    tcp_server_task_stop(cfg->trans);
    return 0;
}

void* frpc_proxy_monitor(void* arg)
{
    while (head != NULL)
    {
        sleep(1);
        pthread_mutex_lock(&frpc_list_mutex);
        frpc_server_t* tmp = head;
        time_t         now = time(NULL);
        while (tmp != NULL)
        {
            if (atomic_load(&tmp->state) == FRPC_SERVER_STARTED)
            {
                get_frpc_server_info(tmp);
                if (strcmp(tmp->info.status, "running") == 0)
                {
                    atomic_store(&tmp->state, FRPC_SERVER_RUNNING);
                    cJSON* info = cJSON_CreateObject();
                    cJSON_AddStringToObject(info, "host", strdup(tmp->info.remote_ip));
                    cJSON_AddNumberToObject(info, "port", tmp->info.remote_port);
                    frpc_porxy_mqtt_answer(tmp->var, 0, tmp->sep, info);
                    cJSON_Delete(info);
                }
                else if (now > tmp->start + FRPC_INFO_START_TIME)
                {
                    frpc_porxy_mqtt_answer(tmp->var, -1, tmp->sep, NULL);
                    atomic_store(&tmp->state, FRPC_SERVER_STOPING);
                }
            }
            if (atomic_load(&tmp->state) == FRPC_SERVER_RUNNING)
            {
                if (now > tmp->stop)
                {
                    frpc_proxy_mqtt_report_errcode(tmp->var, tmp->sep, FRPC_SERVER_ERROR_TIMEOUT);
                    atomic_store(&tmp->state, FRPC_SERVER_STOPING);
                }
                else if (atomic_load(&tmp->trans->state) == FRPC_SERVER_STOPED)
                {
                    frpc_proxy_mqtt_report_errcode(tmp->var, tmp->sep, FRPC_SERVER_ERROR_DEVSTOP);
                    atomic_store(&tmp->state, FRPC_SERVER_STOPING);
                }
                else
                {
                    if (now - tmp->last > PROXY_SERVER_KEEPALIVE / 2)
                    {
                        int stop = now + PROXY_SERVER_KEEPALIVE;
                        notify_the_frpc_process(tmp, stop > tmp->stop ? tmp->stop : stop);
                        tmp->last = now;
                    }
                }
            }
            if (atomic_load(&tmp->state) == FRPC_SERVER_STOPING)
            {
                notify_the_frpc_process(tmp, now);
                frpc_proxy_server_stop(tmp);
                atomic_store(&tmp->state, FRPC_SERVER_STOPED);
            }
            if (atomic_load(&tmp->state) == FRPC_SERVER_STOPED)
            {
                frpc_server_t* tmp_next = tmp->next;
                destroy_frpc_cfg(tmp);
                if (tmp == head)
                {
                    head = tmp_next;
                }
                else
                {
                    frpc_server_t* tmp_prev = head;
                    while (tmp_prev->next != tmp)
                    {
                        tmp_prev = tmp_prev->next;
                    }
                    tmp_prev->next = tmp_next;
                }
                tmp = tmp_next;
            }
            else
            {
                tmp = tmp->next;
            }
        }
        pthread_mutex_unlock(&frpc_list_mutex);
    }

    return NULL;
}

static int frpc_proxy_monitor_start()
{
    pthread_t tid = -1;
    if (pthread_create(&tid, NULL, frpc_proxy_monitor, NULL) != 0)
    {
        tid = -1;
    }
    else
    {
        pthread_setname_np(tid, "proxy_server_monitor");
    }
    return tid;
}
