/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "array.h"
#include "ioloop.h"
#include "net.h"
#ifdef HAVE_SYSTEMD
#include "sd-daemon.h"
#endif
#include "service.h"
#include "service-listen.h"
#include <unistd.h>
#include <fcntl.h>
{
unsigned int backlog;
/* as unlikely as it is, avoid overflows */
else
}
static int
{
return 0;
return -1;
}
return 0;
}
{
int fd, i;
for (i = 0;; i++) {
if (fd != -1)
break;
/* looks like the path doesn't exist. */
return 0;
}
if (errno != EADDRINUSE) {
return -1;
}
/* already in use - see if it really exists.
after 3 times just fail here. */
i_close_fd(&fd);
return 0;
}
/* delete and try again */
return -1;
}
}
if (service_file_chown(l) < 0) {
i_close_fd(&fd);
return -1;
}
return 1;
}
{
unsigned int i;
for (i = 0;; i++) {
if (ret == 0)
break;
return -1;
}
return -1;
}
}
if (service_file_chown(l) < 0)
return -1;
/* open as RDWR, so that even if the last writer closes,
we won't get EOF errors */
if (fd == -1) {
return -1;
}
return 1;
}
#ifdef HAVE_SYSTEMD
static int
{
if (sd_fds < 0) {
sd_fds = sd_listen_fds(0);
if (sd_fds < 0) {
return -1;
}
}
return 0;
}
}
/* when systemd didn't provide a usable socket,
fall back to the regular socket creation code */
*fd_r = -1;
return 0;
}
#endif
{
int fd;
#ifdef HAVE_SYSTEMD
return -1;
if (fd == -1)
#endif
{
if (set->reuse_port)
if (fd < 0) {
}
}
return 1;
}
{
switch (l->type) {
case SERVICE_LISTENER_UNIX:
return service_unix_listener_listen(l);
case SERVICE_LISTENER_FIFO:
return service_fifo_listener_listen(l);
case SERVICE_LISTENER_INET:
return service_inet_listener_listen(l);
}
i_unreached();
}
{
struct service_listener *l = *listeners;
if (l->fd != -1)
continue;
ret2 = service_listener_listen(l);
}
return ret;
}
#ifdef HAVE_SYSTEMD
{
union sockaddr_union {
} sockaddr;
socklen_t l;
// FIXME(Stephan): why -1?
l = sizeof(sockaddr);
return -errno;
if (port) {
if (l < sizeof(struct sockaddr_in))
return -EINVAL;
} else {
if (l < sizeof(struct sockaddr_in6))
return -EINVAL;
}
}
return 0;
}
{
if (sd_fds < 0) {
sd_fds = sd_listen_fds(0);
if (sd_fds == -1) {
i_error("sd_listen_fds() failed: %m");
return -1;
}
}
unsigned int family;
struct service_listener *l = *listeners;
if (l->type != SERVICE_LISTENER_INET)
continue;
break;
}
}
if (found) break;
}
if (!found) {
i_error("shutdown() failed: %m");
i_error("dup2() failed: %m");
}
}
}
return 0;
}
#endif
{
const char *path;
/* already in use. all the other sockets were fine, so just
delete this and retry. */
}
return 0;
}
return 1;
}
{
}
/* reloading config wants to continue even when we're returning 0. */
if (ret >= 0) {
}
#ifdef HAVE_SYSTEMD
if (ret > 0)
#endif
return ret;
}
const struct service_listener *l2)
{
return FALSE;
case SERVICE_LISTENER_UNIX:
case SERVICE_LISTENER_FIFO:
/* We could just keep using the same listener, but it's more
likely to cause problems if old process accepts a connection
before it knows that it should die. So just always unlink
return FALSE;
case SERVICE_LISTENER_INET:
return FALSE;
return FALSE;
return TRUE;
}
return FALSE;
}
struct service_list *old_service_list)
{
/* rescue anvil's UNIX socket listener */
break;
}
i_error("Can't change anvil's listeners on the fly");
return -1;
}
for (i = 0; i < new_count; i++) {
}
}
/* first create an arrays of all listeners to make things easier */
for (i = 0; i < count; i++)
for (i = 0; i < count; i++)
/* then start moving fds */
for (i = 0; i < new_count; i++) {
for (j = 0; j < old_count; j++) {
old_listeners[j])) {
break;
}
}
}
/* close what's left */
for (j = 0; j < old_count; j++) {
continue;
i_error("close(listener) failed: %m");
switch (old_listeners[j]->type) {
case SERVICE_LISTENER_UNIX:
case SERVICE_LISTENER_FIFO: {
break;
}
case SERVICE_LISTENER_INET:
break;
}
}
/* and let services_listen() deal with the remaining fds */
return services_listen(new_service_list);
}