service-listen.c revision f6ba2de94f207839983e1b5b4bac930df465f572
/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "array.h"
#include "fd-set-nonblock.h"
#include "fd-close-on-exec.h"
#include "network.h"
#ifdef HAVE_SYSTEMD
#include "sd-daemon.h"
#endif
#include "service.h"
#include "service-listen.h"
#include <unistd.h>
#include <fcntl.h>
#define MIN_BACKLOG 4
#define MAX_BACKLOG 128
{
unsigned int backlog;
/* as unlikely as it is, avoid overflows */
else {
if (backlog > MAX_BACKLOG)
}
}
static int service_unix_listener_listen(struct service_listener *l)
{
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. */
if (fd != -1)
return 0;
}
/* delete and try again */
return -1;
}
}
return -1;
}
}
return 1;
}
static int service_fifo_listener_listen(struct service_listener *l)
{
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;
}
}
return 1;
}
#ifdef HAVE_SYSTEMD
static int
{
static int sd_fds = -1;
if (sd_fds < 0) {
sd_fds = sd_listen_fds(0);
if (sd_fds == -1) {
i_error("sd_listen_fds() failed: %m");
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
static int service_inet_listener_listen(struct service_listener *l)
{
int fd;
#ifdef HAVE_SYSTEMD
return -1;
if (fd == -1)
#endif
{
if (fd < 0) {
}
}
return 1;
}
{
struct service_listener *const *listeners;
struct service_listener *l = *listeners;
if (l->fd != -1)
continue;
switch (l->type) {
case SERVICE_LISTENER_UNIX:
break;
case SERVICE_LISTENER_FIFO:
break;
case SERVICE_LISTENER_INET:
break;
}
}
return ret;
}
{
}
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: {
const char *path =
break;
}
case SERVICE_LISTENER_INET:
break;
}
}
/* and let services_listen() deal with the remaining fds */
return services_listen(new_service_list);
}