Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Westermo fixes for UDP inetd services and more #27

Merged
merged 7 commits into from Apr 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion api.c
Expand Up @@ -346,7 +346,7 @@ int api_init(uev_ctx_t *ctx)
.sun_path = INIT_SOCKET,
};

sd = socket(AF_UNIX, SOCK_STREAM, 0);
sd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (-1 == sd) {
_pe("Failed starting external API socket");
return 1;
Expand Down
6 changes: 3 additions & 3 deletions exec.c
Expand Up @@ -245,9 +245,9 @@ pid_t run_getty(char *cmd, char *args[], int console)
if (fd != STDIN_FILENO)
exit(1);

dup2(0, STDIN_FILENO);
dup2(0, STDOUT_FILENO);
dup2(0, STDERR_FILENO);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);

prctl(PR_SET_NAME, "console", 0, 0, 0);
}
Expand Down
72 changes: 53 additions & 19 deletions inetd.c
Expand Up @@ -127,8 +127,7 @@ static int get_stdin(svc_t *svc)
}

if (!inetd_is_allowed(&svc->inetd, ifname)) {
FLOG_INFO("Service %s on port %d not allowed from interface %s.",
svc->inetd.name, svc->inetd.port, ifname);
FLOG_INFO("Service %s on %s:%d is not allowed.", svc->inetd.name, ifname, svc->inetd.port);
if (svc->inetd.type == SOCK_STREAM)
close(stdin);

Expand All @@ -144,10 +143,19 @@ static void socket_cb(uev_t *w, void *arg, int UNUSED(events))
svc_t *svc = (svc_t *)arg, *task;
int stdin;

_d("Got event on %s socket ...", svc->cmd);
stdin = get_stdin(svc);
if (stdin < 0) {
FLOG_ERROR("%s: Unable to accept incoming connection",
svc->cmd);
FLOG_ERROR("%s: Unable to accept incoming connection", svc->cmd);
return;
}

/*
* Make sure to disable O_NONBLOCK on the descriptor before
* passing it to the inetd service, that's what is expected.
*/
if (fcntl(stdin, F_SETFL, fcntl(stdin, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
FLOG_ERROR("Failed disabling non-blocking on %s socket", svc->cmd);
return;
}

Expand All @@ -158,22 +166,27 @@ static void socket_cb(uev_t *w, void *arg, int UNUSED(events))
return;
}

/* Copy inherited attributes from inetd */
if (!svc->inetd.forking) {
svc->block = SVC_BLOCK_INETD_BUSY;
service_step(svc);
}

/* Copy inherited attributes from inetd service's svc */
task->runlevels = svc->runlevels;
task->inetd = svc->inetd;

/* Only copy the most relevant parts of inetd, in particular we
* must *not* copy the watcher data to the clone! */
task->inetd.svc = svc;
task->inetd.type = svc->inetd.type;

memcpy(task->cond, svc->cond, sizeof(task->cond));
memcpy(task->username, svc->username, sizeof(task->username));
memcpy(task->group, svc->group, sizeof(task->group));
memcpy(task->args, svc->args, sizeof(task->args));
snprintf(task->desc, sizeof(task->desc), "%s Connection", svc->desc);
snprintf(task->desc, sizeof(task->desc), "%s connection", svc->desc);

task->stdin = stdin;
service_step(task);

if (!svc->inetd.forking) {
svc->block = SVC_BLOCK_INETD_BUSY;
service_step(svc);
}
}

/* Launch Inet socket for service.
Expand All @@ -190,7 +203,7 @@ static int spawn_socket(inetd_t *inetd)
return -EINVAL;
}

_d("Spawning server socket for inetd %s ...", inetd->name);
_d("Spawning server socket for inetd %s, type %s ...", inetd->name, inetd->type == SOCK_STREAM ? "stream" : "dgram");
sd = socket(AF_INET, inetd->type | SOCK_NONBLOCK | SOCK_CLOEXEC, inetd->proto);
if (-1 == sd) {
FLOG_PERROR("Failed opening inetd socket type %d proto %d", inetd->type, inetd->proto);
Expand All @@ -215,7 +228,7 @@ static int spawn_socket(inetd_t *inetd)

if (inetd->port) {
if (inetd->type == SOCK_STREAM) {
if (-1 == listen(sd, 20)) {
if (-1 == listen(sd, 10)) {
FLOG_PERROR("Failed listening to inetd service %s", inetd->name);
close(sd);
return -errno;
Expand All @@ -232,19 +245,40 @@ static int spawn_socket(inetd_t *inetd)

int inetd_start(inetd_t *inetd)
{
if (inetd->watcher.fd == -1)
int sd;
char buf[BUFSIZ];
ssize_t len;

sd = inetd->watcher.fd;
if (sd == -1)
return spawn_socket(inetd);

return -EEXIST;
/* Read anything lingering, or clean up socket after failure */
len = recv(sd, buf, sizeof(buf), MSG_DONTWAIT);
_d("Read %d lingering bytes from socket before restarting %s ...", len, inetd->svc->cmd);

/* Restore O_NONBLOCK for socket */
fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK);

_d("Re-starting %s socket watcher ...", inetd->svc->cmd);
uev_io_start(&inetd->watcher);

return 0;
}

void inetd_stop(inetd_t *inetd)
{
if (inetd->watcher.fd != -1) {
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
uev_io_stop(&inetd->watcher);
shutdown(inetd->watcher.fd, SHUT_RDWR);
close(inetd->watcher.fd);
inetd->watcher.fd = -1;

/* For dgram inetd services we block the parent SVC
* and halt the watcher, so don't close the socket! */
if (inetd->svc->block != SVC_BLOCK_INETD_BUSY) {
shutdown(inetd->watcher.fd, SHUT_RDWR);
close(inetd->watcher.fd);
inetd->watcher.fd = -1;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion plugins/pidfile.c
Expand Up @@ -104,7 +104,7 @@ static plugin_t plugin = {

PLUGIN_INIT(plugin_init)
{
pidfile_ctx.fd = inotify_init();
pidfile_ctx.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (pidfile_ctx.fd < 0) {
_pe("inotify_init()");
return;
Expand Down
4 changes: 3 additions & 1 deletion svc.c
Expand Up @@ -97,7 +97,9 @@ svc_t *svc_new(char *cmd, int id, int type)
*/
int svc_del(svc_t *svc)
{
svc->type = SVC_TYPE_FREE;
/* Clear any old references and set SVC_TYPE_FREE */
memset(svc, 0, sizeof(*svc));

return 0;
}

Expand Down