mirror of https://github.com/omar-polo/gmid.git
give each server process its own socket for the executor
this fixes a bug introduced with the prefork mechanics: every server process shared the same socket, and this would cause a race condition when multiple server processes asked for a script cgi being executed. This gives each server process its own socket to talk to the executor, so the race cannot happen.
This commit is contained in:
parent
fda7b99fc7
commit
2c3e53dac6
78
ex.c
78
ex.c
|
@ -19,6 +19,7 @@
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <event.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -397,15 +398,50 @@ childerr:
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static void
|
||||||
executor_main()
|
handle_fork_req(int fd, short ev, void *data)
|
||||||
{
|
{
|
||||||
char *spath, *relpath, *addr, *ruser, *cissuer, *chash;
|
char *spath, *relpath, *addr, *ruser, *cissuer, *chash;
|
||||||
struct vhost *vhost;
|
struct vhost *vhost;
|
||||||
struct iri iri;
|
struct iri iri;
|
||||||
time_t notbefore, notafter;
|
time_t notbefore, notafter;
|
||||||
int d;
|
int d;
|
||||||
|
|
||||||
|
if (!recv_iri(fd, &iri)
|
||||||
|
|| !recv_string(fd, &spath)
|
||||||
|
|| !recv_string(fd, &relpath)
|
||||||
|
|| !recv_string(fd, &addr)
|
||||||
|
|| !recv_string(fd, &ruser)
|
||||||
|
|| !recv_string(fd, &cissuer)
|
||||||
|
|| !recv_string(fd, &chash)
|
||||||
|
|| !recv_time(fd, ¬before)
|
||||||
|
|| !recv_time(fd, ¬after)
|
||||||
|
|| !recv_vhost(fd, &vhost))
|
||||||
|
fatal("failure in handling fork request");
|
||||||
|
|
||||||
|
d = launch_cgi(&iri, spath, relpath, addr, ruser, cissuer, chash,
|
||||||
|
notbefore, notafter, vhost);
|
||||||
|
if (!send_fd(fd, d))
|
||||||
|
fatal("failure in sending the fd to the server: %s",
|
||||||
|
strerror(errno));
|
||||||
|
close(d);
|
||||||
|
|
||||||
|
free_recvd_iri(&iri);
|
||||||
|
free(spath);
|
||||||
|
free(relpath);
|
||||||
|
free(addr);
|
||||||
|
free(ruser);
|
||||||
|
free(cissuer);
|
||||||
|
free(chash);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
executor_main(void)
|
||||||
|
{
|
||||||
|
struct vhost *vhost;
|
||||||
|
struct event evs[PROC_MAX];
|
||||||
|
int i;
|
||||||
|
|
||||||
#ifdef __OpenBSD__
|
#ifdef __OpenBSD__
|
||||||
for (vhost = hosts; vhost->domain != NULL; ++vhost) {
|
for (vhost = hosts; vhost->domain != NULL; ++vhost) {
|
||||||
/* r so we can chdir into the correct directory */
|
/* r so we can chdir into the correct directory */
|
||||||
|
@ -419,39 +455,15 @@ executor_main()
|
||||||
err(1, "pledge");
|
err(1, "pledge");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (!hupped) {
|
event_init();
|
||||||
if (!recv_iri(exfd, &iri)
|
|
||||||
|| !recv_string(exfd, &spath)
|
|
||||||
|| !recv_string(exfd, &relpath)
|
|
||||||
|| !recv_string(exfd, &addr)
|
|
||||||
|| !recv_string(exfd, &ruser)
|
|
||||||
|| !recv_string(exfd, &cissuer)
|
|
||||||
|| !recv_string(exfd, &chash)
|
|
||||||
|| !recv_time(exfd, ¬before)
|
|
||||||
|| !recv_time(exfd, ¬after)
|
|
||||||
|| !recv_vhost(exfd, &vhost))
|
|
||||||
break;
|
|
||||||
|
|
||||||
d = launch_cgi(&iri, spath, relpath, addr, ruser, cissuer, chash,
|
for (i = 0; i < conf.prefork; ++i) {
|
||||||
notbefore, notafter, vhost);
|
event_set(&evs[i], servpipes[i], EV_READ | EV_PERSIST,
|
||||||
if (!send_fd(exfd, d))
|
handle_fork_req, NULL);
|
||||||
break;
|
event_add(&evs[i], NULL);
|
||||||
close(d);
|
|
||||||
|
|
||||||
free_recvd_iri(&iri);
|
|
||||||
free(spath);
|
|
||||||
free(relpath);
|
|
||||||
free(addr);
|
|
||||||
free(ruser);
|
|
||||||
free(cissuer);
|
|
||||||
free(chash);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hupped)
|
event_dispatch();
|
||||||
_exit(0);
|
|
||||||
|
|
||||||
/* kill all process in my group. This means the listener and
|
|
||||||
* every pending CGI script. */
|
|
||||||
kill(0, SIGINT);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
1
gmid.1
1
gmid.1
|
@ -159,6 +159,7 @@ This increases the performance and prevents delays when connecting to
|
||||||
a server.
|
a server.
|
||||||
.Nm
|
.Nm
|
||||||
runs 3 server processes by default, when not in config-less mode.
|
runs 3 server processes by default, when not in config-less mode.
|
||||||
|
The maximum number allowed is 16.
|
||||||
.It Ic protocols Ar string
|
.It Ic protocols Ar string
|
||||||
Specify the TLS protocols to enable.
|
Specify the TLS protocols to enable.
|
||||||
Refer to
|
Refer to
|
||||||
|
|
89
gmid.c
89
gmid.c
|
@ -29,7 +29,7 @@ volatile sig_atomic_t hupped;
|
||||||
|
|
||||||
struct vhost hosts[HOSTSLEN];
|
struct vhost hosts[HOSTSLEN];
|
||||||
|
|
||||||
int exfd, logfd, sock4, sock6;
|
int exfd, logfd, sock4, sock6, servpipes[PROC_MAX];
|
||||||
|
|
||||||
struct imsgbuf logpibuf, logcibuf;
|
struct imsgbuf logpibuf, logcibuf;
|
||||||
|
|
||||||
|
@ -299,31 +299,6 @@ drop_priv(void)
|
||||||
log_warn(NULL, "not a good idea to run a network daemon as root");
|
log_warn(NULL, "not a good idea to run a network daemon as root");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
spawn_listeners(int *p)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
close(p[0]);
|
|
||||||
exfd = p[1];
|
|
||||||
|
|
||||||
for (i = 0; i < conf.prefork -1; ++i) {
|
|
||||||
switch (fork()) {
|
|
||||||
case -1:
|
|
||||||
fatal("fork: %s", strerror(errno));
|
|
||||||
case 0: /* child */
|
|
||||||
setproctitle("server(%d)", i+1);
|
|
||||||
return listener_main();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conf.prefork == 0)
|
|
||||||
setproctitle("server");
|
|
||||||
else
|
|
||||||
setproctitle("server(%d)", conf.prefork);
|
|
||||||
return listener_main();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(const char *me)
|
usage(const char *me)
|
||||||
{
|
{
|
||||||
|
@ -359,13 +334,13 @@ logger_init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
serve(int argc, char **argv, int *p)
|
serve(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
|
int i, p[2];
|
||||||
|
|
||||||
if (config_path == NULL) {
|
if (config_path == NULL) {
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
hostname = "localhost";
|
hostname = "localhost";
|
||||||
if (certs_dir == NULL)
|
if (certs_dir == NULL)
|
||||||
|
@ -395,28 +370,35 @@ serve(int argc, char **argv, int *p)
|
||||||
* to put private certs inside the chroot. */
|
* to put private certs inside the chroot. */
|
||||||
setup_tls();
|
setup_tls();
|
||||||
|
|
||||||
switch (fork()) {
|
for (i = 0; i < conf.prefork; ++i) {
|
||||||
case -1:
|
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
|
||||||
fatal("fork: %s", strerror(errno));
|
PF_UNSPEC, p) == -1)
|
||||||
|
fatal("socketpair: %s", strerror(errno));
|
||||||
|
|
||||||
case 0: /* child */
|
switch (fork()) {
|
||||||
return spawn_listeners(p);
|
case -1:
|
||||||
|
fatal("fork: %s", strerror(errno));
|
||||||
default: /* parent */
|
case 0: /* child */
|
||||||
setproctitle("executor");
|
close(p[0]);
|
||||||
close(p[1]);
|
exfd = p[1];
|
||||||
exfd = p[0];
|
setproctitle("server");
|
||||||
drop_priv();
|
_exit(listener_main());
|
||||||
unblock_signals();
|
default:
|
||||||
return executor_main();
|
servpipes[i] = p[0];
|
||||||
|
close(p[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setproctitle("executor");
|
||||||
|
drop_priv();
|
||||||
|
unblock_signals();
|
||||||
|
_exit(executor_main());
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ch, p[2];
|
int ch, conftest = 0, configless = 0;
|
||||||
int conftest = 0, configless = 0;
|
|
||||||
int old_ipv6, old_port;
|
int old_ipv6, old_port;
|
||||||
|
|
||||||
init_config();
|
init_config();
|
||||||
|
@ -482,7 +464,7 @@ main(int argc, char **argv)
|
||||||
if (config_path == NULL) {
|
if (config_path == NULL) {
|
||||||
configless = 1;
|
configless = 1;
|
||||||
conf.foreground = 1;
|
conf.foreground = 1;
|
||||||
conf.prefork = 0;
|
conf.prefork = 1;
|
||||||
conf.verbose++;
|
conf.verbose++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,10 +491,6 @@ main(int argc, char **argv)
|
||||||
err(1, "daemon");
|
err(1, "daemon");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
|
|
||||||
PF_UNSPEC, p) == -1)
|
|
||||||
err(1, "socketpair");
|
|
||||||
|
|
||||||
if (config_path != NULL)
|
if (config_path != NULL)
|
||||||
parse_conf(config_path);
|
parse_conf(config_path);
|
||||||
|
|
||||||
|
@ -524,7 +502,7 @@ main(int argc, char **argv)
|
||||||
sock6 = make_socket(conf.port, AF_INET6);
|
sock6 = make_socket(conf.port, AF_INET6);
|
||||||
|
|
||||||
if (configless)
|
if (configless)
|
||||||
return serve(argc, argv, p);
|
return serve(argc, argv);
|
||||||
|
|
||||||
/* wait a sighup and reload the daemon */
|
/* wait a sighup and reload the daemon */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -535,12 +513,9 @@ main(int argc, char **argv)
|
||||||
case -1:
|
case -1:
|
||||||
fatal("fork: %s", strerror(errno));
|
fatal("fork: %s", strerror(errno));
|
||||||
case 0:
|
case 0:
|
||||||
return serve(argc, argv, p);
|
return serve(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(p[0]);
|
|
||||||
close(p[1]);
|
|
||||||
|
|
||||||
wait_sighup();
|
wait_sighup();
|
||||||
unblock_signals();
|
unblock_signals();
|
||||||
log_info(NULL, "reloading configuration %s", config_path);
|
log_info(NULL, "reloading configuration %s", config_path);
|
||||||
|
@ -568,9 +543,5 @@ main(int argc, char **argv)
|
||||||
sock4 = make_socket(conf.port, AF_INET);
|
sock4 = make_socket(conf.port, AF_INET);
|
||||||
if (sock6 == -1 && conf.ipv6)
|
if (sock6 == -1 && conf.ipv6)
|
||||||
sock6 = make_socket(conf.port, AF_INET6);
|
sock6 = make_socket(conf.port, AF_INET6);
|
||||||
|
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
|
|
||||||
PF_UNSPEC, p) == -1)
|
|
||||||
fatal("socketpair: %s", strerror(errno));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
gmid.h
4
gmid.h
|
@ -56,6 +56,8 @@
|
||||||
#define DOMAIN_NAME_LEN (253+1)
|
#define DOMAIN_NAME_LEN (253+1)
|
||||||
#define LABEL_LEN (63+1)
|
#define LABEL_LEN (63+1)
|
||||||
|
|
||||||
|
#define PROC_MAX 16
|
||||||
|
|
||||||
struct location {
|
struct location {
|
||||||
const char *match;
|
const char *match;
|
||||||
const char *lang;
|
const char *lang;
|
||||||
|
@ -120,6 +122,8 @@ extern struct imsgbuf logpibuf, logcibuf;
|
||||||
|
|
||||||
extern volatile sig_atomic_t hupped;
|
extern volatile sig_atomic_t hupped;
|
||||||
|
|
||||||
|
extern int servpipes[PROC_MAX];
|
||||||
|
|
||||||
struct iri {
|
struct iri {
|
||||||
char *schema;
|
char *schema;
|
||||||
char *host;
|
char *host;
|
||||||
|
|
Loading…
Reference in New Issue