diff options
-rw-r--r-- | Makefile.am | 14 | ||||
-rw-r--r-- | src/tcp_connect.c | 250 | ||||
-rw-r--r-- | src/tcp_connect.h | 96 | ||||
-rw-r--r-- | src/tcp_socket.c | 377 | ||||
-rw-r--r-- | src/tcp_socket.h | 61 | ||||
-rw-r--r-- | src/udp_server.c | 140 | ||||
-rw-r--r-- | src/udp_server.h | 52 |
7 files changed, 0 insertions, 990 deletions
diff --git a/Makefile.am b/Makefile.am index a8ee39de5..332b51d9e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -290,9 +290,6 @@ src_mpd_SOURCES = \ src/client_subscribe.h \ src/client_subscribe.c \ src/client_file.c src/client_file.h \ - src/tcp_connect.c src/tcp_connect.h \ - src/tcp_socket.c src/tcp_socket.h \ - src/udp_server.c src/udp_server.h \ src/server_socket.c \ src/listen.c \ src/log.c \ @@ -1000,7 +997,6 @@ noinst_PROGRAMS = \ $(C_TESTS) \ test/read_conf \ test/run_resolver \ - test/run_tcp_connect \ test/run_input \ test/dump_text_file \ test/dump_playlist \ @@ -1031,14 +1027,6 @@ test_run_resolver_LDADD = \ test_run_resolver_SOURCES = test/run_resolver.c \ src/resolver.c -test_run_tcp_connect_LDADD = \ - $(GLIB_LIBS) -test_run_tcp_connect_SOURCES = test/run_tcp_connect.c \ - src/io_thread.c src/io_thread.h \ - src/fd_util.c \ - src/resolver.c \ - src/tcp_connect.c - test_run_input_LDADD = \ $(INPUT_LIBS) \ $(ARCHIVE_LIBS) \ @@ -1249,8 +1237,6 @@ 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/tcp_socket.c src/tcp_socket.h \ src/audio_check.c \ src/audio_format.c \ src/audio_parser.c \ diff --git a/src/tcp_connect.c b/src/tcp_connect.c deleted file mode 100644 index 291114f4b..000000000 --- a/src/tcp_connect.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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 "config.h" -#include "tcp_connect.h" -#include "fd_util.h" -#include "io_thread.h" -#include "glib_socket.h" - -#include <assert.h> -#include <errno.h> - -#ifdef WIN32 -#include <ws2tcpip.h> -#include <winsock.h> -#else -#include <sys/socket.h> -#include <unistd.h> -#endif - -struct tcp_connect { - const struct tcp_connect_handler *handler; - void *handler_ctx; - - int fd; - GSource *source; - - unsigned timeout_ms; - GSource *timeout_source; -}; - -static bool -is_in_progress_errno(int e) -{ -#ifdef WIN32 - return e == WSAEINPROGRESS || e == WSAEWOULDBLOCK; -#else - return e == EINPROGRESS; -#endif -} - -static gboolean -tcp_connect_event(G_GNUC_UNUSED GIOChannel *source, - G_GNUC_UNUSED GIOCondition condition, - gpointer data) -{ - struct tcp_connect *c = data; - - assert(c->source != NULL); - assert(c->timeout_source != NULL); - - /* clear the socket source */ - g_source_unref(c->source); - c->source = NULL; - - /* delete the timeout source */ - g_source_destroy(c->timeout_source); - g_source_unref(c->timeout_source); - c->timeout_source = NULL; - - /* obtain the connect result */ - int s_err = 0; - socklen_t s_err_size = sizeof(s_err); - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, - (char*)&s_err, &s_err_size) < 0) - s_err = errno; - - if (s_err == 0) { - /* connection established successfully */ - - c->handler->success(c->fd, c->handler_ctx); - } else { - /* there was an I/O error; close the socket and pass - the error to the handler */ - - close_socket(c->fd); - - GError *error = - g_error_new_literal(g_file_error_quark(), s_err, - g_strerror(s_err)); - c->handler->error(error, c->handler_ctx); - } - - return false; -} - -static gboolean -tcp_connect_timeout(gpointer data) -{ - struct tcp_connect *c = data; - - assert(c->source != NULL); - assert(c->timeout_source != NULL); - - /* clear the timeout source */ - g_source_unref(c->timeout_source); - c->timeout_source = NULL; - - /* delete the socket source */ - g_source_destroy(c->source); - g_source_unref(c->source); - c->source = NULL; - - /* report timeout to handler */ - c->handler->timeout(c->handler_ctx); - - return false; -} - -static gpointer -tcp_connect_init(gpointer data) -{ - struct tcp_connect *c = data; - - /* create a connect source */ - GIOChannel *channel = g_io_channel_new_socket(c->fd); - c->source = g_io_create_watch(channel, G_IO_OUT); - g_io_channel_unref(channel); - - g_source_set_callback(c->source, (GSourceFunc)tcp_connect_event, c, - NULL); - g_source_attach(c->source, io_thread_context()); - - /* create a timeout source */ - if (c->timeout_ms > 0) - c->timeout_source = - io_thread_timeout_add(c->timeout_ms, - tcp_connect_timeout, c); - - return NULL; -} - -void -tcp_connect_address(const struct sockaddr *address, size_t address_length, - unsigned timeout_ms, - const struct tcp_connect_handler *handler, void *ctx, - struct tcp_connect **handle_r) -{ - assert(address != NULL); - assert(address_length > 0); - assert(handler != NULL); - assert(handler->success != NULL); - assert(handler->error != NULL); - assert(handler->canceled != NULL); - assert(handler->timeout != NULL || timeout_ms == 0); - assert(handle_r != NULL); - assert(*handle_r == NULL); - - int fd = socket_cloexec_nonblock(address->sa_family, SOCK_STREAM, 0); - if (fd < 0) { - GError *error = - g_error_new_literal(g_file_error_quark(), errno, - g_strerror(errno)); - handler->error(error, ctx); - return; - } - - int ret = connect(fd, address, address_length); - if (ret >= 0) { - /* quick connect, no I/O thread */ - handler->success(fd, ctx); - return; - } - - if (!is_in_progress_errno(errno)) { - GError *error = - g_error_new_literal(g_file_error_quark(), errno, - g_strerror(errno)); - close_socket(fd); - handler->error(error, ctx); - return; - } - - /* got EINPROGRESS, use the I/O thread to wait for the - operation to finish */ - - struct tcp_connect *c = g_new(struct tcp_connect, 1); - c->handler = handler; - c->handler_ctx = ctx; - c->fd = fd; - c->source = NULL; - c->timeout_ms = timeout_ms; - c->timeout_source = NULL; - - *handle_r = c; - - io_thread_call(tcp_connect_init, c); -} - -static gpointer -tcp_connect_cancel_callback(gpointer data) -{ - struct tcp_connect *c = data; - - assert((c->source == NULL) == (c->timeout_source == NULL)); - - if (c->source == NULL) - return NULL; - - /* delete the socket source */ - g_source_destroy(c->source); - g_source_unref(c->source); - c->source = NULL; - - /* delete the timeout source */ - g_source_destroy(c->timeout_source); - g_source_unref(c->timeout_source); - c->timeout_source = NULL; - - /* close the socket */ - close_socket(c->fd); - - /* notify the handler */ - c->handler->canceled(c->handler_ctx); - - return NULL; -} - -void -tcp_connect_cancel(struct tcp_connect *c) -{ - if (c->source == NULL) - return; - - io_thread_call(tcp_connect_cancel_callback, c); -} - -void -tcp_connect_free(struct tcp_connect *c) -{ - assert(c->source == NULL); - - g_free(c); -} diff --git a/src/tcp_connect.h b/src/tcp_connect.h deleted file mode 100644 index bdbe85c14..000000000 --- a/src/tcp_connect.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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_TCP_CONNECT_H -#define MPD_TCP_CONNECT_H - -#include <glib.h> - -struct sockaddr; - -struct tcp_connect_handler { - /** - * The connection was established successfully. - * - * @param fd a file descriptor that must be closed with - * close_socket() when finished - */ - void (*success)(int fd, void *ctx); - - /** - * An error has occurred. The method is responsible for - * freeing the GError. - */ - void (*error)(GError *error, void *ctx); - - /** - * The connection could not be established in the specified - * time span. - */ - void (*timeout)(void *ctx); - - /** - * The operation was canceled before a result was available. - */ - void (*canceled)(void *ctx); -}; - -struct tcp_connect; - -/** - * Establish a TCP connection to the specified address. - * - * Note that the result may be available before this function returns. - * - * The caller must free this object with tcp_connect_free(). - * - * @param timeout_ms time out after this number of milliseconds; 0 - * means no timeout - * @param handle_r a handle that can be used to cancel the operation; - * the caller must initialize it to NULL - */ -void -tcp_connect_address(const struct sockaddr *address, size_t address_length, - unsigned timeout_ms, - const struct tcp_connect_handler *handler, void *ctx, - struct tcp_connect **handle_r); - -/** - * Cancel the operation. It is possible that the result is delivered - * before the operation has been canceled; in that case, the - * canceled() handler method will not be invoked. - * - * Even after calling this function, tcp_connect_free() must still be - * called to free memory. - */ -void -tcp_connect_cancel(struct tcp_connect *handle); - -/** - * Free memory used by this object. - * - * This function is not thread safe. It must not be called while - * other threads are still working with it. If no callback has been - * invoked so far, then you must call tcp_connect_cancel() to release - * I/O thread resources, before calling this function. - */ -void -tcp_connect_free(struct tcp_connect *handle); - -#endif diff --git a/src/tcp_socket.c b/src/tcp_socket.c deleted file mode 100644 index bfed4dc56..000000000 --- a/src/tcp_socket.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * 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 "tcp_socket.h" -#include "fifo_buffer.h" -#include "io_thread.h" -#include "glib_socket.h" - -#include <assert.h> -#include <string.h> - -#ifdef WIN32 -#include <ws2tcpip.h> -#include <winsock.h> -#else -#include <sys/socket.h> -#include <netinet/in.h> -#endif - -struct tcp_socket { - const struct tcp_socket_handler *handler; - void *handler_ctx; - - GMutex *mutex; - - GIOChannel *channel; - GSource *in_source, *out_source; - - struct fifo_buffer *input, *output; -}; - -static gboolean -tcp_event(GIOChannel *source, GIOCondition condition, gpointer data); - -static void -tcp_socket_schedule_read(struct tcp_socket *s) -{ - assert(s->input != NULL); - assert(!fifo_buffer_is_full(s->input)); - - if (s->in_source != NULL) - return; - - s->in_source = g_io_create_watch(s->channel, - G_IO_IN|G_IO_ERR|G_IO_HUP); - g_source_set_callback(s->in_source, (GSourceFunc)tcp_event, s, NULL); - g_source_attach(s->in_source, io_thread_context()); -} - -static void -tcp_socket_unschedule_read(struct tcp_socket *s) -{ - if (s->in_source == NULL) - return; - - g_source_destroy(s->in_source); - g_source_unref(s->in_source); - s->in_source = NULL; -} - -static void -tcp_socket_schedule_write(struct tcp_socket *s) -{ - assert(s->output != NULL); - assert(!fifo_buffer_is_empty(s->output)); - - if (s->out_source != NULL) - return; - - s->out_source = g_io_create_watch(s->channel, G_IO_OUT); - g_source_set_callback(s->out_source, (GSourceFunc)tcp_event, s, NULL); - g_source_attach(s->out_source, io_thread_context()); -} - -static void -tcp_socket_unschedule_write(struct tcp_socket *s) -{ - if (s->out_source == NULL) - return; - - g_source_destroy(s->out_source); - g_source_unref(s->out_source); - s->out_source = NULL; -} - -/** - * Close the socket. Caller must lock the mutex. - */ -static void -tcp_socket_close(struct tcp_socket *s) -{ - tcp_socket_unschedule_read(s); - tcp_socket_unschedule_write(s); - - if (s->channel != NULL) { - g_io_channel_unref(s->channel); - s->channel = NULL; - } - - if (s->input != NULL) { - fifo_buffer_free(s->input); - s->input = NULL; - } - - if (s->output != NULL) { - fifo_buffer_free(s->output); - s->output = NULL; - } -} - -static gpointer -tcp_socket_close_callback(gpointer data) -{ - struct tcp_socket *s = data; - - g_mutex_lock(s->mutex); - tcp_socket_close(s); - g_mutex_unlock(s->mutex); - - return NULL; -} - -static void -tcp_socket_close_indirect(struct tcp_socket *s) -{ - io_thread_call(tcp_socket_close_callback, s); - - assert(s->channel == NULL); - assert(s->in_source == NULL); - assert(s->out_source == NULL); -} - -static void -tcp_handle_input(struct tcp_socket *s) -{ - size_t length; - const void *p = fifo_buffer_read(s->input, &length); - if (p == NULL) - return; - - g_mutex_unlock(s->mutex); - size_t consumed = s->handler->data(p, length, s->handler_ctx); - g_mutex_lock(s->mutex); - if (consumed > 0 && s->input != NULL) - fifo_buffer_consume(s->input, consumed); -} - -static bool -tcp_in_event(struct tcp_socket *s) -{ - assert(s != NULL); - assert(s->channel != NULL); - - g_mutex_lock(s->mutex); - - size_t max_length; - void *p = fifo_buffer_write(s->input, &max_length); - if (p == NULL) { - GError *error = g_error_new_literal(tcp_socket_quark(), 0, - "buffer overflow"); - tcp_socket_close(s); - g_mutex_unlock(s->mutex); - s->handler->error(error, s->handler_ctx); - return false; - } - - gsize bytes_read; - GError *error = NULL; - GIOStatus status = g_io_channel_read_chars(s->channel, - p, max_length, - &bytes_read, &error); - switch (status) { - case G_IO_STATUS_NORMAL: - fifo_buffer_append(s->input, bytes_read); - tcp_handle_input(s); - g_mutex_unlock(s->mutex); - return true; - - case G_IO_STATUS_AGAIN: - /* try again later */ - g_mutex_unlock(s->mutex); - return true; - - case G_IO_STATUS_EOF: - /* peer disconnected */ - tcp_socket_close(s); - g_mutex_unlock(s->mutex); - s->handler->disconnected(s->handler_ctx); - return false; - - case G_IO_STATUS_ERROR: - /* I/O error */ - tcp_socket_close(s); - g_mutex_unlock(s->mutex); - s->handler->error(error, s->handler_ctx); - return false; - } - - /* unreachable */ - assert(false); - return true; -} - -static bool -tcp_out_event(struct tcp_socket *s) -{ - assert(s != NULL); - assert(s->channel != NULL); - - g_mutex_lock(s->mutex); - - size_t length; - const void *p = fifo_buffer_read(s->output, &length); - if (p == NULL) { - /* no more data in the output buffer, remove the - output event */ - tcp_socket_unschedule_write(s); - g_mutex_unlock(s->mutex); - return false; - } - - gsize bytes_written; - GError *error = NULL; - GIOStatus status = g_io_channel_write_chars(s->channel, p, length, - &bytes_written, &error); - switch (status) { - case G_IO_STATUS_NORMAL: - fifo_buffer_consume(s->output, bytes_written); - g_mutex_unlock(s->mutex); - return true; - - case G_IO_STATUS_AGAIN: - tcp_socket_schedule_write(s); - g_mutex_unlock(s->mutex); - return true; - - case G_IO_STATUS_EOF: - /* peer disconnected */ - tcp_socket_close(s); - g_mutex_unlock(s->mutex); - s->handler->disconnected(s->handler_ctx); - return false; - - case G_IO_STATUS_ERROR: - /* I/O error */ - tcp_socket_close(s); - g_mutex_unlock(s->mutex); - s->handler->error(error, s->handler_ctx); - return false; - } - - /* unreachable */ - g_mutex_unlock(s->mutex); - assert(false); - return true; -} - -static gboolean -tcp_event(G_GNUC_UNUSED GIOChannel *source, GIOCondition condition, - gpointer data) -{ - struct tcp_socket *s = data; - - assert(source == s->channel); - - switch (condition) { - case G_IO_IN: - case G_IO_PRI: - return tcp_in_event(s); - - case G_IO_OUT: - return tcp_out_event(s); - - case G_IO_ERR: - case G_IO_HUP: - case G_IO_NVAL: - tcp_socket_close(s); - s->handler->disconnected(s->handler_ctx); - return false; - } - - /* unreachable */ - assert(false); - return false; -} - -struct tcp_socket * -tcp_socket_new(int fd, - const struct tcp_socket_handler *handler, void *ctx) -{ - assert(fd >= 0); - assert(handler != NULL); - assert(handler->data != NULL); - assert(handler->error != NULL); - assert(handler->disconnected != NULL); - - struct tcp_socket *s = g_new(struct tcp_socket, 1); - s->handler = handler; - s->handler_ctx = ctx; - s->mutex = g_mutex_new(); - - g_mutex_lock(s->mutex); - - s->channel = g_io_channel_new_socket(fd); - /* GLib is responsible for closing the file descriptor */ - g_io_channel_set_close_on_unref(s->channel, true); - /* NULL encoding means the stream is binary safe */ - g_io_channel_set_encoding(s->channel, NULL, NULL); - /* no buffering */ - g_io_channel_set_buffered(s->channel, false); - - s->input = fifo_buffer_new(4096); - s->output = fifo_buffer_new(4096); - - s->in_source = NULL; - s->out_source = NULL; - - tcp_socket_schedule_read(s); - - g_mutex_unlock(s->mutex); - - return s; -} - -void -tcp_socket_free(struct tcp_socket *s) -{ - tcp_socket_close_indirect(s); - g_mutex_free(s->mutex); - g_free(s); -} - -bool -tcp_socket_send(struct tcp_socket *s, const void *data, size_t length) -{ - assert(s != NULL); - - g_mutex_lock(s->mutex); - - if (s->output == NULL || s->channel == NULL) { - /* already disconnected */ - g_mutex_unlock(s->mutex); - return false; - } - - size_t max_length; - void *p = fifo_buffer_write(s->output, &max_length); - if (p == NULL || max_length < length) { - /* buffer is full */ - g_mutex_unlock(s->mutex); - return false; - } - - memcpy(p, data, length); - fifo_buffer_append(s->output, length); - tcp_socket_schedule_write(s); - - g_mutex_unlock(s->mutex); - return true; -} - diff --git a/src/tcp_socket.h b/src/tcp_socket.h deleted file mode 100644 index b6b367b86..000000000 --- a/src/tcp_socket.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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_TCP_SOCKET_H -#define MPD_TCP_SOCKET_H - -#include <glib.h> - -#include <stdbool.h> -#include <stddef.h> - -struct sockaddr; - -struct tcp_socket_handler { - /** - * New data has arrived. - * - * @return the number of bytes consumed; 0 if more data is - * needed - */ - size_t (*data)(const void *data, size_t length, void *ctx); - - void (*error)(GError *error, void *ctx); - - void (*disconnected)(void *ctx); -}; - -static inline GQuark -tcp_socket_quark(void) -{ - return g_quark_from_static_string("tcp_socket"); -} - -G_GNUC_MALLOC -struct tcp_socket * -tcp_socket_new(int fd, - const struct tcp_socket_handler *handler, void *ctx); - -void -tcp_socket_free(struct tcp_socket *s); - -bool -tcp_socket_send(struct tcp_socket *s, const void *data, size_t length); - -#endif diff --git a/src/udp_server.c b/src/udp_server.c deleted file mode 100644 index f96b40b6b..000000000 --- a/src/udp_server.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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_socket.h" -#include "gcc.h" - -#include <glib.h> -#include <unistd.h> -#include <sys/time.h> -#include <errno.h> - -#ifdef WIN32 -#include <ws2tcpip.h> -#include <winsock.h> -#else -#include <sys/socket.h> -#include <netinet/in.h> -#endif - -#if GCC_CHECK_VERSION(4, 2) -/* allow C99 initialisers on struct sockaddr_in, even if the - (non-portable) attribute "sin_zero" is missing */ -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#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), -#ifdef WIN32 - 0, -#else - MSG_DONTWAIT, -#endif - 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 defined(__linux__) && !GCC_CHECK_VERSION(4, 2) - .sin_zero = { 0 }, -#endif - }; - - 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; - udp->channel = g_io_channel_new_socket(fd); - /* 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 deleted file mode 100644 index 9e3471a45..000000000 --- a/src/udp_server.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 |