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; }
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; }
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; }
/** * 由于自己封装了结构,方便调用,所以有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; }
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; }
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; }
// 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; }
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; }
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 } } } }
/** * 只会在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; }
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; }
/** * 客户端和远程服务器的交互 */ 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!"); } } }