static int update_pid_file(struct runtime_config *rtc) { FILE *fd; char *pidfile; if (access(rtc->statedir, W_OK)) if (mkdir(rtc->statedir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) return 1; pidfile = construct_pidfile(rtc); if (!(fd = fopen(pidfile, "w"))) { #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=could not open file", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_ERROR), "PID_FILE=%s", pidfile, "STRERROR=%s", strerror(errno), "PRIORITY=3", NULL); #else syslog(LOG_ERR, "could not open file: %s: %s", pidfile, strerror(errno)); #endif return 1; } fprintf(fd, "%u %d", getpid(), rtc->msg_type); if (close_stream(fd)) #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=close failed", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_ERROR), "PID_FILE=%s", pidfile, "STRERROR=%s", strerror(errno), "PRIORITY=3", NULL); #else syslog(LOG_ERR, "close failed: %s: %s", pidfile, strerror(errno)); #endif free(pidfile); return 0; }
static void run_server(struct runtime_config *rtc) { struct sockaddr_in client_addr; socklen_t addr_len; pthread_attr_t attr; #ifdef USE_SYSTEMD int ret; ret = sd_listen_fds(0); if (1 < ret) faillog("no or too many file descriptors received"); else if (ret == 1) rtc->server_s = SD_LISTEN_FDS_START + 0; else { #endif if (!(rtc->server_s = socket(rtc->res->ai_family, rtc->res->ai_socktype, rtc->res->ai_protocol))) err(EXIT_FAILURE, "cannot create socket"); if (bind(rtc->server_s, rtc->res->ai_addr, rtc->res->ai_addrlen)) err(EXIT_FAILURE, "unable to bind"); if (listen(rtc->server_s, SOMAXCONN)) err(EXIT_FAILURE, "unable to listen"); #ifdef USE_SYSTEMD } #endif if (pthread_attr_init(&attr)) err(EXIT_FAILURE, "cannot init thread attribute"); if (pthread_rwlock_init(&(rtc->lock), NULL)) err(EXIT_FAILURE, "cannot init read-write lock"); daemonize(); if (rtc->msg_type == STATE_UNKNOWN) read_status_from_file(rtc); if (update_pid_file(rtc)) faillog("cannot write pid file"); openlog(PACKAGE_NAME, LOG_PID, LOG_DAEMON); signal(SIGHUP, stop_server); signal(SIGINT, stop_server); signal(SIGTERM, stop_server); #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=service started", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_STOP_START), "STATE=%s", state_messages[rtc->msg_type], "PRIORITY=6", NULL); #else syslog(LOG_INFO, "started in state %s", state_messages[rtc->msg_type]); #endif while (1) { int accepted; pthread_t thread; int *newsock; addr_len = sizeof(client_addr); accepted = accept(rtc->server_s, (struct sockaddr *)&client_addr, &addr_len); newsock = malloc(sizeof(int)); *newsock = accepted; pthread_create(&thread, NULL, handle_request, newsock); pthread_detach(thread); } }
faillog(char *msg) { #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=%s", msg, "STRERROR=%s", strerror(errno), "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_ERROR), "PRIORITY=3", NULL); #else syslog(LOG_ERR, "%s: %s", msg, strerror(errno)); #endif exit(EXIT_FAILURE); }
static void stop_server(int sig __attribute__ ((__unused__))) { pthread_rwlock_destroy(&(rtc.lock)); freeaddrinfo(rtc.res); close(rtc.server_s); #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=service stopped", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_STOP_START), "PRIORITY=6", NULL); #else syslog(LOG_INFO, "stopped"); #endif closelog(); }
static void catch_signals(int signal) { if (pthread_rwlock_wrlock(&rtc.lock)) { #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=could not get lock", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_ERROR), "STRERROR=%s", strerror(errno), "PRIORITY=3", NULL); #else syslog(LOG_ERR, "could not get lock"); #endif return; } switch (signal) { case SIGUSR1: rtc.msg_type = STATE_DISABLE; break; case SIGUSR2: rtc.msg_type = STATE_MAINTENANCE; break; case SIGWINCH: rtc.msg_type = STATE_ENABLE; break; default: /* should be impossible to reach */ abort(); } rtc.msg_len = strlen(state_messages[rtc.msg_type]); update_pid_file(&rtc); pthread_rwlock_unlock(&(rtc.lock)); #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=signal received", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_STATE_CHANGE), "NEW_STATE=%s", state_messages[rtc.msg_type], "PRIORITY=6", NULL); #else syslog(LOG_INFO, "signal received, state is %s", state_messages[rtc.msg_type]); #endif closelog(); }
int main(int argc, char **argv) { int c, server = 0; char *listen = NULL, *port = PORT_NUM; struct addrinfo hints; int e; enum { STATEDIR_OPT = CHAR_MAX + 1 }; static const struct option longopts[] = { {"disable", no_argument, NULL, 'd'}, {"maintenance", no_argument, NULL, 'm'}, {"enable", no_argument, NULL, 'e'}, {"server", no_argument, NULL, 's'}, {"listen", required_argument, NULL, 'l'}, {"port", required_argument, NULL, 'p'}, {"state", required_argument, NULL, STATEDIR_OPT}, {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; set_program_name(argv[0]); atexit(close_stdout); memset(&rtc, 0, sizeof(struct runtime_config)); rtc.argv = argv; rtc.statedir = F5GS_RUNDIR; while ((c = getopt_long(argc, argv, "dmesl:p:Vh", longopts, NULL)) != -1) { switch (c) { case 'd': rtc.send_signal = state_signals[STATE_DISABLE]; break; case 'm': rtc.send_signal = state_signals[STATE_MAINTENANCE]; break; case 'e': rtc.send_signal = state_signals[STATE_ENABLE]; break; case 's': server = 1; break; case 'l': listen = optarg; break; case 'p': port = optarg; break; case STATEDIR_OPT: rtc.statedir = optarg; break; case 'V': printf("%s version %s", PACKAGE_NAME, PACKAGE_VERSION); #ifdef USE_SYSTEMD puts(" with systemd support"); #else puts(""); #endif return EXIT_SUCCESS; case 'h': usage(stdout); default: usage(stderr); } } if (signal(state_signals[STATE_DISABLE], catch_signals) == SIG_ERR || signal(state_signals[STATE_MAINTENANCE], catch_signals) == SIG_ERR || signal(state_signals[STATE_ENABLE], catch_signals) == SIG_ERR) err(EXIT_FAILURE, "cannot set signal handler"); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; e = getaddrinfo(listen, port, &hints, &(rtc.res)); if (e) { warnx("getaddrinfo: %s port %s: %s", listen, port, gai_strerror(e)); exit(EXIT_FAILURE); } if (rtc.send_signal && server) change_state(&rtc, getpid()); else if (server) { rtc.msg_type = STATE_UNKNOWN; rtc.msg_len = strlen(state_messages[STATE_UNKNOWN]); } else if (rtc.send_signal) { char *eptr; pid_t pid; FILE *pidfd; char *pid_file = construct_pidfile(&rtc); if (!(pidfd = fopen(pid_file, "r"))) err(EXIT_FAILURE, "cannot open pid file: %s", pid_file); fscanf(pidfd, "%d", &pid); if (close_stream(pidfd)) #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=close failed", "PID_FILE=%s", pid_file, "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_ERROR), "STRERROR=%s", strerror(errno), "PRIORITY=3", NULL); #else syslog(LOG_ERR, "close failed: %s: %s", pid_file, strerror(errno)); #endif free(pid_file); if (change_state(&rtc, pid)) { if (errno == 0) { errx(EXIT_FAILURE, "execution of %s failed", F5GS_PRE); } else { err(EXIT_FAILURE, "sending signal failed"); } } openlog(PACKAGE_NAME, LOG_PID, LOG_DAEMON); eptr = getenv("USER"); if (eptr != NULL) #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=signal was sent", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_STATE_CHANGE), "USER=%s", eptr, "PRIORITY=6", NULL); #else syslog(LOG_INFO, "signal was sent by USER: %s", eptr); #endif eptr = getenv("SUDO_USER"); if (eptr != NULL) #ifdef USE_SYSTEMD sd_journal_send("MESSAGE=signal was sent", "MESSAGE_ID=%s", SD_ID128_CONST_STR(MESSAGE_STATE_CHANGE), "SUDO_USER=%s", eptr, "PRIORITY=6", NULL); #else syslog(LOG_INFO, "signal was sent by SUDO_USER: %s", eptr); #endif } if (server) run_server(&rtc); printf("current status is: %s\n", get_server_status(&rtc)); freeaddrinfo(rtc.res); return EXIT_SUCCESS; }
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; }
/** * 客户端和远程服务器的交互 */ 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!"); } } }