Use SO_REUSEPORT

Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
main^2
Jianhui Zhao 2021-01-03 21:53:20 +08:00
parent b2ce003bcc
commit db85c135cb
4 changed files with 85 additions and 21 deletions

View File

@ -27,7 +27,6 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <netdb.h> #include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h> #include <sys/socket.h>
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
#include <dlfcn.h> #include <dlfcn.h>
@ -145,6 +144,40 @@ static void uh_worker_exit(struct ev_loop *loop, struct ev_child *w, int revents
free(wk); free(wk);
} }
static int uh_socket(int family)
{
int on = 1;
int sock;
sock = socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (sock < 0) {
uh_log_err("socket: %s\n", strerror(errno));
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) {
uh_log_err("setsockopt: %s\n", strerror(errno));
close(sock);
return -1;
}
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
return sock;
}
static int uh_listen(int sock, struct sockaddr *addr, socklen_t addrlen)
{
if (bind(sock, addr, addrlen) < 0) {
uh_log_err("bind: %s\n", strerror(errno));
return -1;
}
listen(sock, SOMAXCONN);
return 0;
}
static void uh_start_worker(struct uh_server *srv, int n) static void uh_start_worker(struct uh_server *srv, int n)
{ {
struct uh_server_internal *srvi = (struct uh_server_internal *)srv; struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
@ -159,6 +192,9 @@ static void uh_start_worker(struct uh_server *srv, int n)
uh_stop_accept(srvi); uh_stop_accept(srvi);
if (srvi->reuseport)
close(srvi->sock);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
pids[i] = fork(); pids[i] = fork();
switch (pids[i]) { switch (pids[i]) {
@ -167,6 +203,12 @@ static void uh_start_worker(struct uh_server *srv, int n)
return; return;
case 0: case 0:
ev_loop_fork(srvi->loop); ev_loop_fork(srvi->loop);
if (srvi->reuseport) {
srvi->sock = uh_socket(srvi->addr.sa.sa_family);
uh_listen(srvi->sock, &srvi->addr.sa, srvi->addrlen);
}
uh_start_accept(srvi); uh_start_accept(srvi);
uh_log_info("worker %d started\n", i); uh_log_info("worker %d started\n", i);
@ -337,7 +379,6 @@ int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host
char addr_str[INET6_ADDRSTRLEN]; char addr_str[INET6_ADDRSTRLEN];
socklen_t addrlen; socklen_t addrlen;
int sock = -1; int sock = -1;
int on = 1;
if (!host || *host == '\0') { if (!host || *host == '\0') {
addr.sin.sin_family = AF_INET; addr.sin.sin_family = AF_INET;
@ -377,34 +418,31 @@ int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host
inet_ntop(AF_INET6, &addr.sin6.sin6_addr, addr_str, sizeof(addr_str)); inet_ntop(AF_INET6, &addr.sin6.sin6_addr, addr_str, sizeof(addr_str));
} }
sock = socket(addr.sa.sa_family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); memset(srvi, 0, sizeof(struct uh_server_internal));
if (sock < 0) {
uh_log_err("socket: %s\n", strerror(errno)); srvi->loop = loop ? loop : EV_DEFAULT;
srvi->reuseport = support_so_reuseport();
sock = uh_socket(addr.sa.sa_family);
if (sock < 0)
return -1; return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) { if (uh_listen(sock, &addr.sa, addrlen) < 0)
uh_log_err("setsockopt: %s\n", strerror(errno));
goto err; goto err;
}
if (bind(sock, &addr.sa, addrlen) < 0) { srvi->sock = sock;
close(sock);
uh_log_err("bind: %s\n", strerror(errno));
goto err;
}
listen(sock, SOMAXCONN); uh_start_accept(srvi);
srvi->addrlen = addrlen;
memcpy(&srvi->addr, &addr, sizeof(addr));
if (uh_log_get_threshold() == LOG_DEBUG) { if (uh_log_get_threshold() == LOG_DEBUG) {
saddr2str(&addr.sa, addr_str, sizeof(addr_str), &port); saddr2str(&addr.sa, addr_str, sizeof(addr_str), &port);
uh_log_debug("Listen on: %s %d\n", addr_str, port); uh_log_debug("Listen on: %s %d\n", addr_str, port);
} }
memset(srvi, 0, sizeof(struct uh_server_internal));
srvi->loop = loop ? loop : EV_DEFAULT;
srvi->sock = sock;
srv->free = uh_server_free; srv->free = uh_server_free;
srv->start_worker = uh_start_worker; srv->start_worker = uh_start_worker;
@ -420,8 +458,6 @@ int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host
srv->set_docroot = uh_set_docroot; srv->set_docroot = uh_set_docroot;
srv->set_index_page = uh_set_index_page; srv->set_index_page = uh_set_index_page;
uh_start_accept(srvi);
return 0; return 0;
err: err:

View File

@ -25,6 +25,8 @@
#ifndef LIBUHTTPD_UHTTPD_INTERNAL_H #ifndef LIBUHTTPD_UHTTPD_INTERNAL_H
#define LIBUHTTPD_UHTTPD_INTERNAL_H #define LIBUHTTPD_UHTTPD_INTERNAL_H
#include <arpa/inet.h>
#include "uhttpd.h" #include "uhttpd.h"
struct uh_connection_internal; struct uh_connection_internal;
@ -32,6 +34,13 @@ struct uh_connection_internal;
struct uh_server_internal { struct uh_server_internal {
struct uh_server com; struct uh_server com;
int sock; int sock;
bool reuseport;
union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} addr;
socklen_t addrlen;
char *docroot; char *docroot;
char *index_page; char *index_page;
struct ev_loop *loop; struct ev_loop *loop;

View File

@ -27,6 +27,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <unistd.h>
#include "utils.h" #include "utils.h"
@ -44,3 +45,19 @@ const char *saddr2str(struct sockaddr *addr, char buf[], int len, int *port)
return buf; return buf;
} }
bool support_so_reuseport()
{
bool ok = false;
int on = 1;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (!setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int)))
ok = true;
close(sock);
return ok;
}

View File

@ -41,4 +41,6 @@
const char *saddr2str(struct sockaddr *addr, char buf[], int len, int *port); const char *saddr2str(struct sockaddr *addr, char buf[], int len, int *port);
bool support_so_reuseport();
#endif #endif