aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ntp_server.c79
-rw-r--r--src/ntp_server.h8
-rw-r--r--src/output/raop_output_plugin.c6
-rw-r--r--src/udp_server.c130
-rw-r--r--src/udp_server.h52
5 files changed, 211 insertions, 64 deletions
diff --git a/src/ntp_server.c b/src/ntp_server.c
index d2e45bcac..c33c0a933 100644
--- a/src/ntp_server.c
+++ b/src/ntp_server.c
@@ -18,7 +18,7 @@
*/
#include "ntp_server.h"
-#include "io_thread.h"
+#include "udp_server.h"
#include <glib.h>
#include <assert.h>
@@ -76,18 +76,18 @@ fill_time_buffer(unsigned char *buffer)
fill_time_buffer_with_time(buffer, &current_time);
}
-static bool
-ntp_server_handle(struct ntp_server *ntp)
+static void
+ntp_server_datagram(int fd, const void *data, size_t num_bytes,
+ const struct sockaddr *source_address,
+ size_t source_address_length, G_GNUC_UNUSED void *ctx)
{
unsigned char buf[32];
- struct sockaddr addr;
int iter;
- socklen_t addr_len = sizeof(addr);
- ssize_t num_bytes = recvfrom(ntp->fd, (void *)buf, sizeof(buf), 0,
- &addr, &addr_len);
- if (num_bytes == 0) {
- return false;
- }
+
+ if (num_bytes > sizeof(buf))
+ num_bytes = sizeof(buf);
+ memcpy(buf, data, num_bytes);
+
fill_time_buffer(buf + 16);
// set to response
buf[1] = 0xd3;
@@ -97,65 +97,36 @@ ntp_server_handle(struct ntp_server *ntp)
}
fill_time_buffer(buf + 24);
- num_bytes = sendto(ntp->fd, (void *)buf, num_bytes, 0,
- &addr, addr_len);
-
- return num_bytes == sizeof(buf);
+ sendto(fd, (void *)buf, num_bytes, 0,
+ source_address, source_address_length);
}
-static gboolean
-ntp_in_event(G_GNUC_UNUSED GIOChannel *source,
- G_GNUC_UNUSED GIOCondition condition,
- gpointer data)
-{
- struct ntp_server *ntp = data;
-
- ntp_server_handle(ntp);
- return true;
-}
+static const struct udp_server_handler ntp_server_handler = {
+ .datagram = ntp_server_datagram,
+};
void
ntp_server_init(struct ntp_server *ntp)
{
ntp->port = 6002;
- ntp->fd = -1;
+ ntp->udp = NULL;
}
-void
-ntp_server_open(struct ntp_server *ntp, int fd)
+bool
+ntp_server_open(struct ntp_server *ntp, GError **error_r)
{
- assert(ntp->fd < 0);
- assert(fd >= 0);
+ assert(ntp->udp == NULL);
- ntp->fd = fd;
-
-#ifndef G_OS_WIN32
- ntp->channel = g_io_channel_unix_new(fd);
-#else
- ntp->channel = g_io_channel_win32_new_socket(fd);
-#endif
- /* NULL encoding means the stream is binary safe */
- g_io_channel_set_encoding(ntp->channel, NULL, NULL);
- /* no buffering */
- g_io_channel_set_buffered(ntp->channel, false);
-
- ntp->source = g_io_create_watch(ntp->channel, G_IO_IN);
- g_source_set_callback(ntp->source, (GSourceFunc)ntp_in_event, ntp,
- NULL);
- g_source_attach(ntp->source, io_thread_context());
+ ntp->udp = udp_server_new(ntp->port, &ntp_server_handler, ntp,
+ error_r);
+ return ntp->udp != NULL;
}
void
ntp_server_close(struct ntp_server *ntp)
{
- if (ntp->source != NULL) {
- g_source_destroy(ntp->source);
- g_source_unref(ntp->source);
+ if (ntp->udp != NULL) {
+ udp_server_free(ntp->udp);
+ ntp->udp = NULL;
}
-
- if (ntp->channel != NULL)
- g_io_channel_unref(ntp->channel);
-
- if (ntp->fd >= 0)
- close(ntp->fd);
}
diff --git a/src/ntp_server.h b/src/ntp_server.h
index 2b970dff2..fe6f8083b 100644
--- a/src/ntp_server.h
+++ b/src/ntp_server.h
@@ -28,17 +28,15 @@ struct timeval;
struct ntp_server {
unsigned short port;
- int fd;
- GIOChannel *channel;
- GSource *source;
+ struct udp_server *udp;
};
void
ntp_server_init(struct ntp_server *ntp);
-void
-ntp_server_open(struct ntp_server *ntp, int fd);
+bool
+ntp_server_open(struct ntp_server *ntp, GError **error_r);
void
ntp_server_close(struct ntp_server *ntp);
diff --git a/src/output/raop_output_plugin.c b/src/output/raop_output_plugin.c
index ee5f67411..7ff5b009a 100644
--- a/src/output/raop_output_plugin.c
+++ b/src/output/raop_output_plugin.c
@@ -799,13 +799,9 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r
if (raop_session->data_fd < 0)
return false;
- int fd = open_udp_socket(NULL, &raop_session->ntp.port,
- error_r);
- if (fd < 0)
+ if (!ntp_server_open(&raop_session->ntp, error_r))
return false;
- ntp_server_open(&raop_session->ntp, fd);
-
raop_session->ctrl.fd =
open_udp_socket(NULL, &raop_session->ctrl.port,
error_r);
diff --git a/src/udp_server.c b/src/udp_server.c
new file mode 100644
index 000000000..05779138b
--- /dev/null
+++ b/src/udp_server.c
@@ -0,0 +1,130 @@
+/*
+ * 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
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "udp_server.h"
+#include "io_thread.h"
+
+#include <glib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#ifdef WIN32
+#define WINVER 0x0501
+#include <ws2tcpip.h>
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+struct udp_server {
+ const struct udp_server_handler *handler;
+ void *handler_ctx;
+
+ int fd;
+ GIOChannel *channel;
+ GSource *source;
+
+ char buffer[8192];
+};
+
+static gboolean
+udp_in_event(G_GNUC_UNUSED GIOChannel *source,
+ G_GNUC_UNUSED GIOCondition condition,
+ gpointer data)
+{
+ struct udp_server *udp = data;
+
+ struct sockaddr_storage address_storage;
+ struct sockaddr *address = (struct sockaddr *)&address_storage;
+ socklen_t address_length = sizeof(address_storage);
+
+ ssize_t nbytes = recvfrom(udp->fd, udp->buffer, sizeof(udp->buffer),
+ MSG_DONTWAIT,
+ address, &address_length);
+ if (nbytes <= 0)
+ return true;
+
+ udp->handler->datagram(udp->fd, udp->buffer, nbytes,
+ address, address_length, udp->handler_ctx);
+ return true;
+}
+
+struct udp_server *
+udp_server_new(unsigned port,
+ const struct udp_server_handler *handler, void *ctx,
+ GError **error_r)
+{
+ int fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ g_set_error(error_r, udp_server_quark(), errno,
+ "failed to create UDP socket: %s",
+ g_strerror(errno));
+ return NULL;
+ }
+
+ const struct sockaddr_in address = {
+ .sin_family = AF_INET,
+ .sin_addr = {
+ .s_addr = htonl(INADDR_ANY),
+ },
+ .sin_port = htons(port),
+ };
+
+ if (bind(fd, (const struct sockaddr *)&address, sizeof(address)) < 0) {
+ g_set_error(error_r, udp_server_quark(), errno,
+ "failed to bind UDP port %u: %s",
+ port, g_strerror(errno));
+ close(fd);
+ return NULL;
+ }
+
+ struct udp_server *udp = g_new(struct udp_server, 1);
+ udp->handler = handler;
+ udp->handler_ctx = ctx;
+
+ udp->fd = fd;
+#ifndef G_OS_WIN32
+ udp->channel = g_io_channel_unix_new(fd);
+#else
+ udp->channel = g_io_channel_win32_new_socket(fd);
+#endif
+ /* NULL encoding means the stream is binary safe */
+ g_io_channel_set_encoding(udp->channel, NULL, NULL);
+ /* no buffering */
+ g_io_channel_set_buffered(udp->channel, false);
+
+ udp->source = g_io_create_watch(udp->channel, G_IO_IN);
+ g_source_set_callback(udp->source, (GSourceFunc)udp_in_event, udp,
+ NULL);
+ g_source_attach(udp->source, io_thread_context());
+
+ return udp;
+}
+
+void
+udp_server_free(struct udp_server *udp)
+{
+ g_source_destroy(udp->source);
+ g_source_unref(udp->source);
+ g_io_channel_unref(udp->channel);
+ close(udp->fd);
+ g_free(udp);
+}
diff --git a/src/udp_server.h b/src/udp_server.h
new file mode 100644
index 000000000..9e3471a45
--- /dev/null
+++ b/src/udp_server.h
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_UDP_SERVER_H
+#define MPD_UDP_SERVER_H
+
+#include <glib.h>
+
+#include <stddef.h>
+
+struct sockaddr;
+
+struct udp_server_handler {
+ /**
+ * A datagram was received.
+ */
+ void (*datagram)(int fd, const void *data, size_t length,
+ const struct sockaddr *source_address,
+ size_t source_address_length, void *ctx);
+};
+
+static inline GQuark
+udp_server_quark(void)
+{
+ return g_quark_from_static_string("udp_server");
+}
+
+struct udp_server *
+udp_server_new(unsigned port,
+ const struct udp_server_handler *handler, void *ctx,
+ GError **error_r);
+
+void
+udp_server_free(struct udp_server *udp);
+
+#endif