diff options
Diffstat (limited to '')
-rw-r--r-- | src/server_socket.c | 96 |
1 files changed, 68 insertions, 28 deletions
diff --git a/src/server_socket.c b/src/server_socket.c index 482e0cda1..e4b5e3ece 100644 --- a/src/server_socket.c +++ b/src/server_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2010 The Music Player Daemon Project + * Copyright (C) 2003-2011 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,14 @@ */ #include "config.h" + +#ifdef HAVE_STRUCT_UCRED +#define _GNU_SOURCE 1 +#endif + #include "server_socket.h" #include "socket_util.h" +#include "resolver.h" #include "fd_util.h" #include "glib_compat.h" #include "glib_socket.h" @@ -155,16 +161,35 @@ server_socket_in_event(G_GNUC_UNUSED GIOChannel *source, size_t address_length = sizeof(address); int fd = accept_cloexec_nonblock(s->fd, (struct sockaddr*)&address, &address_length); - if (fd >= 0) + if (fd >= 0) { + if (socket_keepalive(fd)) + g_warning("Could not set TCP keepalive option: %s", + g_strerror(errno)); s->parent->callback(fd, (const struct sockaddr*)&address, address_length, get_remote_uid(fd), s->parent->callback_ctx); - else + } else { g_warning("accept() failed: %s", g_strerror(errno)); + } return true; } +static void +set_fd(struct one_socket *s, int fd) +{ + assert(s != NULL); + assert(s->fd < 0); + assert(fd >= 0); + + s->fd = fd; + + GIOChannel *channel = g_io_channel_new_socket(s->fd); + s->source_id = g_io_add_watch(channel, G_IO_IN, + server_socket_in_event, s); + g_io_channel_unref(channel); +} + bool server_socket_open(struct server_socket *ss, GError **error_r) { @@ -183,10 +208,11 @@ server_socket_open(struct server_socket *ss, GError **error_r) } GError *error = NULL; - s->fd = socket_bind_listen(s->address.sa_family, SOCK_STREAM, 0, - &s->address, s->address_length, 5, - &error); - if (s->fd < 0) { + int fd = socket_bind_listen(s->address.sa_family, + SOCK_STREAM, 0, + &s->address, s->address_length, 5, + &error); + if (fd < 0) { if (good != NULL && good->serial == s->serial) { char *address_string = one_socket_to_string(s); char *good_string = one_socket_to_string(good); @@ -218,10 +244,7 @@ server_socket_open(struct server_socket *ss, GError **error_r) /* register in the GLib main loop */ - GIOChannel *channel = g_io_channel_new_socket(s->fd); - s->source_id = g_io_add_watch(channel, G_IO_IN, - server_socket_in_event, s); - g_io_channel_unref(channel); + set_fd(s, fd); /* mark this socket as "good", and clear previous errors */ @@ -276,6 +299,36 @@ one_socket_new(unsigned serial, const struct sockaddr *address, return s; } +bool +server_socket_add_fd(struct server_socket *ss, int fd, GError **error_r) +{ + assert(ss != NULL); + assert(ss->sockets_tail_r != NULL); + assert(*ss->sockets_tail_r == NULL); + assert(fd >= 0); + + struct sockaddr_storage address; + socklen_t address_length; + if (getsockname(fd, (struct sockaddr *)&address, + &address_length) < 0) { + g_set_error(error_r, server_socket_quark(), errno, + "Failed to get socket address: %s", + g_strerror(errno)); + return false; + } + + struct one_socket *s = one_socket_new(ss->next_serial, + (struct sockaddr *)&address, + address_length); + s->parent = ss; + *ss->sockets_tail_r = s; + ss->sockets_tail_r = &s->next; + + set_fd(s, fd); + + return true; +} + static struct one_socket * server_socket_add_address(struct server_socket *ss, const struct sockaddr *address, @@ -369,24 +422,11 @@ server_socket_add_host(struct server_socket *ss, const char *hostname, unsigned port, GError **error_r) { #ifdef HAVE_TCP - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - char service[20]; - g_snprintf(service, sizeof(service), "%u", port); - - struct addrinfo *ai; - int ret = getaddrinfo(hostname, service, &hints, &ai); - if (ret != 0) { - g_set_error(error_r, server_socket_quark(), ret, - "Failed to look up host \"%s\": %s", - hostname, gai_strerror(ret)); + struct addrinfo *ai = resolve_host_port(hostname, port, + AI_PASSIVE, SOCK_STREAM, + error_r); + if (ai == NULL) return false; - } for (const struct addrinfo *i = ai; i != NULL; i = i->ai_next) server_socket_add_address(ss, i->ai_addr, i->ai_addrlen); |