aboutsummaryrefslogtreecommitdiffstats
path: root/src/server_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server_socket.c')
-rw-r--r--src/server_socket.c96
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);