|
|
@ -71,7 +71,6 @@ char *working_dir = NULL; |
|
|
|
int working_dir_size = 0; |
|
|
|
|
|
|
|
static struct cork_hash_table *server_table; |
|
|
|
static struct cork_hash_table *sock_table; |
|
|
|
|
|
|
|
static int |
|
|
|
setnonblocking(int fd) |
|
|
@ -350,7 +349,7 @@ create_and_bind(const char *host, const char *port, int protocol) |
|
|
|
{ |
|
|
|
struct addrinfo hints; |
|
|
|
struct addrinfo *result, *rp, *ipv4v6bindall; |
|
|
|
int s, listen_sock = -1, is_reuse_port = 0; |
|
|
|
int s, listen_sock = -1; |
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(struct addrinfo)); |
|
|
|
hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ |
|
|
@ -403,25 +402,12 @@ create_and_bind(const char *host, const char *port, int protocol) |
|
|
|
#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_reuse_port = 1; |
|
|
|
} |
|
|
|
|
|
|
|
s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); |
|
|
|
if (s == 0) { |
|
|
|
/* We managed to bind successfully! */ |
|
|
|
|
|
|
|
if (!is_reuse_port) { |
|
|
|
if (verbose) { |
|
|
|
LOGI("close sock due to %s port reuse disabled", protocol == IPPROTO_TCP ? "tcp" : "udp"); |
|
|
|
} |
|
|
|
close(listen_sock); |
|
|
|
} |
|
|
|
close(listen_sock); |
|
|
|
|
|
|
|
break; |
|
|
|
} else { |
|
|
@ -438,80 +424,7 @@ create_and_bind(const char *host, const char *port, int protocol) |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
return is_reuse_port ? 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 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; |
|
|
|
return listen_sock; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
@ -541,45 +454,18 @@ check_port(struct manager_ctx *manager, struct server *server) |
|
|
|
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); |
|
|
|
/* clean socks */ |
|
|
|
for (int i = 0; i < fd_count; i++) { |
|
|
|
if (sock_fds[i] > 0) { |
|
|
|
close(sock_fds[i]); |
|
|
|
} |
|
|
|
} 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 available but can not be locked"); |
|
|
|
} |
|
|
|
|
|
|
|
return bind_err == -1 ? -1 : 0; |
|
|
|
} |
|
|
|
|
|
|
@ -799,7 +685,6 @@ 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; |
|
|
@ -1250,7 +1135,6 @@ 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++) { |
|
|
@ -1313,7 +1197,6 @@ 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); |
|
|
|
|
|
|
@ -1322,13 +1205,6 @@ 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); |
|
|
|
} |
|
|
|
|
|
|
|
ev_signal_stop(EV_DEFAULT, &sigint_watcher); |
|
|
|
ev_signal_stop(EV_DEFAULT, &sigterm_watcher); |
|
|
|
ss_free(working_dir); |
|
|
|