void thread_bufferevent_cb(struct bufferevent *bev, short events, void *ptr)
{
    P_TRANS_ITEM p_trans = (P_TRANS_ITEM)ptr; 

    struct event_base *base = bufferevent_get_base(bev);
    int loop_terminate_flag = 0;

    //只有使用bufferevent_socket_connect进行的连接才会得到CONNECTED的事件
    if (events & BEV_EVENT_CONNECTED) 
    {
        st_d_print("GOT BEV_EVENT_CONNECTED event! ");
    } 
    else if (events & BEV_EVENT_ERROR) 
    {
        st_d_error("GOT BEV_EVENT_ERROR event[%d]! ", p_trans->usr_lport); 

        ss_free_trans(p_trans->p_activ_item, p_trans);
    } 
    else if (events & BEV_EVENT_EOF) 
    {
        st_d_print("GOT BEV_EVENT_EOF event[%d]! ", p_trans->usr_lport); 

        // 实际传输端结束,那么只针对这个传输,把对端的连接断开,
        // 由于TCP连接,那么对端的be_usr_srv和be_daemon_srv也会收到BEV_EVENT_EOF消息
        ss_free_trans(p_trans->p_activ_item, p_trans);

    }
    else if (events & BEV_EVENT_TIMEOUT) 
    {
        st_d_print("GOT BEV_EVENT_TIMEOUT event[%d]! ", p_trans->usr_lport); 

        ss_free_trans(p_trans->p_activ_item, p_trans);
    } 

    if (loop_terminate_flag)
    {
        bufferevent_free(bev);
        event_base_loopexit(base, NULL);
    }

    return;
}
Beispiel #2
0
BOOL SetEvent( HANDLE hEvent)
{
    P_ST_WINSYNC_T p_event = (P_ST_WINSYNC_T)hEvent;
    int ret = 0;

    if (p_event->type == SYNC_EVENT)
    {
        //如果上次的事件还没有被消费掉,就忽略本次的发送
        //是否要重发,可以调用程序根据结果来判断

        if (strlen(p_event->sync_name))  //inter-process
        {
            sem_getvalue((sem_t *)(p_event->p_sem), &ret);
            if (ret > 0)
            {
                st_d_print("Producer Fast, Dismiss it!\n");
                return EBUSY;
            }
            return sem_post((sem_t *)(p_event->p_sem)); 
        }
        else    // intra-process
        {
            sem_getvalue((sem_t *)(&p_event->sem), &ret);
            if (ret > 0)
            {
                st_d_print("Producer Fast, Dismiss it!\n");
                return EBUSY;
            }
            return sem_post((sem_t *)(&p_event->sem));
        }
    }
    else
    {
        SYS_ABORT("WIN SYNC error For Event with %d\n", p_event->type);
    }

	return TRUE;
}
/**
 * 读取事件,主要进行数据转发 
 *  
 * 这里命令字段和数据字段分开处理,命令是自己解析,而数据需要转发,需要 
 * 为数据流程进行优化 
 */
void thread_bufferread_cb(struct bufferevent *bev, void *ptr)
{
    P_TRANS_ITEM p_trans = (P_TRANS_ITEM)ptr; 

    struct evbuffer *input = bufferevent_get_input(bev);
    struct evbuffer *output = bufferevent_get_output(bev);

    if (bev == p_trans->bev_u && p_trans->bev_d) 
    {
        st_d_print("转发数据包USR->DAEMON");
        bufferevent_write_buffer(p_trans->bev_d, bufferevent_get_input(bev));
    }
    else if (bev == p_trans->bev_d && p_trans->bev_u) 
    {
        st_d_print("转发数据包DAEMON->USR");
        bufferevent_write_buffer(p_trans->bev_u, bufferevent_get_input(bev));
    }
    else
    {
        SYS_ABORT("WRRRRRR!");
    }

    return;
}
Beispiel #4
0
int mysql_conns_capacity(P_MYSQL_CONNS p_conns)
{
    int i = 0;
    int free_c = 0;
    int total_c = 0;

    if (!p_conns || !p_conns->len)
        return 0;


    pthread_mutex_lock(&p_conns->mutex);
    for (i=0; i<p_conns->len; ++i)
    {
        if (p_conns->conns[i].free == 1)
            ++ free_c;
        ++ total_c;
    }
    pthread_mutex_unlock(&p_conns->mutex);

    st_d_print("Free:%d, Total:%d\n", free_c, total_c);
    return free_c;
}
Beispiel #5
0
/**
 * 由于自己封装了结构,方便调用,所以有fork亲属关系的进程,不再
 * 让其继承mutex结构,需要创建使用命名Mutex
 */
HANDLE CreateMutex( void* lpMutexAttributes,
                BOOL bInitialOwner, const char* lpName)
{
    P_ST_WINSYNC_T p_mutex = NULL;

    p_mutex = (P_ST_WINSYNC_T)malloc(sizeof(ST_WINSYNC_T));
    if (!p_mutex)
        return NULL;

    memset(p_mutex, 0, sizeof(ST_WINSYNC_T));
    p_mutex->type = SYNC_MUTEX;

    if ( lpName) // Inter-Process
    {
        strncpy(p_mutex->sync_name, lpName, PATH_MAX);
        sem_unlink(lpName); // Just for safe
        //bInitialOwner
        p_mutex->p_sem = sem_open(p_mutex->sync_name, O_CREAT | O_EXCL, 0644, bInitialOwner); 
        if (p_mutex->p_sem == SEM_FAILED)
        {
            st_d_print("Create Mutex: %s failed!\n", p_mutex->sync_name);
            free(p_mutex);
            return NULL;
        }
    }
    else        // Intra-Process
    {
        p_mutex->sync_name[0] = '\0';
        if( sem_init((sem_t *)(&p_mutex->sem), 1/*pshared for forked dismiss*/, 1) != 0)
        {
            st_print("semaphore initilization");
            return NULL;
        }
    }

    return p_mutex;
}
Beispiel #6
0
int main(int argc, char* argv[])
{

#if 1
    // For debug with segment fault
    struct sigaction sa;
    sa.sa_handler = backtrace_info;
    sigaction(SIGSEGV, &sa, NULL);

    // ignore SIGPIPE
    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);
    signal(SIGABRT, SIG_IGN);

#endif

    int opt_g = 0;
    memset(&cltopt, 0, sizeof(CLT_OPT));

    cltopt.C_TYPE = C_USR;
    while( (opt_g = getopt(argc, argv, "Dh")) != -1 )
    {
        switch(opt_g)
        {
            case 'D':
                cltopt.C_TYPE = C_DAEMON;
                break;
            case 'h':
            default:
                usage();
                exit(EXIT_SUCCESS);
        }
    }

    if(load_settings_client(&cltopt) == RET_NO)
    {
        st_d_error("加载配置文件settings.json出错!");
        exit(EXIT_FAILURE);
    }

    OpenSSL_add_ssl_algorithms();
    SSL_load_error_strings();
    SSL_library_init();     //SSL_library_init() always returns "1"

    //int sd_id128_from_string(const char *s, sd_id128_t *ret);
    sd_id128_get_machine(&cltopt.mach_uuid);
    gethostname(cltopt.hostname, sizeof(cltopt.hostname)); 
    st_d_print("CURRENT MACH_ID:%s, HOSTNAME:%s", SD_ID128_CONST_STR(cltopt.mach_uuid), 
               cltopt.hostname);

    if (cltopt.C_TYPE == C_DAEMON) 
    {
        cltopt.session_uuid = cltopt.mach_uuid;
        st_d_print("PLEASE REMEMEBER SET MACH_ID FOR USER TYPE!");
    }

    dump_clt_opts(&cltopt);

    /*带配置产生event_base对象*/
    struct event_config *cfg;
    cfg = event_config_new();
    event_config_avoid_method(cfg, "select");   //避免使用select
    event_config_require_features(cfg, EV_FEATURE_ET);  //使用边沿触发类型
    base = event_base_new_with_config(cfg);
    event_config_free(cfg);
    st_d_print("当前复用Event模式: %s", event_base_get_method(base)); // epoll

    /*连接服务器*/
    int srv_fd = socket(AF_INET, SOCK_STREAM, 0);
    unsigned int optval = 1;
    setsockopt(srv_fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));//禁用NAGLE算法

    if(sc_connect_srv(srv_fd) != RET_YES) 
    {
        SYS_ABORT("连接服务器失败!");
    }

    if(cltopt.C_TYPE == C_DAEMON) 
    {
        if (sc_daemon_init_srv(srv_fd) != RET_YES) 
            SYS_ABORT("(Daemon) 服务器返回错误!");
    }
    else
    {
        if (sc_usr_init_srv(srv_fd) != RET_YES) 
            SYS_ABORT("(Usr) 服务器返回错误!");
    }

    st_d_print("客户端连接服务器OK!");

    /**
     * USR 建立本地Listen侦听套接字
     */

    if (cltopt.C_TYPE == C_USR)
    {
        int i = 0;
        for (i=0; i<MAX_PORT_NUM; i++)
        {
            if (cltopt.maps[i].usrport) 
            {
                struct evconnlistener *listener;
                struct sockaddr_in sin;
                memset(&sin, 0, sizeof(sin));
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = htonl(0);
                sin.sin_port = htons(cltopt.maps[i].usrport); /* Port Num */

                listener = evconnlistener_new_bind(base, accept_conn_cb, &cltopt.maps[i],
                        LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1/*backlog 连接无限制*/,
                        (struct sockaddr*)&sin, sizeof(sin));

                if (!listener) 
                {
                    st_d_error("[USR]创建侦听套接字失败 %d:%d", 
                               cltopt.maps[i].usrport, cltopt.maps[i].daemonport); 
                    continue;
                }
                evconnlistener_set_error_cb(listener, accept_error_cb);

                st_d_print("[USR]创建侦听套接字 %d:%d OK", 
                               cltopt.maps[i].usrport, cltopt.maps[i].daemonport); 
            }
            else
                break;
        }
    }
    
    encrypt_init(SD_ID128_CONST_STR(cltopt.mach_uuid), cltopt.enc_key);

    if (cltopt.C_TYPE == C_DAEMON && cltopt.ss5_port ) 
    {
        /**
         * 目前只考虑将sockets5代理使用线程池来处理,其它的端口暴露 
         * 基本都是长连接,不单独处理 
         */
        cltopt.thread_num = 5;

        cltopt.main_thread_id = pthread_self(); 
        cltopt.thread_objs = (P_THREAD_OBJ)calloc(sizeof(THREAD_OBJ), cltopt.thread_num);
        if (!cltopt.thread_objs) 
        {
            SYS_ABORT("申请THREAD_OBJ出错");
        }


        sc_create_ss5_worker_threads(cltopt.thread_num, cltopt.thread_objs); 

        st_d_print("[DAEMON]创建sockets5代理端口:%d", cltopt.ss5_port); 

        struct evconnlistener *listener;
        struct sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(0);
        sin.sin_port = htons(cltopt.ss5_port); /* Port Num */

        listener = evconnlistener_new_bind(base, ss5_accept_conn_cb, NULL,
                LEV_OPT_LEAVE_SOCKETS_BLOCKING/* 阻塞 */|LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, 
                -1/*backlog 连接无限制*/,
                (struct sockaddr*)&sin, sizeof(sin));

        if (!listener) 
        {
            st_d_error("[DAEMON]sockets5代理创建侦听套接字失败 %d", cltopt.ss5_port); 
            exit(EXIT_FAILURE); 
        }
        evconnlistener_set_error_cb(listener, accept_error_cb);

        st_d_print("[DAEMON]sockets5代理创建侦听套接字OK %d", cltopt.ss5_port); 

    }



    if (cltopt.C_TYPE == C_DAEMON && cltopt.dns_port) 
    {
        st_d_print("[DAEMON]创建DNS代理端口:%d", cltopt.dns_port); 
        if (cltopt.dns_port != 53) 
        {
            st_d_print("[DAEMON]请注意标准DNS侦听#53端口!");
        }

        int dns_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (dns_socket < 0 )
        {
            st_d_error("Create DNS socket error!");
            exit(EXIT_FAILURE);
        }

        unsigned int optval = 1;
        setsockopt(dns_socket, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));//禁用NAGLE算法
        setsockopt(dns_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
        evutil_make_socket_closeonexec(dns_socket);
        evutil_make_socket_nonblocking(dns_socket);

        struct sockaddr_in sin;
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(0);
        sin.sin_port = htons(cltopt.dns_port); /* Port Num */

        if (bind(dns_socket, (struct sockaddr *)&sin, sizeof(sin)))
        {
            st_d_error("Bind DNS socket error!");
            exit(EXIT_FAILURE);
        }

        cltopt.dns_transid_port_map = (unsigned short*)malloc(sizeof(unsigned short) * 0xFFFF);
        if (!cltopt.dns_transid_port_map) 
        {
            st_d_error("Malloc for requestid-port failed!");
            exit(EXIT_FAILURE);
        }

        P_PORTTRANS p_trans = sc_create_trans(cltopt.dns_port); 
        if (!p_trans)
        {
            st_d_error("本地无空闲TRANS!");
            exit(EXIT_FAILURE);
        }
        p_trans->is_enc = 1;
        p_trans->l_port = cltopt.dns_port;
        encrypt_ctx_init(&p_trans->ctx_enc, p_trans->l_port, cltopt.enc_key, 1); 
        encrypt_ctx_init(&p_trans->ctx_dec, p_trans->l_port, cltopt.enc_key, 0);
        // 建立DNS UDP事件侦听
        p_trans->extra_ev = event_new(base, dns_socket, EV_READ | EV_PERSIST, 
                                      dns_client_to_proxy_cb, p_trans);


        int dns_srv_fd = socket(AF_INET, SOCK_STREAM, 0);
        if(sc_connect_srv(dns_srv_fd) != RET_YES) 
        {
            SYS_ABORT("连接服务器失败!");
        }

        sc_daemon_dns_init_srv(dns_srv_fd, p_trans->l_port, 12333);
        evutil_make_socket_nonblocking(dns_srv_fd);

        // later enabled
        //event_add(p_trans->extra_ev, NULL) != 0);

        p_trans->srv_bev = bufferevent_socket_new(base, dns_srv_fd, BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(p_trans->srv_bev, dns_bufferread_cb_enc, NULL, dns_bufferevent_cb, p_trans);

        st_d_print("[DAEMON]DNS代理创建侦听套接字OK %d", cltopt.dns_port); 
    }

    sc_set_eventcb_srv(srv_fd, base); 

    /**
     * Main Loop Here
     */

    event_base_loop(base, 0);
    event_base_free(base);
    st_d_print("程序退出!!!!");
    return 0;
}
Beispiel #7
0
DWORD  WaitForSingleObject(HANDLE hHandle,
                DWORD dwMilliseconds)
{
    P_ST_WINSYNC_T p_sync = (P_ST_WINSYNC_T)hHandle;

    struct timespec	ts;

    if (! p_sync)
    {
        st_d_print("Invalid Argument!\n");
        return 0;
    }

    if ( dwMilliseconds == INFINITE)
    {
        if (p_sync->type == SYNC_MUTEX)
        {
            if (strlen(p_sync->sync_name))  //inter-process
            {
                return sem_wait((sem_t *)(p_sync->p_sem));
            }
            else    // intra-process
            {
                return sem_wait((sem_t *)(&p_sync->sem));
            }
        }
        if (p_sync->type == SYNC_EVENT)
        {
            if (strlen(p_sync->sync_name))  //inter-process
            {
                return sem_wait((sem_t *)(p_sync->p_sem));
            }
            else    // intra-process
            {
                return sem_wait((sem_t *)(&p_sync->sem));
            }
        }
    }
    else
    {
        st_make_timespec(&ts, dwMilliseconds);

        if (p_sync->type == SYNC_MUTEX)
        {
            if (strlen(p_sync->sync_name))  //inter-process
            {
                if(sem_timedwait((sem_t *)(p_sync->p_sem), &ts))
                {
                    if ( errno == ETIMEDOUT )
                        return ETIMEDOUT;
                    else
                        return -1;
                }
            }
            else    // intra-process
            {
                if(sem_timedwait((sem_t *)(&p_sync->sem), &ts))
                {
                    if ( errno == ETIMEDOUT )
                        return ETIMEDOUT;
                    else
                        return -1;
                }
            }
        }
        if (p_sync->type == SYNC_EVENT)
        {
            if (strlen(p_sync->sync_name))  //inter-process
            {
                if(sem_timedwait((sem_t *)(p_sync->p_sem), &ts))
                {
                    if ( errno == ETIMEDOUT )
                        return ETIMEDOUT;
                    else
                        return -1;
                }
            }
            else    // intra-process
            {
                if(sem_timedwait((sem_t *)(&p_sync->sem), &ts))
                {
                    if ( errno == ETIMEDOUT )
                        return ETIMEDOUT;
                    else
                        return -1;
                }
            }
        }
    }

    return 0;
}
void dns_query_cb(int errcode, struct evutil_addrinfo *addr, void *ptr)
{
    P_DNS_STRUCT p_dns = (P_DNS_STRUCT)ptr;

    if (errcode) 
    {
        printf("Query error for: %s -> %s\n", p_dns->hostname, evutil_gai_strerror(errcode)); 
    }
    else
    {
        struct evutil_addrinfo *ai;
        struct sockaddr_in sin;

        for (ai = addr; ai; ai = ai->ai_next) 
        {
            if (ai->ai_family == AF_INET) 
            {
                memset(&sin, 0, sizeof(sin));
                sin.sin_family = AF_INET;
                sin.sin_addr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
                sin.sin_port = p_dns->port;

                st_d_print("REQUEST: %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));

                int remote_socket = ss_connect_srv(&sin);
                if (remote_socket == -1)
                {
                    st_d_error("REQUEST: %s:%d FAILED!", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
                    continue;
                }

                evutil_make_socket_nonblocking(p_dns->p_c_item->socket);
                struct bufferevent *new_bev = 
                    bufferevent_socket_new(p_dns->p_threadobj->base, p_dns->p_c_item->socket, BEV_OPT_CLOSE_ON_FREE); 
                assert(new_bev);
                bufferevent_setcb(new_bev, thread_bufferread_cb_enc, NULL, thread_bufferevent_cb, p_dns->p_trans);
                bufferevent_enable(new_bev, EV_READ|EV_WRITE);

                evutil_make_socket_nonblocking(remote_socket);
                struct bufferevent *new_ext_bev = 
                    bufferevent_socket_new(p_dns->p_threadobj->base, remote_socket , BEV_OPT_CLOSE_ON_FREE); 
                assert(new_ext_bev);
                bufferevent_setcb(new_ext_bev, thread_bufferread_cb_enc, NULL, thread_bufferevent_cb, p_dns->p_trans);
                bufferevent_enable(new_ext_bev, EV_READ|EV_WRITE);

                p_dns->p_trans->bev_d = new_bev;
                p_dns->p_trans->bev_u = new_ext_bev;

                st_d_print("DDDDD: 当前活动连接数:[[[ %d ]]], 任务队列:[[ %d ]]", 
                           slist_count(&p_dns->p_trans->p_activ_item->trans), 
                           slist_count(&p_dns->p_threadobj->conn_queue)); 


                st_d_print("SS5激活客户端Bufferevent使能!");
                CTL_HEAD head;
                memset(&head, 0, CTL_HEAD_LEN);
                head.direct = USR_DAEMON; 
                head.cmd = HD_CMD_SS5_ACT; 
                head.extra_param = p_dns->p_trans->usr_lport; 
                head.mach_uuid = p_dns->p_trans->p_activ_item->mach_uuid; 
                bufferevent_write(p_dns->p_trans->p_activ_item->bev_daemon, &head, CTL_HEAD_LEN); 

                break;

            } 

            st_d_print("ALL REQUEST FOR %s FAILED!", p_dns->hostname); 

        }
        evutil_freeaddrinfo(addr);
    }

    free(p_dns->p_c_item);
    free(p_dns);

    return;
}
/**
 * 这里有一个竞争条件:如果这里不能建立libevent连接,或者发送HD_CMD_SS5_ACT之前就收到了 
 * EOF的事件,那么客户端就会存在一个僵尸的trans连接,客户端目前是单线程的,必须消除这种 
 * 消耗 
 *  
 * 目前想到的处理方式就是,在拆除trans的同时,额外的向客户端主通道发送一个命令 
 */
static void thread_process(int fd, short which, void *arg) 
{
    P_THREAD_OBJ p_threadobj = (P_THREAD_OBJ)arg; 
    P_TRANS_ITEM p_trans = NULL;
    P_SLIST_HEAD p_list = NULL;
    P_C_ITEM p_c_item = NULL;
    struct bufferevent *new_bev = NULL;
    char buf[1];
    CTL_HEAD head;

    if (read(fd, buf, 1) != 1)
    {
        st_d_error("Can't read from libevent pipe\n");
        return;
    }

    switch (buf[0]) 
    {
        case 'D':   // DAEMON->USR
            p_list = slist_fetch(&p_threadobj->conn_queue);
            if (!p_list)
            {
                st_d_error("无法从任务队列中获取任务!");
                return;
            }

            p_c_item = list_entry(p_list, C_ITEM, list);
            p_trans = (P_TRANS_ITEM)p_c_item->arg.ptr; 

            new_bev = 
                bufferevent_socket_new(p_threadobj->base, p_c_item->socket, BEV_OPT_CLOSE_ON_FREE); 
            bufferevent_setcb(new_bev, thread_bufferread_cb, NULL, thread_bufferevent_cb, p_trans);
            bufferevent_enable(new_bev, EV_READ|EV_WRITE);

            p_trans->bev_d = new_bev;
            free(p_c_item);

            if (p_trans->bev_u == NULL || p_trans->usr_lport == 0 || p_trans->p_activ_item == NULL) 
            {
                SYS_ABORT("USR SIDE SHOULD BE OK ALREAY!!!");
            }

            st_d_print("WORKTHREAD-> DAEMON_USR(%d) OK!", p_trans->usr_lport); 
            st_d_print("DDDDD: 当前活动连接数:[[[ %d ]]],任务队列:[[ %d ]]", 
                       slist_count(&p_trans->p_activ_item->trans), slist_count(&p_threadobj->conn_queue)); 

            st_d_print("激活客户端Bufferevent使能!");
            memset(&head, 0, CTL_HEAD_LEN);
            head.direct = USR_DAEMON; 
            head.cmd = HD_CMD_CONN_ACT; 
            head.extra_param = p_trans->usr_lport; 
            head.mach_uuid = p_trans->p_activ_item->mach_uuid; 
            bufferevent_write(p_trans->p_activ_item->bev_daemon, &head, CTL_HEAD_LEN); 
            head.direct = DAEMON_USR; 
            bufferevent_write(p_trans->p_activ_item->bev_usr, &head, CTL_HEAD_LEN); 

            break;

        case 'U':   //USR->DAEMON
            p_list = slist_fetch(&p_threadobj->conn_queue);
            if (!p_list)
            {
                st_d_error("无法从任务队列中获取任务!");
                return;
            }

            p_c_item = list_entry(p_list, C_ITEM, list);
            p_trans = (P_TRANS_ITEM)p_c_item->arg.ptr; 

            new_bev = 
                bufferevent_socket_new(p_threadobj->base, p_c_item->socket, BEV_OPT_CLOSE_ON_FREE); 
            bufferevent_setcb(new_bev, thread_bufferread_cb, NULL, thread_bufferevent_cb, p_trans);
            bufferevent_enable(new_bev, EV_READ|EV_WRITE);

            p_trans->bev_u = new_bev;
            free(p_c_item);

            st_d_print("WORKTHREAD-> USR_DAEMON(%d) OK!", p_trans->usr_lport); 

            break;

        case 'S':   // DAEMON->USR
            p_list = slist_fetch(&p_threadobj->conn_queue);
            if (!p_list)
            {
                st_d_error("无法从任务队列中获取任务!");
                return;
            }
            p_c_item = list_entry(p_list, C_ITEM, list);
            p_trans = (P_TRANS_ITEM)p_c_item->arg.ptr; 

            assert(p_trans->is_enc);
            assert(p_trans->dat); 

            encrypt_ctx_init(&p_trans->ctx_enc, p_trans->usr_lport, p_trans->p_activ_item->enc_key, 1); 
            encrypt_ctx_init(&p_trans->ctx_dec, p_trans->usr_lport, p_trans->p_activ_item->enc_key, 0);

            int remote_socket = 0;
            char* buf = (char *)p_trans->dat;

            if (buf[3] == 0x01)
            {
                struct sockaddr_in sin;
                memset(&sin, 0, sizeof(sin));

                sin.sin_family = AF_INET;
                memcpy(&sin.sin_addr.s_addr, &buf[4], 4);
                memcpy(&sin.sin_port, &buf[4+4], 2);
                free(p_trans->dat);

                st_d_print("REQUEST: %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));

                remote_socket = ss_connect_srv(&sin);
                if (remote_socket == -1)
                {
                    free(p_c_item);
                    st_d_error("CONNECT ERROR!");
                    return;
                }
            }
            else
            {
                char remote_addr[128];
                unsigned short remote_port = 0;
                memset(remote_addr, 0, sizeof(remote_addr));
                strncpy(remote_addr, &buf[4+1], buf[4]);
                memcpy(&remote_port, &buf[4+1+buf[4]], 2);
                free(p_trans->dat);

                P_DNS_STRUCT p_dns = (P_DNS_STRUCT)calloc(sizeof(DNS_STRUCT), 1);
                if (!p_dns)
                {
                    st_d_error("申请内存失败:%d", sizeof(DNS_STRUCT));
                    free(p_c_item);
                    return;
                }

                st_d_print("REQUEST: %s:%d", remote_addr, ntohs(remote_port));

                strncpy(p_dns->hostname, remote_addr, sizeof(p_dns->hostname));
                p_dns->port = remote_port;
                p_dns->p_c_item = p_c_item;
                p_dns->p_threadobj = p_threadobj;
                p_dns->p_trans = p_trans;

                struct evutil_addrinfo hints;
                struct evdns_getaddrinfo_request *req;
                memset(&hints, 0, sizeof(hints));
                hints.ai_family = AF_INET;
                hints.ai_flags = EVUTIL_AI_CANONNAME;
                /* Unless we specify a socktype, we'll get at least two entries for
                 * each address: one for TCP and one for UDP. That's not what we
                 * want. */
                hints.ai_socktype = SOCK_STREAM;
                hints.ai_protocol = IPPROTO_TCP;


                req = evdns_getaddrinfo(
                    srvopt.evdns_base, remote_addr, NULL /* no service name given */, 
                                  &hints, dns_query_cb, p_dns);
                if (req == NULL) {
                  printf("    [request for %s returned immediately]\n", remote_addr);
                  /* No need to free user_data or decrement n_pending_requests; that
                   * happened in the callback. */
                }

                return;
            }

            evutil_make_socket_nonblocking(p_c_item->socket);
            struct bufferevent *new_bev = 
                bufferevent_socket_new(p_threadobj->base, p_c_item->socket, BEV_OPT_CLOSE_ON_FREE); 
            assert(new_bev);
            bufferevent_setcb(new_bev, thread_bufferread_cb_enc, NULL, thread_bufferevent_cb, p_trans);
            bufferevent_enable(new_bev, EV_READ|EV_WRITE);

            evutil_make_socket_nonblocking(remote_socket);
            struct bufferevent *new_ext_bev = 
                bufferevent_socket_new(p_threadobj->base, remote_socket , BEV_OPT_CLOSE_ON_FREE); 
            assert(new_ext_bev);
            bufferevent_setcb(new_ext_bev, thread_bufferread_cb_enc, NULL, thread_bufferevent_cb, p_trans);
            bufferevent_enable(new_ext_bev, EV_READ|EV_WRITE);

            p_trans->bev_d = new_bev;
            p_trans->bev_u = new_ext_bev;
            free(p_c_item);

            st_d_print("DDDDD: 当前活动连接数:[[[ %d ]]], 任务队列:[[ %d ]]", 
                       slist_count(&p_trans->p_activ_item->trans), slist_count(&p_threadobj->conn_queue)); 

            st_d_print("SS5激活客户端Bufferevent使能!");
            memset(&head, 0, CTL_HEAD_LEN);
            head.direct = USR_DAEMON; 
            head.cmd = HD_CMD_SS5_ACT; 
            head.extra_param = p_trans->usr_lport; 
            head.mach_uuid = p_trans->p_activ_item->mach_uuid; 
            bufferevent_write(p_trans->p_activ_item->bev_daemon, &head, CTL_HEAD_LEN); 
            break;

    default:
        SYS_ABORT("WHAT DO I GET: %c", buf[0]);
        break;
    }

    return;
}
Beispiel #10
0
// POSIX要求的共享名字必须是  /sharename  < NAME_MAX
//
void* st_shm_create(const char* share_name, size_t max_size)
{
	char path_buf[PATH_MAX];
	P_ST_SHM_T p_token = NULL;
	FILE* fp = NULL;
	char    rw_buf[512];
	
    if (!share_name)
        return NULL;
	
    p_token = (P_ST_SHM_T)malloc(sizeof(ST_SHM_T));
    if (! p_token)
    {
        return NULL;
    }
	
	if ( access(ST_SHM_PREFIX, W_OK) != 0)
        mkdir(ST_SHM_PREFIX, 0777);

	// Additional
	shm_unlink(share_name);

    memset(p_token, 0, sizeof(ST_SHM_T));
	p_token->location = NULL;
    p_token->fd = -1;
    p_token->size = max_size;
	
	// For compatible
	if(share_name[0] != '/')
	{
		p_token->shmname[0] = '/';
		strncpy(p_token->shmname + 1, share_name, NAME_MAX);
	}
	else
	{
		strncpy(p_token->shmname, share_name, NAME_MAX);
	}

	p_token->fd = shm_open(p_token->shmname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 
		S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
	if( p_token->fd < 0)
	{
		perror("Create shm_open failed!");
		goto failed;
	}
    
    if( ftruncate(p_token->fd, max_size) == -1)
	{
		perror("ftruncate share mem failed!");
		goto failed;
	}

    p_token->location = mmap( NULL, p_token->size,
                      PROT_READ | PROT_WRITE,
                      MAP_SHARED, p_token->fd, 0);
    if ((void *)p_token->location == (void *)MAP_FAILED)
    {
        st_print("Call mmap failed:%s\n", p_token->shmname);
        goto failed;
    }
		
	//Store the address in mapfile for referenec
    strncpy(path_buf, ST_SHM_PREFIX, PATH_MAX);
    strncat(path_buf, p_token->shmname, NAME_MAX);
	if ( access(ST_SHM_PREFIX, W_OK) == 0)
	{
		st_d_print("shm file exists, delete it anyway!\n");
		remove(path_buf);
	}
	
    if((fp = fopen(path_buf, "w")))
    {
        snprintf(rw_buf, sizeof(rw_buf), "ADDR:%p,SIZE:%u\n", p_token->location, 
                 p_token->size);
        fwrite(rw_buf, strlen(rw_buf)+1, 1, fp);
        fclose(fp);
    }

    st_d_print("ShareName:%s,\t Location:%p,\t MapSize:%u\n", 
               p_token->shmname, p_token->location, p_token->size);
		   
    return p_token;
     
failed:
    free(p_token);
    return NULL;
}
Beispiel #11
0
void* st_shm_open(const char* share_name, int fixaddr, int writable)
{
    P_ST_SHM_T p_token = NULL;
    mode_t	mode = 0;
    int	    flag = 0;
	int map_flag = 0;
	FILE*     fp = NULL;
    char rw_buf[512];
	char path_buf[PATH_MAX];

    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
    if (writable)
    {
        flag = O_RDWR ; 
        map_flag = PROT_READ | PROT_WRITE;
    }
    else
    {
        flag = O_RDONLY;
        map_flag = PROT_READ;
    }
	
	p_token = (P_ST_SHM_T)malloc(sizeof(ST_SHM_T));
    if (! p_token)
        return NULL;
    
	memset(p_token, 0, sizeof(ST_SHM_T));
    p_token->location = NULL;
    p_token->fd = -1;
    p_token->size = 0;
    // For compatible
	if(share_name[0] != '/')
	{
		p_token->shmname[0] = '/';
		strncpy(p_token->shmname + 1, share_name, NAME_MAX);
	}
	else
	{
		strncpy(p_token->shmname, share_name, NAME_MAX);
	}
	
	p_token->fd = shm_open(p_token->shmname, flag, mode);
	if( p_token->fd < 0)
	{
		perror("Create shm_open failed!");
		goto failed;
	}
	
    snprintf(path_buf, PATH_MAX, "%s/%s", ST_SHM_PREFIX, share_name);
    if((fp = fopen(path_buf, "r")))
    {
        rewind(fp);
        fscanf(fp,"ADDR:%p,SIZE:%u\n", &p_token->location,
               &p_token->size);
        fclose(fp);
        st_d_print("MAPINFO ADDR:%p,SIZE:%u\n", p_token->location,
               p_token->size);
    }
	else
	{
		st_print("Open shm info failed with %s\n", path_buf);
		goto failed;
	}


    if (fixaddr)
        p_token->location = mmap(p_token->location, p_token->size,
                      map_flag,
                      MAP_SHARED | MAP_FIXED, p_token->fd, 0);
    else
        p_token->location = mmap(NULL, p_token->size,
                      map_flag,
                      MAP_SHARED, p_token->fd, 0);

    if ((void *)p_token->location == (void *)MAP_FAILED)
    {
        perror("Call mmap failed:\n");
        goto failed;
    }

    return p_token;

failed:
    free(p_token);
    return NULL;
}
Beispiel #12
0
void st_event_loop(P_EPOLL_STRUCT p_epoll, P_ST_THREAD_MANAGE p_manage, void* handler(void* data))
{
    if (!p_epoll)
        return;
    struct epoll_event* p_events = p_epoll->p_events;
    int listen_socket = p_epoll->event.data.fd;

    int e_i = 0;
    int ready = 0;

    for ( ; ; )
    {
        ready = epoll_wait(p_epoll->event_fd, p_events, p_epoll->max_events, -1); 
        for (e_i = 0; e_i < ready; e_i++)
        {
			if( (p_epoll->p_events[e_i].events & EPOLLERR) )			
            {
                st_d_print("Epoll Error!\n");
                close(p_epoll->p_events[e_i].data.fd);
                continue;
            }
			
			if ( ( p_epoll->p_events[e_i].events & EPOLLHUP ) ||
				 ( p_epoll->p_events[e_i].events & EPOLLRDHUP) )
			{
				st_d_print("Remote Disconnected!\n");
                close(p_epoll->p_events[e_i].data.fd);
				continue;
			}
            
            if (listen_socket == p_events[e_i].data.fd)
            {
                 /* 新链接到了(可能会有多个连接同时到来) */
                while (1)
                {
                    struct sockaddr in_addr;
                    socklen_t in_len;
                    int infd;
                    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

                    in_len = sizeof(struct sockaddr);
                    infd = accept (listen_socket, &in_addr, &in_len); //非阻塞的Socket
                    if (infd == -1)
                        break;

                    int sk = getnameinfo (&in_addr, in_len,
                                       hbuf, sizeof(hbuf),
                                       sbuf, sizeof(sbuf),
                                       NI_NUMERICHOST | NI_NUMERICSERV);
                    if (sk == 0)
                    {
                        st_print("Accept NEW Connect:[%d} "
                                 "(host=%s, port=%s)\n", infd, hbuf, sbuf);
                    }

                    if (st_add_new_event(infd, p_epoll))
                    {
                        st_print("Add socket:%d to event error!\n", infd);
                        break;
                    }

                    continue;       //可能有多个连接
                }
            }
            else
            {
                //有侦听的套接字发送数据的请求,添加你的处理
                if (p_manage && handler)
                {
                    st_threadpool_push_task(p_manage, handler, (void *)p_events[e_i].data.fd);  //传值调用简单些!
                }
#if 0
                while (1)
                {
                    ssize_t count;
                    char buf[512];

                    count = read (p_events[e_i].data.fd, buf, sizeof(buf));
                    if (count == -1)
                    {
                        /* If errno == EAGAIN, that means we have read all
                         data. So go back to the main loop. */
                        if (errno != EAGAIN)
                        {
                            perror ("read");
                            done = 1;
                        }

                        break;
                    }
                    else if (count == 0)
                    {
                      /* End of file. The remote has closed the
                         connection. */
                      done = 1;
                      break;
                    }

                    /* Write the buffer to standard output */
                    int s = write (1, buf, count);
                    if (s == -1)
                    {
                        perror ("write");
                        abort ();
                    }
                }

                if (done)
                {
                    printf ("Closed connection on descriptor %d\n",
                          p_events[e_i].data.fd);

                    /* Closing the descriptor will make epoll remove it
                     from the set of descriptors which are monitored. */
                    close (p_events[e_i].data.fd);
                }
#endif
            }
        }
    }
}
Beispiel #13
0
/**
 * 只会在USR端被调用
 */
void accept_conn_cb(struct evconnlistener *listener,
    evutil_socket_t fd, struct sockaddr *address, int socklen,
    void *ctx)
{
    P_PORTMAP p_map = (P_PORTMAP)ctx; 
    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

    getnameinfo (address, socklen,
               hbuf, sizeof(hbuf),sbuf, sizeof(sbuf),
               NI_NUMERICHOST | NI_NUMERICSERV);

    st_print("WELCOME NEW CONNECT (HOST=%s, PORT=%s)\n", hbuf, sbuf);

    /* We got a new connection! Set up a bufferevent for it. */
    struct event_base *base = evconnlistener_get_base(listener);

    int srv_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(sc_connect_srv(srv_fd) != RET_YES) 
    {
        st_d_error("连接服务器失败!");
        return;
    }

    P_PORTTRANS p_trans = sc_create_trans(atoi(sbuf)); 

    if (!p_trans)
    {
        st_d_error("本地无空闲TRANS!");
        return;
    }

    struct bufferevent *local_bev = 
        bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    assert(local_bev);
    bufferevent_setcb(local_bev, bufferread_cb, NULL, bufferevent_cb, p_trans);
    //bufferevent_enable(local_bev, EV_READ|EV_WRITE);

    struct bufferevent *srv_bev = 
        bufferevent_socket_new(base, srv_fd, BEV_OPT_CLOSE_ON_FREE);
    assert(srv_bev);
    bufferevent_setcb(srv_bev, bufferread_cb, NULL, bufferevent_cb, p_trans);
    //bufferevent_enable(srv_bev, EV_READ|EV_WRITE);

    p_trans->is_enc = 0;
    p_trans->l_port = atoi(sbuf);
    p_trans->local_bev = local_bev;
    p_trans->srv_bev = srv_bev;

    st_d_print("DDDDD: 当前活动连接数:[[[ %d ]]]", 
               slist_count(&cltopt.trans)); 

    /* 向服务器报告连接请求 */
    CTL_HEAD ret_head;
    memset(&ret_head, 0, CTL_HEAD_LEN);
    ret_head.cmd = HD_CMD_CONN;
    ret_head.daemonport = p_map->daemonport;
    ret_head.usrport = p_map->usrport;
    ret_head.extra_param = atoi(sbuf);
    ret_head.mach_uuid = cltopt.session_uuid;
    ret_head.direct = USR_DAEMON;

    bufferevent_write(srv_bev, &ret_head, CTL_HEAD_LEN);

    st_d_print("客户端创建BEV OK!");

    /**
     * 有些服务是conn连接之后,服务端先发消息,然后客户端再进行响应的,所以 
     * 为了避免这种情况,客户端接收到conn消息之后,需要先向DAEMON端发送一个控制 
     * 消息,打通DAEMON端的数据传输接口 
     */

    return;
}
Beispiel #14
0
void srv_bufferevent_cb(struct bufferevent *bev, short events, void *ptr)
{
    struct event_base *base = bufferevent_get_base(bev);
    int loop_terminate_flag = 0;

    //只有使用bufferevent_socket_connect进行的连接才会得到CONNECTED的事件
    if (events & BEV_EVENT_CONNECTED) 
    {
        st_d_print("GOT BEV_EVENT_CONNECTED event! ");
    } 
    else if (events & BEV_EVENT_ERROR) 
    {
        st_d_error("GOT BEV_EVENT_ERROR event! ");
        loop_terminate_flag = 1;
    } 
    else if (events & BEV_EVENT_EOF) 
    {
        st_d_print("GOT BEV_EVENT_EOF event! ");

        // main_be连接断开,这时候:如果是DAEMON端主动断开,那么USR端也要断开
        // 否则,就让DAEMON进行重置(重新连接服务器)
        // 任何情况下,所有的服务都必须断开

        // BEV_OPT_CLOSE_ON_FREE already closed the socket
        if (cltopt.C_TYPE == C_USR) 
        {
            st_d_print("DAEMON已经退出,本端挂起!");
            exit(EXIT_SUCCESS);
        }
        else
        {
            sc_free_all_trans();
            st_d_print("DAEMON端重连服务器!");

            int srv_fd;
            srv_fd = socket(AF_INET, SOCK_STREAM, 0);

            if (sc_connect_srv(srv_fd) != RET_YES)
            {
                st_d_error("连接服务器失败!");
                event_base_loopexit(base, NULL);
            }

            if (sc_daemon_init_srv(srv_fd) != RET_YES) 
            {
                st_d_error("(DAEMON)服务端返回错误!");
                event_base_loopexit(base, NULL);
            }
       
            sc_set_eventcb_srv(srv_fd, base);
            st_d_print("(DAEMON)重连OK!");

        }

    }
    else if (events & BEV_EVENT_TIMEOUT) 
    {
        st_d_print("GOT BEV_EVENT_TIMEOUT event! ");
    } 
    
    if (loop_terminate_flag)
    {
        bufferevent_free(bev);
        event_base_loopexit(base, NULL);
    }

    return;
}
Beispiel #15
0
/**
 * 客户端和远程服务器的交互
 */
void srv_bufferread_cb(struct bufferevent *bev, void *ptr)
{
    size_t n = 0;
    CTL_HEAD head;

    struct evbuffer *input = bufferevent_get_input(bev);
    struct evbuffer *output = bufferevent_get_output(bev);

    if ( evbuffer_remove(input, &head, CTL_HEAD_LEN) != CTL_HEAD_LEN)
    {
        st_d_print("读取数据包头%d错误!", CTL_HEAD_LEN);
        return;
    }

    if (!sd_id128_equal(head.mach_uuid, cltopt.session_uuid))
    {
        SYS_ABORT("服务端返回UUID校验失败:%s-%s",
                  SD_ID128_CONST_STR(head.mach_uuid), SD_ID128_CONST_STR(cltopt.session_uuid)); 
    }

    if (head.cmd == HD_CMD_ERROR) 
    {
        st_d_error("SERVER RETURNED ERROR!");
        exit(EXIT_SUCCESS);
    }

    if (head.cmd == HD_CMD_CONN_ACT)
    {
        P_PORTTRANS p_trans = sc_find_trans(head.extra_param); 
        if (!p_trans) 
        {
            SYS_ABORT("本地未找到连接信息:%d", head.extra_param);
        }

        bufferevent_enable(p_trans->local_bev, EV_READ|EV_WRITE);
        bufferevent_enable(p_trans->srv_bev, EV_READ|EV_WRITE); 

        st_d_print("开始传输数据:%d", head.extra_param); 
    }
    if (head.cmd == HD_CMD_END_TRANS) 
    {
        P_PORTTRANS p_trans = sc_find_trans(head.extra_param); 
        if (p_trans) 
        {
            st_d_print("EXTRA CLOSE TRANS: %d", head.extra_param);
            sc_free_trans(p_trans);
        }
    }
    if (head.cmd == HD_CMD_SS5_ACT) 
    {    
        // OK,返回给本地程序告知可以开始传输了
        // 这个绑定地址目前还没利用,主要是需要FTP这类需要带外传输另外连接端口的
        char ret_msg[10] = "\x05\x00\x00\x01\x00\x00\x00\x00\x10\x10";

        P_PORTTRANS p_trans = sc_find_trans(head.extra_param); 
        if (!p_trans) 
        {
            SYS_ABORT("本地SS5未找到连接信息:%d", head.extra_param);
        }

        bufferevent_enable(p_trans->local_bev, EV_READ|EV_WRITE);
        bufferevent_enable(p_trans->srv_bev, EV_READ|EV_WRITE); 

        bufferevent_write(p_trans->local_bev, ret_msg, sizeof(ret_msg));
        st_d_print("SS5准备传输数据:%d", head.extra_param); 

        return;
    }
    if (head.cmd == HD_CMD_CONN) 
    {
        assert(cltopt.C_TYPE == C_DAEMON);
        if (cltopt.C_TYPE == C_DAEMON) 
        {
            sc_find_daemon_portmap(head.daemonport, 1);
            P_PORTTRANS p_trans = sc_create_trans(head.extra_param); 
            p_trans->is_enc = 0;
            
            if (!p_trans)
            {
                st_d_error("本地无空闲TRANS!");
                return;
            }

            /*建立本地连接*/
            int local_fd = socket(AF_INET, SOCK_STREAM, 0);
            int reuseaddr_on = 1;
            if (setsockopt(local_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, 
                sizeof(reuseaddr_on)) == -1)
            {
                st_d_error("Reuse socket opt faile!\n");
                return;
            }
            struct sockaddr_in  local_srv;
            local_srv.sin_family = AF_INET;
            local_srv.sin_addr.s_addr = inet_addr("127.0.0.1");
            local_srv.sin_port = htons(head.daemonport);

            if (connect(local_fd, (struct sockaddr *)&local_srv, sizeof(local_srv))) 
            {
                st_d_error("连接本地端口%d失败!", head.daemonport); 
                return;
            }
            else
            {
                st_d_print("连接本地端口%d OK!", head.daemonport); 
            }


            /*建立服务器连接*/
            int srv_fd = socket(AF_INET, SOCK_STREAM, 0);
            if(sc_connect_srv(srv_fd) != RET_YES) 
            {
                st_d_error("连接服务器失败!");
                return;
            }


            struct event_base *base = bufferevent_get_base(bev);

            evutil_make_socket_nonblocking(local_fd);
            struct bufferevent *local_bev = 
                bufferevent_socket_new(base, local_fd, BEV_OPT_CLOSE_ON_FREE);
            bufferevent_setcb(local_bev, bufferread_cb, NULL, bufferevent_cb, p_trans);
            //bufferevent_enable(local_bev, EV_READ|EV_WRITE);

            evutil_make_socket_nonblocking(srv_fd); 
            struct bufferevent *srv_bev = 
                bufferevent_socket_new(base, srv_fd, BEV_OPT_CLOSE_ON_FREE);
            bufferevent_setcb(srv_bev, bufferread_cb, NULL, bufferevent_cb, p_trans);
            //bufferevent_enable(srv_bev, EV_READ|EV_WRITE);


            p_trans->l_port = head.extra_param;
            p_trans->local_bev = local_bev;
            p_trans->srv_bev = srv_bev;

            /* 向服务器报告连接请求 */
            // 必须要发送CONN包,触发这个连接转移到线程池处理  
            CTL_HEAD ret_head;
            memset(&ret_head, 0, CTL_HEAD_LEN);
            ret_head.cmd = HD_CMD_CONN;
            ret_head.extra_param = p_trans->l_port; 
            ret_head.mach_uuid = cltopt.session_uuid;
            ret_head.direct = DAEMON_USR; 

            bufferevent_write(srv_bev, &ret_head, CTL_HEAD_LEN);

            st_d_print("DAEMON端准备OK!");
        }
    }

}