aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-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
-rw-r--r--test/run_ntp_server.c83
7 files changed, 219 insertions, 142 deletions
diff --git a/Makefile.am b/Makefile.am
index b6947e137..dae71c209 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -294,6 +294,7 @@ src_mpd_SOURCES = \
src/client_message.c \
src/client_subscribe.h \
src/client_subscribe.c \
+ src/udp_server.c src/udp_server.h \
src/server_socket.c \
src/listen.c \
src/log.c \
@@ -1016,6 +1017,7 @@ test_run_ntp_server_LDADD = $(MPD_LIBS) \
test_run_ntp_server_SOURCES = test/run_ntp_server.c \
test/signals.c test/signals.h \
src/io_thread.c src/io_thread.h \
+ src/udp_server.c src/udp_server.h \
src/ntp_server.c src/ntp_server.h
test_run_filter_CPPFLAGS = $(AM_CPPFLAGS)
@@ -1122,6 +1124,7 @@ test_run_output_SOURCES = test/run_output.c \
test/stdbin.h \
src/conf.c src/tokenizer.c src/utils.c src/string_util.c src/log.c \
src/io_thread.c src/io_thread.h \
+ src/udp_server.c src/udp_server.h \
src/audio_check.c \
src/audio_format.c \
src/audio_parser.c \
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
diff --git a/test/run_ntp_server.c b/test/run_ntp_server.c
index db24059ab..6f732a074 100644
--- a/test/run_ntp_server.c
+++ b/test/run_ntp_server.c
@@ -46,78 +46,6 @@ on_quit(void)
io_thread_quit();
}
-static int bind_host(int sd, char *hostname, unsigned long ulAddr,
- unsigned short *port)
-{
- struct sockaddr_in my_addr;
- socklen_t nlen = sizeof(struct sockaddr);
- struct hostent *h;
-
- memset(&my_addr, 0, sizeof(my_addr));
- /* use specified hostname */
- if (hostname) {
- /* get server IP address (no check if input is IP address or DNS name) */
- h = gethostbyname(hostname);
- if (h == NULL) {
- if (strstr(hostname, "255.255.255.255") == hostname) {
- my_addr.sin_addr.s_addr=-1;
- } else {
- if ((my_addr.sin_addr.s_addr = inet_addr(hostname)) == 0xFFFFFFFF) {
- return -1;
- }
- }
- my_addr.sin_family = AF_INET;
- } else {
- my_addr.sin_family = h->h_addrtype;
- memcpy((char *) &my_addr.sin_addr.s_addr,
- h->h_addr_list[0], h->h_length);
- }
- } else {
- // if hostname=NULL, use INADDR_ANY
- if (ulAddr)
- my_addr.sin_addr.s_addr = ulAddr;
- else
- my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- my_addr.sin_family = AF_INET;
- }
-
- /* bind a specified port */
- my_addr.sin_port = htons(*port);
-
- if (bind(sd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
- return -1;
- }
-
- if (*port == 0) {
- getsockname(sd, (struct sockaddr *) &my_addr, &nlen);
- *port = ntohs(my_addr.sin_port);
- }
-
- return 0;
-}
-
-static int
-open_udp_socket(char *hostname, unsigned short *port)
-{
- int sd;
- int size = 30000;
-
- /* socket creation */
- sd = socket(PF_INET, SOCK_DGRAM, 0);
- if (sd < 0) {
- return -1;
- }
- if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) < 0) {
- return -1;
- }
- if (bind_host(sd, hostname, 0, port)) {
- close(sd);
- return -1;
- }
-
- return sd;
-}
-
int
main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
{
@@ -128,15 +56,14 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
struct ntp_server ntp;
ntp_server_init(&ntp);
- int fd = open_udp_socket(NULL, &ntp.port);
- if (fd < 0) {
- g_printerr("Failed to create UDP socket\n");
- ntp_server_close(&ntp);
+ GError *error = NULL;
+ if (!ntp_server_open(&ntp, &error)) {
+ io_thread_deinit();
+ g_printerr("%s\n", error->message);
+ g_error_free(error);
return EXIT_FAILURE;
}
- ntp_server_open(&ntp, fd);
-
io_thread_run();
ntp_server_close(&ntp);