ntp_server: move code to udp_server.c
This commit is contained in:
parent
195496333b
commit
74a39c715b
@ -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 \
|
||||
|
@ -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, ¤t_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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
130
src/udp_server.c
Normal file
130
src/udp_server.c
Normal file
@ -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);
|
||||
}
|
52
src/udp_server.h
Normal file
52
src/udp_server.h
Normal file
@ -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
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user