listen: listen_add_address() returns bool/GError

Don't return -1 on failure, and abort on fatal error - do proper error
reporting with GError, and return false on failure.
This commit is contained in:
Max Kellermann 2009-02-24 17:43:10 +01:00
parent 7de4e7228f
commit dbb067c016

View File

@ -64,13 +64,20 @@ struct listen_socket {
static struct listen_socket *listen_sockets; static struct listen_socket *listen_sockets;
int listen_port; int listen_port;
static GQuark
listen_quark(void)
{
return g_quark_from_static_string("listen");
}
static gboolean static gboolean
listen_in_event(GIOChannel *source, GIOCondition condition, gpointer data); listen_in_event(GIOChannel *source, GIOCondition condition, gpointer data);
static int static bool
listen_add_address(int pf, const struct sockaddr *addrp, socklen_t addrlen) listen_add_address(int pf, const struct sockaddr *addrp, socklen_t addrlen,
GError **error)
{ {
int sock; int fd, ret;
const int reuse = ALLOW_REUSE; const int reuse = ALLOW_REUSE;
#ifdef HAVE_STRUCT_UCRED #ifdef HAVE_STRUCT_UCRED
int passcred = 1; int passcred = 1;
@ -78,38 +85,54 @@ listen_add_address(int pf, const struct sockaddr *addrp, socklen_t addrlen)
struct listen_socket *ls; struct listen_socket *ls;
GIOChannel *channel; GIOChannel *channel;
if ((sock = socket(pf, SOCK_STREAM, 0)) < 0) fd = socket(pf, SOCK_STREAM, 0);
g_error("socket < 0"); if (fd < 0) {
g_set_error(error, listen_quark(), errno,
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, "Failed to create socket: %s", strerror(errno));
&reuse, sizeof(reuse)) < 0) { return false;
g_error("problems setsockopt'ing: %s", strerror(errno));
} }
if (bind(sock, addrp, addrlen) < 0) { ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
close(sock); &reuse, sizeof(reuse));
return -1; if (ret < 0) {
g_set_error(error, listen_quark(), errno,
"setsockopt() failed: %s", strerror(errno));
close(fd);
return false;
} }
if (listen(sock, 5) < 0) ret = bind(fd, addrp, addrlen);
g_error("problems listen'ing: %s", strerror(errno)); if (ret < 0) {
g_set_error(error, listen_quark(), errno,
"%s", strerror(errno));
close(fd);
return false;
}
ret = listen(fd, 5);
if (ret < 0) {
g_set_error(error, listen_quark(), errno,
"listen() failed: %s", strerror(errno));
close(fd);
return false;
}
#ifdef HAVE_STRUCT_UCRED #ifdef HAVE_STRUCT_UCRED
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred, sizeof(passcred)); setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &passcred, sizeof(passcred));
#endif #endif
ls = g_new(struct listen_socket, 1); ls = g_new(struct listen_socket, 1);
ls->fd = sock; ls->fd = fd;
channel = g_io_channel_unix_new(sock); channel = g_io_channel_unix_new(fd);
ls->source_id = g_io_add_watch(channel, G_IO_IN, ls->source_id = g_io_add_watch(channel, G_IO_IN,
listen_in_event, GINT_TO_POINTER(sock)); listen_in_event, GINT_TO_POINTER(fd));
g_io_channel_unref(channel); g_io_channel_unref(channel);
ls->next = listen_sockets; ls->next = listen_sockets;
listen_sockets = ls; listen_sockets = ls;
return 0; return true;
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@ -125,10 +148,12 @@ is_ipv6_enabled(void)
} }
#endif #endif
static void static bool
listen_add_config_param(G_GNUC_UNUSED unsigned int port, listen_add_config_param(G_GNUC_UNUSED unsigned int port,
const struct config_param *param) const struct config_param *param,
GError **error)
{ {
bool success;
const struct sockaddr *addrp; const struct sockaddr *addrp;
socklen_t addrlen; socklen_t addrlen;
#ifdef HAVE_TCP #ifdef HAVE_TCP
@ -154,22 +179,34 @@ listen_add_config_param(G_GNUC_UNUSED unsigned int port,
sin6.sin6_addr = in6addr_any; sin6.sin6_addr = in6addr_any;
addrp = (const struct sockaddr *)&sin6; addrp = (const struct sockaddr *)&sin6;
addrlen = sizeof(struct sockaddr_in6); addrlen = sizeof(struct sockaddr_in6);
if (listen_add_address(PF_INET6, addrp, addrlen) < 0)
BINDERROR(); success = listen_add_address(PF_INET6, addrp, addrlen,
error);
if (!success)
return false;
} }
#endif #endif
sin4.sin_addr.s_addr = INADDR_ANY; sin4.sin_addr.s_addr = INADDR_ANY;
addrp = (const struct sockaddr *)&sin4; addrp = (const struct sockaddr *)&sin4;
addrlen = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in);
success = listen_add_address(PF_INET, addrp, addrlen, error);
if (!success) {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if ((listen_add_address(PF_INET, addrp, addrlen) < 0) && !ipv6_enabled) { if (ipv6_enabled)
#else /* non-critical: IPv6 listener is
if (listen_add_address(PF_INET, addrp, addrlen) < 0) { already set up */
g_clear_error(error);
else
#endif #endif
BINDERROR(); return false;
} }
return true;
#else /* HAVE_TCP */ #else /* HAVE_TCP */
g_error("TCP support is disabled"); g_set_error(error, listen_quark(), 0,
"TCP support is disabled");
return false;
#endif /* HAVE_TCP */ #endif /* HAVE_TCP */
#ifdef HAVE_UN #ifdef HAVE_UN
} else if (param->value[0] == '/') { } else if (param->value[0] == '/') {
@ -188,13 +225,14 @@ listen_add_config_param(G_GNUC_UNUSED unsigned int port,
addrp = (const struct sockaddr *)&s_un; addrp = (const struct sockaddr *)&s_un;
addrlen = sizeof(s_un); addrlen = sizeof(s_un);
if (listen_add_address(PF_UNIX, addrp, addrlen) < 0) success = listen_add_address(PF_UNIX, addrp, addrlen, error);
g_error("unable to bind to %s: %s", if (!success)
param->value, strerror(errno)); return false;
/* allow everybody to connect */ /* allow everybody to connect */
chmod(param->value, 0666); chmod(param->value, 0666);
return true;
#endif /* HAVE_UN */ #endif /* HAVE_UN */
} else { } else {
#ifdef HAVE_TCP #ifdef HAVE_TCP
@ -221,12 +259,16 @@ listen_add_config_param(G_GNUC_UNUSED unsigned int port,
g_error("can't lookup host \"%s\" at line %i: %s", g_error("can't lookup host \"%s\" at line %i: %s",
param->value, param->line, gai_strerror(ret)); param->value, param->line, gai_strerror(ret));
for (i = ai; i != NULL; i = i->ai_next) for (i = ai; i != NULL; i = i->ai_next) {
if (listen_add_address(i->ai_family, i->ai_addr, success = listen_add_address(i->ai_family, i->ai_addr,
i->ai_addrlen) < 0) i->ai_addrlen, error);
BINDERROR(); if (!success)
return false;
}
freeaddrinfo(ai); freeaddrinfo(ai);
return true;
#else /* WIN32 */ #else /* WIN32 */
const struct hostent *he; const struct hostent *he;
@ -241,11 +283,13 @@ listen_add_config_param(G_GNUC_UNUSED unsigned int port,
g_error("IPv4 address expected for host \"%s\" at line %i", g_error("IPv4 address expected for host \"%s\" at line %i",
param->value, param->line); param->value, param->line);
if (listen_add_address(AF_INET, he->h_addr, he->h_length) < 0) return listen_add_address(AF_INET, he->h_addr, he->h_length,
BINDERROR(); error);
#endif /* !WIN32 */ #endif /* !WIN32 */
#else /* HAVE_TCP */ #else /* HAVE_TCP */
g_error("TCP support is disabled"); g_set_error(error, listen_quark(), 0,
"TCP support is disabled");
return false;
#endif /* HAVE_TCP */ #endif /* HAVE_TCP */
} }
} }
@ -255,9 +299,20 @@ void listen_global_init(void)
int port = config_get_positive(CONF_PORT, DEFAULT_PORT); int port = config_get_positive(CONF_PORT, DEFAULT_PORT);
const struct config_param *param = const struct config_param *param =
config_get_next_param(CONF_BIND_TO_ADDRESS, NULL); config_get_next_param(CONF_BIND_TO_ADDRESS, NULL);
bool success;
GError *error = NULL;
do { do {
listen_add_config_param(port, param); success = listen_add_config_param(port, param, &error);
if (!success) {
if (param != NULL)
g_error("Failed to listen on %s (line %i): %s",
param->value, param->line,
error->message);
else
g_error("Failed to listen on *:%d: %s",
port, error->message);
}
} while ((param = config_get_next_param(CONF_BIND_TO_ADDRESS, param))); } while ((param = config_get_next_param(CONF_BIND_TO_ADDRESS, param)));
listen_port = port; listen_port = port;
} }