diff --git a/src/Makefile.am b/src/Makefile.am index b3c43f1f..9d03edbf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,6 +72,7 @@ ss_server_SOURCES = utils.c \ ss_manager_SOURCES = utils.c \ jconf.c \ json.c \ + netutils.c \ manager.c ss_local_LDADD = $(SS_COMMON_LIBS) @@ -82,10 +83,12 @@ if USE_SYSTEM_SHARED_LIB ss_local_LDADD += -ludns ss_tunnel_LDADD += -ludns ss_server_LDADD += -ludns +ss_manager_LDADD += -ludns else ss_local_LDADD += $(top_builddir)/libudns/libudns.la ss_tunnel_LDADD += $(top_builddir)/libudns/libudns.la ss_server_LDADD += $(top_builddir)/libudns/libudns.la +ss_manager_LDADD += $(top_builddir)/libudns/libudns.la endif ss_local_CFLAGS = $(AM_CFLAGS) -DMODULE_LOCAL diff --git a/src/Makefile.in b/src/Makefile.in index f8e8d1f1..dca1f686 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -94,14 +94,16 @@ bin_PROGRAMS = ss-local$(EXEEXT) ss-tunnel$(EXEEXT) $(am__EXEEXT_1) \ @USE_SYSTEM_SHARED_LIB_TRUE@am__append_5 = -ludns @USE_SYSTEM_SHARED_LIB_TRUE@am__append_6 = -ludns @USE_SYSTEM_SHARED_LIB_TRUE@am__append_7 = -ludns -@USE_SYSTEM_SHARED_LIB_FALSE@am__append_8 = $(top_builddir)/libudns/libudns.la +@USE_SYSTEM_SHARED_LIB_TRUE@am__append_8 = -ludns @USE_SYSTEM_SHARED_LIB_FALSE@am__append_9 = $(top_builddir)/libudns/libudns.la @USE_SYSTEM_SHARED_LIB_FALSE@am__append_10 = $(top_builddir)/libudns/libudns.la -@BUILD_WINCOMPAT_TRUE@am__append_11 = win32.c -@BUILD_WINCOMPAT_TRUE@am__append_12 = win32.c -@BUILD_REDIRECTOR_TRUE@am__append_13 = ss-redir -@BUILD_REDIRECTOR_TRUE@@USE_SYSTEM_SHARED_LIB_TRUE@am__append_14 = -ludns -@BUILD_REDIRECTOR_TRUE@@USE_SYSTEM_SHARED_LIB_FALSE@am__append_15 = $(top_builddir)/libudns/libudns.la +@USE_SYSTEM_SHARED_LIB_FALSE@am__append_11 = $(top_builddir)/libudns/libudns.la +@USE_SYSTEM_SHARED_LIB_FALSE@am__append_12 = $(top_builddir)/libudns/libudns.la +@BUILD_WINCOMPAT_TRUE@am__append_13 = win32.c +@BUILD_WINCOMPAT_TRUE@am__append_14 = win32.c +@BUILD_REDIRECTOR_TRUE@am__append_15 = ss-redir +@BUILD_REDIRECTOR_TRUE@@USE_SYSTEM_SHARED_LIB_TRUE@am__append_16 = -ludns +@BUILD_REDIRECTOR_TRUE@@USE_SYSTEM_SHARED_LIB_FALSE@am__append_17 = $(top_builddir)/libudns/libudns.la subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/auto/depcomp $(include_HEADERS) @@ -156,7 +158,7 @@ am__DEPENDENCIES_2 = $(top_builddir)/libipset/libipset.la \ $(top_builddir)/libcork/libcork.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__append_3) am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(am__append_8) + $(am__append_9) libshadowsocks_libev_la_DEPENDENCIES = $(am__DEPENDENCIES_3) am__libshadowsocks_libev_la_SOURCES_DIST = utils.c jconf.c json.c \ encrypt.c udprelay.c cache.c acl.c netutils.c local.c \ @@ -209,15 +211,16 @@ am_ss_local_OBJECTS = ss_local-utils.$(OBJEXT) \ $(am__objects_5) $(am__objects_6) $(am__objects_7) ss_local_OBJECTS = $(am_ss_local_OBJECTS) ss_local_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(am__append_8) + $(am__append_9) ss_local_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_local_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am_ss_manager_OBJECTS = ss_manager-utils.$(OBJEXT) \ ss_manager-jconf.$(OBJEXT) ss_manager-json.$(OBJEXT) \ - ss_manager-manager.$(OBJEXT) + ss_manager-netutils.$(OBJEXT) ss_manager-manager.$(OBJEXT) ss_manager_OBJECTS = $(am_ss_manager_OBJECTS) -ss_manager_DEPENDENCIES = $(am__DEPENDENCIES_2) +ss_manager_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ + $(am__append_12) ss_manager_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_manager_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ @@ -239,7 +242,7 @@ am__objects_9 = ss_redir-http.$(OBJEXT) ss_redir-tls.$(OBJEXT) \ @BUILD_REDIRECTOR_TRUE@ $(am__objects_8) $(am__objects_9) ss_redir_OBJECTS = $(am_ss_redir_OBJECTS) @BUILD_REDIRECTOR_TRUE@ss_redir_DEPENDENCIES = $(am__DEPENDENCIES_2) \ -@BUILD_REDIRECTOR_TRUE@ $(am__DEPENDENCIES_1) $(am__append_15) +@BUILD_REDIRECTOR_TRUE@ $(am__DEPENDENCIES_1) $(am__append_17) ss_redir_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_redir_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ @@ -255,7 +258,7 @@ am_ss_server_OBJECTS = ss_server-utils.$(OBJEXT) \ ss_server-server.$(OBJEXT) $(am__objects_10) $(am__objects_11) ss_server_OBJECTS = $(am_ss_server_OBJECTS) ss_server_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(am__append_10) + $(am__append_11) ss_server_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_server_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ @@ -272,7 +275,7 @@ am_ss_tunnel_OBJECTS = ss_tunnel-utils.$(OBJEXT) \ $(am__objects_12) ss_tunnel-tunnel.$(OBJEXT) $(am__objects_13) ss_tunnel_OBJECTS = $(am_ss_tunnel_OBJECTS) ss_tunnel_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(am__append_9) + $(am__append_10) ss_tunnel_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ss_tunnel_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ @@ -492,9 +495,9 @@ obfs_src = obfs_http.c \ ss_local_SOURCES = utils.c jconf.c json.c encrypt.c udprelay.c cache.c \ acl.c netutils.c local.c $(obfs_src) $(sni_src) \ - $(am__append_11) + $(am__append_13) ss_tunnel_SOURCES = utils.c jconf.c json.c encrypt.c udprelay.c \ - cache.c netutils.c $(obfs_src) tunnel.c $(am__append_12) + cache.c netutils.c $(obfs_src) tunnel.c $(am__append_14) ss_server_SOURCES = utils.c \ netutils.c \ jconf.c \ @@ -511,12 +514,13 @@ ss_server_SOURCES = utils.c \ ss_manager_SOURCES = utils.c \ jconf.c \ json.c \ + netutils.c \ manager.c -ss_local_LDADD = $(SS_COMMON_LIBS) $(am__append_5) $(am__append_8) -ss_tunnel_LDADD = $(SS_COMMON_LIBS) $(am__append_6) $(am__append_9) -ss_server_LDADD = $(SS_COMMON_LIBS) $(am__append_7) $(am__append_10) -ss_manager_LDADD = $(SS_COMMON_LIBS) +ss_local_LDADD = $(SS_COMMON_LIBS) $(am__append_5) $(am__append_9) +ss_tunnel_LDADD = $(SS_COMMON_LIBS) $(am__append_6) $(am__append_10) +ss_server_LDADD = $(SS_COMMON_LIBS) $(am__append_7) $(am__append_11) +ss_manager_LDADD = $(SS_COMMON_LIBS) $(am__append_8) $(am__append_12) ss_local_CFLAGS = $(AM_CFLAGS) -DMODULE_LOCAL ss_tunnel_CFLAGS = $(AM_CFLAGS) -DMODULE_TUNNEL ss_server_CFLAGS = $(AM_CFLAGS) -DMODULE_REMOTE @@ -535,7 +539,7 @@ ss_manager_CFLAGS = $(AM_CFLAGS) -DMODULE_MANAGER @BUILD_REDIRECTOR_TRUE@ss_redir_CFLAGS = $(AM_CFLAGS) -DMODULE_REDIR @BUILD_REDIRECTOR_TRUE@ss_redir_LDADD = $(SS_COMMON_LIBS) \ -@BUILD_REDIRECTOR_TRUE@ $(am__append_14) $(am__append_15) +@BUILD_REDIRECTOR_TRUE@ $(am__append_16) $(am__append_17) lib_LTLIBRARIES = libshadowsocks-libev.la libshadowsocks_libev_la_SOURCES = $(ss_local_SOURCES) libshadowsocks_libev_la_CFLAGS = $(ss_local_CFLAGS) -DLIB_ONLY @@ -760,6 +764,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_manager-jconf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_manager-json.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_manager-manager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_manager-netutils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_manager-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_redir-base64.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ss_redir-cache.Po@am__quote@ @@ -1206,6 +1211,20 @@ ss_manager-json.obj: json.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_manager_CFLAGS) $(CFLAGS) -c -o ss_manager-json.obj `if test -f 'json.c'; then $(CYGPATH_W) 'json.c'; else $(CYGPATH_W) '$(srcdir)/json.c'; fi` +ss_manager-netutils.o: netutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_manager_CFLAGS) $(CFLAGS) -MT ss_manager-netutils.o -MD -MP -MF $(DEPDIR)/ss_manager-netutils.Tpo -c -o ss_manager-netutils.o `test -f 'netutils.c' || echo '$(srcdir)/'`netutils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_manager-netutils.Tpo $(DEPDIR)/ss_manager-netutils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netutils.c' object='ss_manager-netutils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_manager_CFLAGS) $(CFLAGS) -c -o ss_manager-netutils.o `test -f 'netutils.c' || echo '$(srcdir)/'`netutils.c + +ss_manager-netutils.obj: netutils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_manager_CFLAGS) $(CFLAGS) -MT ss_manager-netutils.obj -MD -MP -MF $(DEPDIR)/ss_manager-netutils.Tpo -c -o ss_manager-netutils.obj `if test -f 'netutils.c'; then $(CYGPATH_W) 'netutils.c'; else $(CYGPATH_W) '$(srcdir)/netutils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_manager-netutils.Tpo $(DEPDIR)/ss_manager-netutils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='netutils.c' object='ss_manager-netutils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_manager_CFLAGS) $(CFLAGS) -c -o ss_manager-netutils.obj `if test -f 'netutils.c'; then $(CYGPATH_W) 'netutils.c'; else $(CYGPATH_W) '$(srcdir)/netutils.c'; fi` + ss_manager-manager.o: manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ss_manager_CFLAGS) $(CFLAGS) -MT ss_manager-manager.o -MD -MP -MF $(DEPDIR)/ss_manager-manager.Tpo -c -o ss_manager-manager.o `test -f 'manager.c' || echo '$(srcdir)/'`manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ss_manager-manager.Tpo $(DEPDIR)/ss_manager-manager.Po diff --git a/src/manager.c b/src/manager.c index 9f7142e1..96afa8d1 100644 --- a/src/manager.c +++ b/src/manager.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -67,6 +66,7 @@ #include "json.h" #include "utils.h" #include "manager.h" +#include "netutils.h" #ifndef BUF_SIZE #define BUF_SIZE 65535 @@ -78,6 +78,7 @@ char *working_dir = NULL; int working_dir_size = 0; static struct cork_hash_table *server_table; +static struct cork_hash_table *sock_table; #ifndef __MINGW32__ static int @@ -313,16 +314,271 @@ parse_traffic(char *buf, int len, char *port, uint64_t *traffic) return 0; } +static int +create_and_bind(const char *host, const char *port, int protocol) +{ + struct addrinfo hints; + struct addrinfo *result, *rp, *ipv4v6bindall; + int s, listen_sock, is_port_reuse; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ + hints.ai_socktype = protocol == IPPROTO_TCP ? + SOCK_STREAM : SOCK_DGRAM; /* We want a TCP or UDP socket */ + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* For wildcard IP address */ + hints.ai_protocol = protocol; + + s = getaddrinfo(host, port, &hints, &result); + + if (s != 0) { + LOGE("getaddrinfo: %s", gai_strerror(s)); + return -1; + } + + rp = result; + + /* + * On Linux, with net.ipv6.bindv6only = 0 (the default), getaddrinfo(NULL) with + * AI_PASSIVE returns 0.0.0.0 and :: (in this order). AI_PASSIVE was meant to + * return a list of addresses to listen on, but it is impossible to listen on + * 0.0.0.0 and :: at the same time, if :: implies dualstack mode. + */ + if (!host) { + ipv4v6bindall = result; + + /* Loop over all address infos found until a IPV6 address is found. */ + while (ipv4v6bindall) { + if (ipv4v6bindall->ai_family == AF_INET6) { + rp = ipv4v6bindall; /* Take first IPV6 address available */ + break; + } + ipv4v6bindall = ipv4v6bindall->ai_next; /* Get next address info, if any */ + } + } + + for (/*rp = result*/; rp != NULL; rp = rp->ai_next) { + listen_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (listen_sock == -1) { + continue; + } + + if (rp->ai_family == AF_INET6) { + int ipv6only = host ? 1 : 0; + setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)); + } + + int opt = 1; + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); +#ifdef SO_NOSIGPIPE + setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif + /* Use port reuse to act as lock */ + int err = set_reuseport(listen_sock); + if (err == 0) { + if (verbose) { + LOGI("%s port reuse enabled", protocol == IPPROTO_TCP ? "tcp" : "udp"); + } + is_port_reuse = 1; + } + else { + is_port_reuse = 0; + } + + s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); + if (s == 0) { + /* We managed to bind successfully! */ + break; + } else { + ERROR("bind"); + } + + if (!is_port_reuse) { + if (verbose) { + LOGI("close sock due to %s port reuse disabled", protocol == IPPROTO_TCP ? "tcp" : "udp"); + } + close(listen_sock); + } + } + + if (!result) { + freeaddrinfo(result); + } + + if (rp == NULL) { + LOGE("Could not bind"); + return -1; + } + + return is_port_reuse ? listen_sock : -2; +} + static void +release_sock_lock(sock_lock_t *sock_lock) +{ + + ev_timer_stop(EV_DEFAULT, & sock_lock->watcher); + + while(--sock_lock->fd_count > -1) { + if (verbose) { + LOGI("close sock %d then remaining fd count is %d", + *(sock_lock->fds + sock_lock->fd_count), sock_lock->fd_count); + } + close(*(sock_lock->fds + sock_lock->fd_count)); + } + + if (verbose) { + LOGI("release sock lock: %s", sock_lock->port); + } + + ss_free(sock_lock->port); + ss_free(sock_lock->fds); + ss_free(sock_lock); +} + +static void +get_and_release_sock_lock(char* port) +{ + if (verbose) { + LOGI("try to get and release sock lock at port: %s", port); + } + + sock_lock_t *sock_lock = NULL; + bool ret = cork_hash_table_delete(sock_table, port, NULL, (void **)&sock_lock); + + if (ret) { + release_sock_lock(sock_lock); + } +} + +static void +sock_lock_timeout_cb(EV_P_ ev_timer *watcher, int revents) +{ + sock_lock_t *sock_lock = cork_container_of(watcher, sock_lock_t, watcher); + + cork_hash_table_delete(sock_table, sock_lock->port, NULL, NULL); + release_sock_lock(sock_lock); +} + +static sock_lock_t * +new_sock_lock(char *port, int *fds, int fd_count) +{ + if (verbose) { + LOGI("new sock lock with port: %s fd_count: %d", port, fd_count); + } + + sock_lock_t *sock_lock; + sock_lock = ss_malloc(sizeof(sock_lock_t)); + + memset(sock_lock, 0, sizeof(sock_lock_t)); + + sock_lock->port = ss_malloc(strlen(port) * sizeof(char)); + strcpy(sock_lock->port, port); + + sock_lock->fds = ss_malloc(fd_count * sizeof(int)); + memcpy(sock_lock->fds, fds, fd_count * sizeof(int)); + + sock_lock->fd_count = fd_count; + + /* use 128 as ss-server may use at most 128 seconds to query dns */ + ev_timer_init(& sock_lock->watcher, sock_lock_timeout_cb, 128., 0.); + ev_timer_start(EV_DEFAULT, & sock_lock->watcher); + + return sock_lock; +} + +static int +check_port(struct manager_ctx *manager, struct server *server) +{ + bool both_tcp_udp = manager->mode == TCP_AND_UDP; + int fd_count = manager->host_num * (both_tcp_udp ? 2 : 1); + int bind_err = 0; + + int *sock_fds = (int *)ss_malloc(fd_count * sizeof(int)); + memset(sock_fds, 0, fd_count * sizeof(int)); + + /* try to bind each interface */ + for (int i = 0; i < manager->host_num; i++) { + LOGI("try to bind interface: %s, port: %s", manager->hosts[i], server->port); + + if (manager->mode == UDP_ONLY) { + sock_fds[i] = create_and_bind(manager->hosts[i], server->port, IPPROTO_UDP); + } + else { + sock_fds[i] = create_and_bind(manager->hosts[i], server->port, IPPROTO_TCP); + } + + if (both_tcp_udp) { + sock_fds[i + manager->host_num] = create_and_bind(manager->hosts[i], server->port, IPPROTO_UDP); + } + + if (sock_fds[i] == -1 || (both_tcp_udp && sock_fds[i + manager->host_num] == -1)) { + bind_err = -1; + break; + } + else if (sock_fds[i] == -2 || (both_tcp_udp && sock_fds[i + manager->host_num] == -2)) { + /* continue to check all hosts */ + bind_err = -2; + } + } + + if (!bind_err) { + /* no err happened */ + if (verbose) { + LOGI("port check passed and locked"); + } + + sock_lock_t *sock_lock = new_sock_lock(server->port, sock_fds, fd_count); + + sock_lock_t *old_sock_lock = NULL; + bool new = false; + + cork_hash_table_put(sock_table, (void *)sock_lock->port, (void *)sock_lock, &new, NULL, (void **)&old_sock_lock); + + if (old_sock_lock) { + if (verbose) { + LOGI("release old sock lock after add new one to hash table"); + } + release_sock_lock(old_sock_lock); + } + } + else { + /* clean socks */ + for (int i = 0; i < fd_count; i++) { + if (sock_fds[i] > 0) { + close(sock_fds[i]); + } + } + } + + ss_free(sock_fds); + + if (bind_err == -2) { + LOGI("port is avaiable but can not be locked"); + } + + return bind_err == -1 ? -1 : 0; +} + +static int add_server(struct manager_ctx *manager, struct server *server) { + int ret = check_port(manager, server); + + if (ret == -1) { + LOGE("port is not available, please check."); + return -1; + } + bool new = false; cork_hash_table_put(server_table, (void *)server->port, (void *)server, &new, NULL, NULL); char *cmd = construct_command_line(manager, server); if (system(cmd) == -1) { ERROR("add_server_system"); + return -1; } + + return 0; } static void @@ -435,10 +691,21 @@ manager_recv_cb(EV_P_ ev_io *w, int revents) } remove_server(working_dir, server->port); - add_server(manager, server); + int ret = add_server(manager, server); - char msg[3] = "ok"; - if (sendto(manager->fd, msg, 2, 0, (struct sockaddr *)&claddr, len) != 2) { + char *msg; + int msg_len; + + if (ret == -1) { + msg = "port is not available"; + msg_len = 21; + } + else { + msg = "ok"; + msg_len = 2; + } + + if (sendto(manager->fd, msg, msg_len, 0, (struct sockaddr *)&claddr, len) != 2) { ERROR("add_sendto"); } } else if (strcmp(action, "remove") == 0) { @@ -469,6 +736,7 @@ manager_recv_cb(EV_P_ ev_io *w, int revents) } update_stat(port, traffic); + get_and_release_sock_lock(port); } else if (strcmp(action, "ping") == 0) { struct cork_hash_table_entry *entry; struct cork_hash_table_iterator server_iter; @@ -914,6 +1182,7 @@ main(int argc, char **argv) } server_table = cork_string_hash_table_new(MAX_PORT_NUM, 0); + sock_table = cork_string_hash_table_new(MAX_PORT_NUM, 0); if (conf != NULL) { for (i = 0; i < conf->port_password_num; i++) { @@ -976,6 +1245,7 @@ main(int argc, char **argv) // Clean up struct cork_hash_table_entry *entry; struct cork_hash_table_iterator server_iter; + struct cork_hash_table_iterator sock_iter; cork_hash_table_iterator_init(server_table, &server_iter); @@ -984,6 +1254,13 @@ main(int argc, char **argv) stop_server(working_dir, server->port); } + cork_hash_table_iterator_init(sock_table, &sock_iter); + + while ((entry = cork_hash_table_iterator_next(&sock_iter)) != NULL) { + sock_lock_t *sock_lock = (sock_lock_t *)entry->value; + release_sock_lock(sock_lock); + } + #ifdef __MINGW32__ winsock_cleanup(); #endif diff --git a/src/manager.h b/src/manager.h index c667ae5f..86eb61dd 100644 --- a/src/manager.h +++ b/src/manager.h @@ -63,4 +63,11 @@ struct server { uint64_t traffic; }; +typedef struct sock_lock { + char *port; + int *fds; + int fd_count; + ev_timer watcher; +} sock_lock_t; + #endif // _MANAGER_H