parent
175f7c8f55
commit
9166d3ab80
|
@ -59,9 +59,8 @@ static void usage(const char *prog)
|
||||||
fprintf(stderr, "Usage: %s [option]\n"
|
fprintf(stderr, "Usage: %s [option]\n"
|
||||||
" -h docroot # Document root, default is .\n"
|
" -h docroot # Document root, default is .\n"
|
||||||
" -i index_page # Index page, default is index.html\n"
|
" -i index_page # Index page, default is index.html\n"
|
||||||
" -a addr # Default addr is localhost\n"
|
" -a addr # address to listen\n"
|
||||||
" -p port # Default port is 8080\n"
|
" -s addr # address to listen with ssl\n"
|
||||||
" -s # SSl on\n"
|
|
||||||
" -P # plugin path\n"
|
" -P # plugin path\n"
|
||||||
" -w # worker process number, default is equal to available CPUs\n"
|
" -w # worker process number, default is equal to available CPUs\n"
|
||||||
" -v # verbose\n", prog);
|
" -v # verbose\n", prog);
|
||||||
|
@ -75,16 +74,17 @@ int main(int argc, char **argv)
|
||||||
struct uh_server *srv = NULL;
|
struct uh_server *srv = NULL;
|
||||||
const char *plugin_path = NULL;
|
const char *plugin_path = NULL;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool ssl = false;
|
|
||||||
const char *docroot = ".";
|
const char *docroot = ".";
|
||||||
const char *index_page = "index.html";
|
const char *index_page = "index.html";
|
||||||
const char *addr = "localhost";
|
|
||||||
pid_t workers[MAX_WORKER] = {};
|
pid_t workers[MAX_WORKER] = {};
|
||||||
int nworker = get_nprocs();
|
int nworker = get_nprocs();
|
||||||
int port = 8080;
|
|
||||||
int opt, i;
|
int opt, i;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "h:i:a:p:sfP:w:v")) != -1) {
|
srv = uh_server_new(loop);
|
||||||
|
if (!srv)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "h:i:a:s:P:w:v")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
docroot = optarg;
|
docroot = optarg;
|
||||||
|
@ -93,13 +93,12 @@ int main(int argc, char **argv)
|
||||||
index_page = optarg;
|
index_page = optarg;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
addr = optarg;
|
if (srv->listen(srv, optarg, false) < 1)
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 's':
|
||||||
port = atoi(optarg);
|
if (srv->listen(srv, optarg, true) < 1)
|
||||||
break;
|
goto err;
|
||||||
case 's':
|
|
||||||
ssl = true;
|
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
plugin_path = optarg;
|
plugin_path = optarg;
|
||||||
|
@ -124,13 +123,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
srv = uh_server_new(loop, addr, port);
|
|
||||||
if (!srv)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
if (ssl && srv->ssl_init(srv, "server-cert.pem", "server-key.pem") < 0)
|
srv->ssl_init(srv, "cert.pem", "key.pem");
|
||||||
goto err;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
srv->set_docroot(srv, docroot);
|
srv->set_docroot(srv, docroot);
|
||||||
|
|
|
@ -58,28 +58,37 @@ static void usage(const char *prog)
|
||||||
fprintf(stderr, "Usage: %s [option]\n"
|
fprintf(stderr, "Usage: %s [option]\n"
|
||||||
" -h docroot # Document root, default is .\n"
|
" -h docroot # Document root, default is .\n"
|
||||||
" -i index_page # Index page, default is index.html\n"
|
" -i index_page # Index page, default is index.html\n"
|
||||||
" -a addr # Default addr is localhost\n"
|
" -a addr # address to listen\n"
|
||||||
" -p port # Default port is 8080\n"
|
" -s addr # address to listen with ssl\n"
|
||||||
" -s # SSl on\n"
|
|
||||||
" -P # plugin path\n"
|
" -P # plugin path\n"
|
||||||
" -w # worker process number, default is equal to available CPUs\n"
|
" -w # worker process number, default is equal to available CPUs\n"
|
||||||
" -v # verbose\n", prog);
|
" -v # verbose\n", prog);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_server(const char *addr, int port, const char *docroot, const char *index_page, const char *plugin, bool ssl)
|
static void start_server(const char *addr, const char *addrs, const char *docroot, const char *index_page, const char *plugin, bool ssl)
|
||||||
{
|
{
|
||||||
struct ev_loop *loop = ev_loop_new(0);
|
struct ev_loop *loop = ev_loop_new(0);
|
||||||
struct uh_server *srv = NULL;
|
struct uh_server *srv = NULL;
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
srv = uh_server_new(loop, addr, port);
|
srv = uh_server_new(loop);
|
||||||
if (!srv)
|
if (!srv)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (addr) {
|
||||||
|
if (srv->listen(srv, addrs, false) < 0)
|
||||||
|
return;
|
||||||
|
} else if (addrs) {
|
||||||
|
if (srv->listen(srv, addrs, true) < 0)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
if (ssl && srv->ssl_init(srv, "server-cert.pem", "server-key.pem") < 0)
|
if (ssl && srv->ssl_init(srv, "cert.pem", "key.pem") < 0)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -105,13 +114,13 @@ int main(int argc, char **argv)
|
||||||
bool ssl = false;
|
bool ssl = false;
|
||||||
const char *docroot = ".";
|
const char *docroot = ".";
|
||||||
const char *index_page = "index.html";
|
const char *index_page = "index.html";
|
||||||
const char *addr = "localhost";
|
const char *addr = NULL;
|
||||||
|
const char *addrs = NULL;
|
||||||
pid_t workers[MAX_WORKER] = {};
|
pid_t workers[MAX_WORKER] = {};
|
||||||
int nworker = get_nprocs();
|
int nworker = get_nprocs();
|
||||||
int port = 8080;
|
|
||||||
int opt, i;
|
int opt, i;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "h:i:a:p:sP:w:v")) != -1) {
|
while ((opt = getopt(argc, argv, "h:i:a:s:P:w:v")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
docroot = optarg;
|
docroot = optarg;
|
||||||
|
@ -122,11 +131,8 @@ int main(int argc, char **argv)
|
||||||
case 'a':
|
case 'a':
|
||||||
addr = optarg;
|
addr = optarg;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
|
||||||
port = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case 's':
|
case 's':
|
||||||
ssl = true;
|
addrs = optarg;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
plugin_path = optarg;
|
plugin_path = optarg;
|
||||||
|
@ -164,7 +170,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||||
start_server(addr, port, docroot, index_page, plugin_path, ssl);
|
start_server(addr, addrs, docroot, index_page, plugin_path, ssl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,8 @@ static void usage(const char *prog)
|
||||||
fprintf(stderr, "Usage: %s [option]\n"
|
fprintf(stderr, "Usage: %s [option]\n"
|
||||||
" -h docroot # Document root, default is .\n"
|
" -h docroot # Document root, default is .\n"
|
||||||
" -i index_page # Index page, default is index.html\n"
|
" -i index_page # Index page, default is index.html\n"
|
||||||
" -a addr # Default addr is localhost\n"
|
" -a addr # address to listen\n"
|
||||||
" -p port # Default port is 8080\n"
|
" -s addr # address to listen with ssl\n"
|
||||||
" -s # SSl on\n"
|
|
||||||
" -P # plugin path\n"
|
" -P # plugin path\n"
|
||||||
" -v # verbose\n", prog);
|
" -v # verbose\n", prog);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -63,14 +62,15 @@ int main(int argc, char **argv)
|
||||||
struct uh_server *srv = NULL;
|
struct uh_server *srv = NULL;
|
||||||
const char *plugin_path = NULL;
|
const char *plugin_path = NULL;
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
bool ssl = false;
|
|
||||||
const char *docroot = ".";
|
const char *docroot = ".";
|
||||||
const char *index_page = "index.html";
|
const char *index_page = "index.html";
|
||||||
const char *addr = "localhost";
|
|
||||||
int port = 8080;
|
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "h:i:a:p:sP:v")) != -1) {
|
srv = uh_server_new(loop);
|
||||||
|
if (!srv)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "h:i:a:s:P:v")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
docroot = optarg;
|
docroot = optarg;
|
||||||
|
@ -79,13 +79,12 @@ int main(int argc, char **argv)
|
||||||
index_page = optarg;
|
index_page = optarg;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
addr = optarg;
|
if (srv->listen(srv, optarg, false) < 1)
|
||||||
|
goto err;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 's':
|
||||||
port = atoi(optarg);
|
if (srv->listen(srv, optarg, true) < 1)
|
||||||
break;
|
goto err;
|
||||||
case 's':
|
|
||||||
ssl = true;
|
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
plugin_path = optarg;
|
plugin_path = optarg;
|
||||||
|
@ -93,7 +92,7 @@ int main(int argc, char **argv)
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
default: /* '?' */
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,13 +104,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
srv = uh_server_new(loop, addr, port);
|
|
||||||
if (!srv)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
if (ssl && srv->ssl_init(srv, "server-cert.pem", "server-key.pem") < 0)
|
srv->ssl_init(srv, "cert.pem", "key.pem");
|
||||||
goto err;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
srv->set_docroot(srv, docroot);
|
srv->set_docroot(srv, docroot);
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
openssl req -x509 -newkey rsa:2048 -nodes -keyout server-key.pem -out server-cert.pem -subj "/C=CZ/O=Acme Inc./OU=ACME/CN=ACME-DEV-123"
|
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -subj "/C=CZ/O=Acme Inc./OU=ACME/CN=ACME-DEV-123"
|
||||||
|
|
|
@ -794,8 +794,9 @@ static void conn_init_cb(struct uh_connection *conn)
|
||||||
conn->close = conn_close;
|
conn->close = conn_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct uh_connection_internal *uh_new_connection(struct uh_server_internal *srv, int sock, struct sockaddr *addr)
|
struct uh_connection_internal *uh_new_connection(struct uh_listener *l, int sock, struct sockaddr *addr)
|
||||||
{
|
{
|
||||||
|
struct uh_server_internal *srv = l->srv;
|
||||||
struct uh_connection_internal *conn;
|
struct uh_connection_internal *conn;
|
||||||
|
|
||||||
conn = calloc(1, sizeof(struct uh_connection_internal));
|
conn = calloc(1, sizeof(struct uh_connection_internal));
|
||||||
|
@ -822,7 +823,7 @@ struct uh_connection_internal *uh_new_connection(struct uh_server_internal *srv,
|
||||||
ev_timer_start(srv->loop, &conn->timer);
|
ev_timer_start(srv->loop, &conn->timer);
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
if (srv->ssl_ctx)
|
if (l->ssl)
|
||||||
conn->ssl = uh_ssl_new(srv->ssl_ctx, sock);
|
conn->ssl = uh_ssl_new(srv->ssl_ctx, sock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ struct uh_connection_internal {
|
||||||
void (*handler)(struct uh_connection *conn, int event);
|
void (*handler)(struct uh_connection *conn, int event);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uh_connection_internal *uh_new_connection(struct uh_server_internal *srv, int sock, struct sockaddr *addr);
|
struct uh_connection_internal *uh_new_connection(struct uh_listener *l, int sock, struct sockaddr *addr);
|
||||||
|
|
||||||
void conn_free(struct uh_connection_internal *conn);
|
void conn_free(struct uh_connection_internal *conn);
|
||||||
|
|
||||||
|
|
247
src/uhttpd.c
247
src/uhttpd.c
|
@ -42,15 +42,11 @@ static void uh_server_free(struct uh_server *srv)
|
||||||
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
||||||
struct uh_connection_internal *conn = srvi->conns;
|
struct uh_connection_internal *conn = srvi->conns;
|
||||||
struct uh_path_handler *h = srvi->handlers;
|
struct uh_path_handler *h = srvi->handlers;
|
||||||
|
struct uh_listener *l = srvi->listeners;
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
struct uh_plugin *p = srvi->plugins;
|
struct uh_plugin *p = srvi->plugins;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ev_io_stop(srvi->loop, &srvi->ior);
|
|
||||||
|
|
||||||
if (srvi->sock > 0)
|
|
||||||
close(srvi->sock);
|
|
||||||
|
|
||||||
if (srvi->docroot)
|
if (srvi->docroot)
|
||||||
free(srvi->docroot);
|
free(srvi->docroot);
|
||||||
|
|
||||||
|
@ -69,6 +65,18 @@ static void uh_server_free(struct uh_server *srv)
|
||||||
free(temp);
|
free(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (l) {
|
||||||
|
struct uh_listener *temp = l;
|
||||||
|
|
||||||
|
ev_io_stop(srvi->loop, &l->ior);
|
||||||
|
|
||||||
|
if (l->sock > 0)
|
||||||
|
close(l->sock);
|
||||||
|
|
||||||
|
l = l->next;
|
||||||
|
free(temp);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
while (p) {
|
while (p) {
|
||||||
struct uh_plugin *temp = p;
|
struct uh_plugin *temp = p;
|
||||||
|
@ -85,7 +93,8 @@ static void uh_server_free(struct uh_server *srv)
|
||||||
|
|
||||||
static void uh_accept_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
static void uh_accept_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
{
|
{
|
||||||
struct uh_server_internal *srv = container_of(w, struct uh_server_internal, ior);
|
struct uh_listener *l = container_of(w, struct uh_listener, ior);
|
||||||
|
struct uh_server_internal *srv = l->srv;
|
||||||
struct uh_connection_internal *conn;
|
struct uh_connection_internal *conn;
|
||||||
union {
|
union {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
|
@ -97,7 +106,7 @@ static void uh_accept_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
int port;
|
int port;
|
||||||
int sock;
|
int sock;
|
||||||
|
|
||||||
sock = accept4(srv->sock, (struct sockaddr *)&addr, &addr_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
sock = accept4(l->sock, (struct sockaddr *)&addr, &addr_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
if (errno != EAGAIN)
|
if (errno != EAGAIN)
|
||||||
uh_log_err("accept: %s\n", strerror(errno));
|
uh_log_err("accept: %s\n", strerror(errno));
|
||||||
|
@ -109,7 +118,21 @@ static void uh_accept_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
uh_log_debug("New Connection from: %s %d\n", addr_str, port);
|
uh_log_debug("New Connection from: %s %d\n", addr_str, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = uh_new_connection(srv, sock, &addr.sa);
|
if (l->ssl) {
|
||||||
|
#if UHTTPD_SSL_SUPPORT
|
||||||
|
if (!srv->ssl_ctx) {
|
||||||
|
uh_log_err("SSL not initialized\n");
|
||||||
|
close(sock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
close(sock);
|
||||||
|
uh_log_err("SSL not enabled when build\n");
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = uh_new_connection(l, sock, &addr.sa);
|
||||||
if (!conn)
|
if (!conn)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -123,7 +146,7 @@ static void uh_accept_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||||
srv->conns = conn;
|
srv->conns = conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct uh_server *uh_server_new(struct ev_loop *loop, const char *host, int port)
|
struct uh_server *uh_server_new(struct ev_loop *loop)
|
||||||
{
|
{
|
||||||
struct uh_server *srv;
|
struct uh_server *srv;
|
||||||
|
|
||||||
|
@ -133,10 +156,7 @@ struct uh_server *uh_server_new(struct ev_loop *loop, const char *host, int port
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uh_server_init(srv, loop, host, port) < 0) {
|
uh_server_init(srv, loop);
|
||||||
free(srv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return srv;
|
return srv;
|
||||||
}
|
}
|
||||||
|
@ -279,93 +299,155 @@ static struct ev_loop *uh_get_loop(struct uh_server *srv)
|
||||||
return srvi->loop;
|
return srvi->loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host, int port)
|
static int parse_address(const char *addr, char **host, char **port)
|
||||||
|
{
|
||||||
|
static char buf[256];
|
||||||
|
char *s;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
strcpy(buf, addr);
|
||||||
|
|
||||||
|
*host = NULL;
|
||||||
|
*port = buf;
|
||||||
|
|
||||||
|
s = strrchr(buf, ':');
|
||||||
|
if (!s)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*host = buf;
|
||||||
|
*port = s + 1;
|
||||||
|
*s = 0;
|
||||||
|
|
||||||
|
if (*host && **host == '[') {
|
||||||
|
l = strlen(*host);
|
||||||
|
if (l >= 2) {
|
||||||
|
(*host)[l - 1] = 0;
|
||||||
|
(*host)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*host)[0] == '\0')
|
||||||
|
*host = "0";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uh_server_listen(struct uh_server *srv, const char *addr, bool ssl)
|
||||||
{
|
{
|
||||||
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
||||||
union {
|
struct uh_listener *l;
|
||||||
struct sockaddr sa;
|
char *host, *port;
|
||||||
struct sockaddr_in sin;
|
struct addrinfo *addrs = NULL, *p = NULL;
|
||||||
struct sockaddr_in6 sin6;
|
static struct addrinfo hints = {
|
||||||
} addr;
|
.ai_family = AF_UNSPEC,
|
||||||
|
.ai_socktype = SOCK_STREAM,
|
||||||
|
.ai_flags = AI_PASSIVE,
|
||||||
|
};
|
||||||
char addr_str[INET6_ADDRSTRLEN];
|
char addr_str[INET6_ADDRSTRLEN];
|
||||||
socklen_t addrlen;
|
int bound = 0;
|
||||||
int sock = -1;
|
|
||||||
int on = 1;
|
int on = 1;
|
||||||
|
int status;
|
||||||
|
int sock;
|
||||||
|
|
||||||
if (!host || *host == '\0') {
|
if (parse_address(addr, &host, &port) < 0) {
|
||||||
addr.sin.sin_family = AF_INET;
|
uh_log_err("invalid address\n");
|
||||||
addr.sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inet_pton(AF_INET, host, &addr.sin.sin_addr) == 1) {
|
|
||||||
addr.sa.sa_family = AF_INET;
|
|
||||||
} else if (inet_pton(AF_INET6, host, &addr.sin6.sin6_addr) == 1) {
|
|
||||||
addr.sa.sa_family = AF_INET6;
|
|
||||||
} else {
|
|
||||||
static struct addrinfo hints = {
|
|
||||||
.ai_family = AF_UNSPEC,
|
|
||||||
.ai_socktype = SOCK_STREAM,
|
|
||||||
.ai_flags = AI_PASSIVE
|
|
||||||
};
|
|
||||||
struct addrinfo *ais;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
status = getaddrinfo(host, NULL, &hints, &ais);
|
|
||||||
if (status != 0) {
|
|
||||||
uh_log_err("getaddrinfo(): %s\n", gai_strerror(status));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&addr, ais->ai_addr, ais->ai_addrlen);
|
|
||||||
freeaddrinfo(ais);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addr.sa.sa_family == AF_INET) {
|
|
||||||
addr.sin.sin_port = ntohs(port);
|
|
||||||
addrlen = sizeof(addr.sin);
|
|
||||||
inet_ntop(AF_INET, &addr.sin.sin_addr, addr_str, sizeof(addr_str));
|
|
||||||
} else {
|
|
||||||
addr.sin6.sin6_port = ntohs(port);
|
|
||||||
addrlen = sizeof(addr.sin6);
|
|
||||||
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);
|
|
||||||
if (sock < 0) {
|
|
||||||
uh_log_err("socket: %s\n", strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) {
|
status = getaddrinfo(host, port, &hints, &addrs);
|
||||||
uh_log_err("setsockopt: %s\n", strerror(errno));
|
if (status != 0) {
|
||||||
goto err;
|
uh_log_err("getaddrinfo(): %s\n", gai_strerror(status));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
|
/* try to bind a new socket to each found address */
|
||||||
|
for (p = addrs; p; p = p->ai_next) {
|
||||||
|
sock = socket(p->ai_family, p->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC, p->ai_protocol);
|
||||||
|
if (sock < 0) {
|
||||||
|
uh_log_err("socket: %s\n", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (bind(sock, &addr.sa, addrlen) < 0) {
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) {
|
||||||
uh_log_err("bind: %s\n", strerror(errno));
|
uh_log_err("setsockopt: %s\n", strerror(errno));
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* required to get parallel v4 + v6 working */
|
||||||
|
if (p->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) < 0) {
|
||||||
|
uh_log_err("setsockopt: %s\n", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
|
||||||
|
|
||||||
|
if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) {
|
||||||
|
uh_log_err("bind: %s\n", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sock, SOMAXCONN) < 0) {
|
||||||
|
uh_log_err("bind: %s\n", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = calloc(1, sizeof(struct uh_listener));
|
||||||
|
if (!l) {
|
||||||
|
uh_log_err("calloc: %s\n", strerror(errno));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->sock = sock;
|
||||||
|
l->ssl = ssl;
|
||||||
|
l->srv = srvi;
|
||||||
|
|
||||||
|
ev_io_init(&l->ior, uh_accept_cb, sock, EV_READ);
|
||||||
|
ev_io_start(srvi->loop, &l->ior);
|
||||||
|
|
||||||
|
if (!srvi->listeners) {
|
||||||
|
srvi->listeners = l;
|
||||||
|
} else {
|
||||||
|
l->next = srvi->listeners;
|
||||||
|
srvi->listeners = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->ai_family == AF_INET) {
|
||||||
|
struct sockaddr_in *ina = (struct sockaddr_in *)p->ai_addr;
|
||||||
|
inet_ntop(p->ai_family, &ina->sin_addr, addr_str, sizeof(addr_str));
|
||||||
|
uh_log_debug("Listen on: %s:%d with ssl %s\n", addr_str, ntohs(ina->sin_port), ssl ? "on" : "off");
|
||||||
|
} else {
|
||||||
|
struct sockaddr_in6 *in6a = (struct sockaddr_in6 *)p->ai_addr;
|
||||||
|
inet_ntop(p->ai_family, &in6a->sin6_addr, addr_str, sizeof(addr_str));
|
||||||
|
uh_log_debug("Listen on: [%s]:%d with ssl %s\n", addr_str, ntohs(in6a->sin6_port), ssl ? "on" : "off");
|
||||||
|
}
|
||||||
|
|
||||||
|
bound++;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (sock > -1)
|
||||||
|
close(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listen(sock, SOMAXCONN) < 0) {
|
freeaddrinfo(addrs);
|
||||||
uh_log_err("bind: %s\n", strerror(errno));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uh_log_get_threshold() == LOG_DEBUG) {
|
return bound;
|
||||||
saddr2str(&addr.sa, addr_str, sizeof(addr_str), &port);
|
}
|
||||||
uh_log_debug("Listen on: %s %d\n", addr_str, port);
|
|
||||||
}
|
void uh_server_init(struct uh_server *srv, struct ev_loop *loop)
|
||||||
|
{
|
||||||
|
struct uh_server_internal *srvi = (struct uh_server_internal *)srv;
|
||||||
|
|
||||||
memset(srvi, 0, sizeof(struct uh_server_internal));
|
memset(srvi, 0, sizeof(struct uh_server_internal));
|
||||||
|
|
||||||
srvi->loop = loop ? loop : EV_DEFAULT;
|
srvi->loop = loop ? loop : EV_DEFAULT;
|
||||||
srvi->sock = sock;
|
|
||||||
|
|
||||||
srv->get_loop = uh_get_loop;
|
srv->get_loop = uh_get_loop;
|
||||||
srv->free = uh_server_free;
|
srv->free = uh_server_free;
|
||||||
|
|
||||||
|
srv->listen = uh_server_listen;
|
||||||
|
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
srv->ssl_init = uh_server_ssl_init;
|
srv->ssl_init = uh_server_ssl_init;
|
||||||
#endif
|
#endif
|
||||||
|
@ -378,13 +460,4 @@ 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;
|
||||||
|
|
||||||
ev_io_init(&srvi->ior, uh_accept_cb, sock, EV_READ);
|
|
||||||
ev_io_start(srvi->loop, &srvi->ior);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
close(sock);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
14
src/uhttpd.h
14
src/uhttpd.h
|
@ -89,6 +89,14 @@ typedef void (*uh_path_handler_prototype)(struct uh_connection *conn, int event)
|
||||||
struct uh_server {
|
struct uh_server {
|
||||||
struct ev_loop *(*get_loop)(struct uh_server *srv);
|
struct ev_loop *(*get_loop)(struct uh_server *srv);
|
||||||
void (*free)(struct uh_server *srv);
|
void (*free)(struct uh_server *srv);
|
||||||
|
/*
|
||||||
|
** listen an address, multiple call allowed
|
||||||
|
** returns the number of successful listen
|
||||||
|
**
|
||||||
|
** :80 0:80 0.0.0.0:80 [::]:80
|
||||||
|
** localhost:80 [::1]:80
|
||||||
|
*/
|
||||||
|
int (*listen)(struct uh_server *srv, const char *addr, bool ssl);
|
||||||
#if UHTTPD_SSL_SUPPORT
|
#if UHTTPD_SSL_SUPPORT
|
||||||
int (*ssl_init)(struct uh_server *srv, const char *cert, const char *key);
|
int (*ssl_init)(struct uh_server *srv, const char *cert, const char *key);
|
||||||
#endif
|
#endif
|
||||||
|
@ -120,11 +128,9 @@ struct uh_path_handler {
|
||||||
/*
|
/*
|
||||||
* uh_server_new - creat an uh_server struct and init it
|
* uh_server_new - creat an uh_server struct and init it
|
||||||
* @loop: If NULL will use EV_DEFAULT
|
* @loop: If NULL will use EV_DEFAULT
|
||||||
* @host: If NULL will listen on "0.0.0.0"
|
|
||||||
* @port: port to listen on
|
|
||||||
*/
|
*/
|
||||||
struct uh_server *uh_server_new(struct ev_loop *loop, const char *host, int port);
|
struct uh_server *uh_server_new(struct ev_loop *loop);
|
||||||
|
|
||||||
int uh_server_init(struct uh_server *srv, struct ev_loop *loop, const char *host, int port);
|
void uh_server_init(struct uh_server *srv, struct ev_loop *loop);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,15 +29,23 @@
|
||||||
|
|
||||||
#include "uhttpd.h"
|
#include "uhttpd.h"
|
||||||
|
|
||||||
|
struct uh_server_internal;
|
||||||
struct uh_connection_internal;
|
struct uh_connection_internal;
|
||||||
|
|
||||||
|
struct uh_listener {
|
||||||
|
int sock;
|
||||||
|
bool ssl;
|
||||||
|
struct ev_io ior;
|
||||||
|
struct uh_server_internal *srv;
|
||||||
|
struct uh_listener *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct uh_server_internal {
|
struct uh_server_internal {
|
||||||
struct uh_server com;
|
struct uh_server com;
|
||||||
int sock;
|
|
||||||
char *docroot;
|
char *docroot;
|
||||||
char *index_page;
|
char *index_page;
|
||||||
struct ev_loop *loop;
|
struct ev_loop *loop;
|
||||||
struct ev_io ior;
|
struct uh_listener *listeners;
|
||||||
struct uh_connection_internal *conns;
|
struct uh_connection_internal *conns;
|
||||||
void (*conn_closed_cb)(struct uh_connection *conn);
|
void (*conn_closed_cb)(struct uh_connection *conn);
|
||||||
void (*default_handler)(struct uh_connection *conn, int event);
|
void (*default_handler)(struct uh_connection *conn, int event);
|
||||||
|
@ -48,9 +56,4 @@ struct uh_server_internal {
|
||||||
struct uh_path_handler *handlers;
|
struct uh_path_handler *handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct worker {
|
|
||||||
struct ev_child w;
|
|
||||||
int i;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue