main: use the GLib main loop
This is a rather huge patch, which unfortunately cannot be splitted. Instead of using our custom ioops.h library, convert everything to use the GLib main loop.
This commit is contained in:
parent
03e650aa9e
commit
71e7ce5d8e
@ -909,7 +909,7 @@ esac
|
||||
|
||||
if test x$with_zeroconf != xno; then
|
||||
if test x$with_zeroconf = xavahi || test x$with_zeroconf = xauto; then
|
||||
PKG_CHECK_MODULES([AVAHI], [avahi-client],
|
||||
PKG_CHECK_MODULES([AVAHI], [avahi-client avahi-glib],
|
||||
[found_avahi=1;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])]
|
||||
MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS",
|
||||
[found_avahi=0])
|
||||
|
@ -78,7 +78,6 @@ mpd_headers = \
|
||||
strset.h \
|
||||
utils.h \
|
||||
volume.h \
|
||||
ioops.h \
|
||||
zeroconf.h zeroconf-internal.h \
|
||||
locate.h \
|
||||
stored_playlist.h \
|
||||
@ -120,7 +119,6 @@ mpd_SOURCES = \
|
||||
input_stream.c \
|
||||
input_file.c \
|
||||
client.c \
|
||||
ioops.c \
|
||||
list.c \
|
||||
listen.c \
|
||||
log.c \
|
||||
|
155
src/client.c
155
src/client.c
@ -22,7 +22,6 @@
|
||||
#include "listen.h"
|
||||
#include "permission.h"
|
||||
#include "utils.h"
|
||||
#include "ioops.h"
|
||||
#include "main_notify.h"
|
||||
#include "dlist.h"
|
||||
#include "idle.h"
|
||||
@ -78,6 +77,8 @@ struct client {
|
||||
size_t bufferPos;
|
||||
|
||||
int fd; /* file descriptor; -1 if expired */
|
||||
GIOChannel *channel;
|
||||
|
||||
unsigned permission;
|
||||
|
||||
/** the uid of the client process, or -1 if unknown */
|
||||
@ -134,12 +135,20 @@ void client_set_permission(struct client *client, unsigned permission)
|
||||
|
||||
static inline void client_set_expired(struct client *client)
|
||||
{
|
||||
if (client->channel != NULL) {
|
||||
g_io_channel_unref(client->channel);
|
||||
client->channel = NULL;
|
||||
}
|
||||
|
||||
if (client->fd >= 0) {
|
||||
xclose(client->fd);
|
||||
client->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
client_in_event(GIOChannel *source, GIOCondition condition, gpointer data);
|
||||
|
||||
static void client_init(struct client *client, int fd)
|
||||
{
|
||||
static unsigned int next_client_num;
|
||||
@ -152,6 +161,10 @@ static void client_init(struct client *client, int fd)
|
||||
client->bufferPos = 0;
|
||||
client->fd = fd;
|
||||
set_nonblocking(fd);
|
||||
|
||||
client->channel = g_io_channel_unix_new(client->fd);
|
||||
g_io_add_watch(client->channel, G_IO_IN, client_in_event, client);
|
||||
|
||||
client->lastTime = time(NULL);
|
||||
client->cmd_list = NULL;
|
||||
client->deferred_send = g_queue_new();
|
||||
@ -436,91 +449,81 @@ static int client_read(struct client *client)
|
||||
return COMMAND_RETURN_CLOSE;
|
||||
}
|
||||
|
||||
static void client_manager_register_read_fd(fd_set * fds, int *fdmax)
|
||||
static gboolean
|
||||
client_out_event(G_GNUC_UNUSED GIOChannel *source,
|
||||
G_GNUC_UNUSED GIOCondition condition,
|
||||
gpointer data);
|
||||
|
||||
static gboolean
|
||||
client_in_event(G_GNUC_UNUSED GIOChannel *source,
|
||||
G_GNUC_UNUSED GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
struct client *client;
|
||||
|
||||
FD_ZERO(fds);
|
||||
addListenSocketsToFdSet(fds, fdmax);
|
||||
|
||||
list_for_each_entry(client, &clients, siblings) {
|
||||
if (!client_is_expired(client) &&
|
||||
g_queue_is_empty(client->deferred_send)) {
|
||||
FD_SET(client->fd, fds);
|
||||
if (*fdmax < client->fd)
|
||||
*fdmax = client->fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void client_manager_register_write_fd(fd_set * fds, int *fdmax)
|
||||
{
|
||||
struct client *client;
|
||||
|
||||
FD_ZERO(fds);
|
||||
|
||||
list_for_each_entry(client, &clients, siblings) {
|
||||
if (client->fd >= 0 && !client_is_expired(client)
|
||||
&& !g_queue_is_empty(client->deferred_send)) {
|
||||
FD_SET(client->fd, fds);
|
||||
if (*fdmax < client->fd)
|
||||
*fdmax = client->fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int client_manager_io(void)
|
||||
{
|
||||
fd_set rfds;
|
||||
fd_set wfds;
|
||||
fd_set efds;
|
||||
struct client *client, *n;
|
||||
struct client *client = data;
|
||||
int ret;
|
||||
int fdmax = 0;
|
||||
|
||||
FD_ZERO( &efds );
|
||||
client_manager_register_read_fd(&rfds, &fdmax);
|
||||
client_manager_register_write_fd(&wfds, &fdmax);
|
||||
if (client_is_expired(client))
|
||||
return false;
|
||||
|
||||
registered_IO_add_fds(&fdmax, &rfds, &wfds, &efds);
|
||||
client->lastTime = time(NULL);
|
||||
|
||||
main_notify_lock();
|
||||
ret = select(fdmax + 1, &rfds, &wfds, &efds, NULL);
|
||||
main_notify_unlock();
|
||||
ret = client_read(client);
|
||||
switch (ret) {
|
||||
case COMMAND_RETURN_KILL:
|
||||
client_close(client);
|
||||
g_main_loop_quit(NULL);
|
||||
return false;
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
return 0;
|
||||
|
||||
g_error("select() failed: %s", strerror(errno));
|
||||
case COMMAND_RETURN_CLOSE:
|
||||
client_close(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
registered_IO_consume_fds(&ret, &rfds, &wfds, &efds);
|
||||
|
||||
getConnections(&rfds);
|
||||
|
||||
list_for_each_entry_safe(client, n, &clients, siblings) {
|
||||
if (FD_ISSET(client->fd, &rfds)) {
|
||||
ret = client_read(client);
|
||||
if (ret == COMMAND_RETURN_KILL)
|
||||
return COMMAND_RETURN_KILL;
|
||||
if (ret == COMMAND_RETURN_CLOSE) {
|
||||
client_close(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(!client_is_expired(client));
|
||||
|
||||
client->lastTime = time(NULL);
|
||||
}
|
||||
if (!client_is_expired(client) &&
|
||||
FD_ISSET(client->fd, &wfds)) {
|
||||
client_write_deferred(client);
|
||||
client->lastTime = time(NULL);
|
||||
}
|
||||
if (client_is_expired(client)) {
|
||||
client_close(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!g_queue_is_empty(client->deferred_send)) {
|
||||
/* deferred buffers exist: schedule write */
|
||||
g_io_add_watch(client->channel, G_IO_OUT,
|
||||
client_out_event, client);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read more */
|
||||
return true;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
client_out_event(G_GNUC_UNUSED GIOChannel *source,
|
||||
G_GNUC_UNUSED GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
struct client *client = data;
|
||||
|
||||
if (client_is_expired(client))
|
||||
return false;
|
||||
|
||||
client_write_deferred(client);
|
||||
|
||||
if (client_is_expired(client)) {
|
||||
client_close(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
client->lastTime = time(NULL);
|
||||
|
||||
if (g_queue_is_empty(client->deferred_send)) {
|
||||
/* done sending deferred buffers exist: schedule
|
||||
read */
|
||||
g_io_add_watch(client->channel, G_IO_IN,
|
||||
client_in_event, client);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* write more */
|
||||
return true;
|
||||
}
|
||||
|
||||
void client_manager_init(void)
|
||||
|
@ -29,7 +29,6 @@ struct sockaddr;
|
||||
|
||||
void client_manager_init(void);
|
||||
void client_manager_deinit(void);
|
||||
int client_manager_io(void);
|
||||
void client_manager_expire(void);
|
||||
|
||||
void client_new(int fd, const struct sockaddr *addr, int uid);
|
||||
|
87
src/ioops.c
87
src/ioops.c
@ -1,87 +0,0 @@
|
||||
/* the Music Player Daemon (MPD)
|
||||
* Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
|
||||
* This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "ioops.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Eventually the listener protocol will use this, too */
|
||||
|
||||
/*
|
||||
* functions and variables in this file are only used by a single thread and
|
||||
* thus do not need to be thread-safe
|
||||
*/
|
||||
|
||||
/* List of registered external IO handlers */
|
||||
static struct ioOps *ioList;
|
||||
|
||||
/* Add fds for all registered IO handlers */
|
||||
void registered_IO_add_fds(int *fdmax,
|
||||
fd_set * rfds, fd_set * wfds, fd_set * efds)
|
||||
{
|
||||
struct ioOps *o = ioList;
|
||||
|
||||
while (o) {
|
||||
struct ioOps *current = o;
|
||||
int fdnum;
|
||||
|
||||
assert(current->fdset);
|
||||
fdnum = current->fdset(rfds, wfds, efds);
|
||||
if (*fdmax < fdnum)
|
||||
*fdmax = fdnum;
|
||||
o = o->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Consume fds for all registered IO handlers */
|
||||
void registered_IO_consume_fds(int *selret,
|
||||
fd_set * rfds, fd_set * wfds, fd_set * efds)
|
||||
{
|
||||
struct ioOps *o = ioList;
|
||||
|
||||
while (o) {
|
||||
struct ioOps *current = o;
|
||||
|
||||
assert(current->consume);
|
||||
*selret = current->consume(*selret, rfds, wfds, efds);
|
||||
o = o->next;
|
||||
}
|
||||
}
|
||||
|
||||
void registerIO(struct ioOps *ops)
|
||||
{
|
||||
assert(ops != NULL);
|
||||
|
||||
ops->next = ioList;
|
||||
ioList = ops;
|
||||
ops->prev = NULL;
|
||||
if (ops->next)
|
||||
ops->next->prev = ops;
|
||||
}
|
||||
|
||||
void deregisterIO(struct ioOps *ops)
|
||||
{
|
||||
assert(ops != NULL);
|
||||
|
||||
if (ioList == ops)
|
||||
ioList = ops->next;
|
||||
else if (ops->prev != NULL)
|
||||
ops->prev->next = ops->next;
|
||||
}
|
||||
|
59
src/ioops.h
59
src/ioops.h
@ -1,59 +0,0 @@
|
||||
/* the Music Player Daemon (MPD)
|
||||
* Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
|
||||
* This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef MPD_IOOPS_H
|
||||
#define MPD_IOOPS_H
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
struct ioOps {
|
||||
struct ioOps *prev, *next;
|
||||
|
||||
/*
|
||||
* Called before each 'select' statement.
|
||||
* To register for IO, call FD_SET for each required queue
|
||||
* Return the highest fd number you registered
|
||||
*/
|
||||
int (*fdset) (fd_set * rfds, fd_set * wfds, fd_set * efds);
|
||||
|
||||
/*
|
||||
* Called after each 'select' statement.
|
||||
* fdCount is the number of fds total in all sets. It may be 0.
|
||||
* For each fd you registered for in (fdset), you should FD_CLR it from the
|
||||
* appropriate queue(s).
|
||||
* Return the total number of fds left in all sets (Ie, return fdCount
|
||||
* minus the number of times you called FD_CLR).
|
||||
*/
|
||||
int (*consume) (int fdCount, fd_set * rfds, fd_set * wfds,
|
||||
fd_set * efds);
|
||||
};
|
||||
|
||||
/* Call this to register your io operation handler struct */
|
||||
void registerIO(struct ioOps *ops);
|
||||
|
||||
/* Call this to deregister your io operation handler struct */
|
||||
void deregisterIO(struct ioOps *ops);
|
||||
|
||||
/* Add fds for all registered IO handlers */
|
||||
void registered_IO_add_fds(int *fdmax,
|
||||
fd_set * rfds, fd_set * wfds, fd_set * efds);
|
||||
|
||||
/* Consume fds for all registered IO handlers */
|
||||
void registered_IO_consume_fds(int *selret,
|
||||
fd_set * rfds, fd_set * wfds, fd_set * efds);
|
||||
#endif
|
44
src/listen.c
44
src/listen.c
@ -55,6 +55,9 @@ static int *listenSockets;
|
||||
static int numberOfListenSockets;
|
||||
int boundPort;
|
||||
|
||||
static gboolean
|
||||
listen_in_event(GIOChannel *source, GIOCondition condition, gpointer data);
|
||||
|
||||
static int establishListen(int pf, const struct sockaddr *addrp,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
@ -63,6 +66,7 @@ static int establishListen(int pf, const struct sockaddr *addrp,
|
||||
#ifdef HAVE_STRUCT_UCRED
|
||||
int passcred = 1;
|
||||
#endif
|
||||
GIOChannel *channel;
|
||||
|
||||
if ((sock = socket(pf, SOCK_STREAM, 0)) < 0)
|
||||
g_error("socket < 0");
|
||||
@ -90,6 +94,11 @@ static int establishListen(int pf, const struct sockaddr *addrp,
|
||||
|
||||
listenSockets[numberOfListenSockets - 1] = sock;
|
||||
|
||||
channel = g_io_channel_unix_new(sock);
|
||||
g_io_add_watch(channel, G_IO_IN,
|
||||
listen_in_event, GINT_TO_POINTER(sock));
|
||||
g_io_channel_unref(channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -223,17 +232,6 @@ void listenOnPort(void)
|
||||
} while ((param = getNextConfigParam(CONF_BIND_TO_ADDRESS, param)));
|
||||
}
|
||||
|
||||
void addListenSocketsToFdSet(fd_set * fds, int *fdmax)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < numberOfListenSockets; i++) {
|
||||
FD_SET(listenSockets[i], fds);
|
||||
if (listenSockets[i] > *fdmax)
|
||||
*fdmax = listenSockets[i];
|
||||
}
|
||||
}
|
||||
|
||||
void closeAllListenSockets(void)
|
||||
{
|
||||
int i;
|
||||
@ -266,21 +264,21 @@ static int get_remote_uid(int fd)
|
||||
#endif
|
||||
}
|
||||
|
||||
void getConnections(fd_set * fds)
|
||||
static gboolean
|
||||
listen_in_event(G_GNUC_UNUSED GIOChannel *source,
|
||||
G_GNUC_UNUSED GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
int i;
|
||||
int fd = 0;
|
||||
int listen_fd = GPOINTER_TO_INT(data), fd;
|
||||
struct sockaddr sockAddr;
|
||||
socklen_t socklen = sizeof(sockAddr);
|
||||
|
||||
for (i = 0; i < numberOfListenSockets; i++) {
|
||||
if (FD_ISSET(listenSockets[i], fds)) {
|
||||
if ((fd = accept(listenSockets[i], &sockAddr, &socklen))
|
||||
>= 0) {
|
||||
client_new(fd, &sockAddr, get_remote_uid(fd));
|
||||
} else if (fd < 0 && errno != EINTR) {
|
||||
g_warning("Problems accept()'ing");
|
||||
}
|
||||
}
|
||||
fd = accept(listen_fd, &sockAddr, &socklen);
|
||||
if (fd >= 0) {
|
||||
client_new(fd, &sockAddr, get_remote_uid(fd));
|
||||
} else if (fd < 0 && errno != EINTR) {
|
||||
g_warning("Problems accept()'ing");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -19,17 +19,10 @@
|
||||
#ifndef MPD_LISTEN_H
|
||||
#define MPD_LISTEN_H
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
extern int boundPort;
|
||||
|
||||
void listenOnPort(void);
|
||||
|
||||
void getConnections(fd_set * fds);
|
||||
|
||||
void closeAllListenSockets(void);
|
||||
|
||||
/* fdmax should be initialized to something */
|
||||
void addListenSocketsToFdSet(fd_set * fds, int *fdmax);
|
||||
|
||||
#endif
|
||||
|
50
src/main.c
50
src/main.c
@ -180,9 +180,34 @@ static void killFromPidFile(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
timer_save_state_file(G_GNUC_UNUSED gpointer data)
|
||||
{
|
||||
g_debug("Saving state file");
|
||||
write_state_file();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
main_notify_triggered(void)
|
||||
{
|
||||
unsigned flags;
|
||||
|
||||
syncPlayerAndPlaylist();
|
||||
client_manager_expire();
|
||||
reap_update_task();
|
||||
|
||||
/* send "idle" notificaions to all subscribed
|
||||
clients */
|
||||
flags = idle_get();
|
||||
if (flags != 0)
|
||||
client_manager_idle_add(flags);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Options options;
|
||||
GMainLoop *main_loop;
|
||||
clock_t start;
|
||||
GTimer *save_state_timer;
|
||||
|
||||
@ -216,6 +241,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
changeToUser();
|
||||
|
||||
main_loop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
path_global_init();
|
||||
mapper_init();
|
||||
initPermissions();
|
||||
@ -258,26 +285,15 @@ int main(int argc, char *argv[])
|
||||
|
||||
save_state_timer = g_timer_new();
|
||||
|
||||
while (COMMAND_RETURN_KILL != client_manager_io() &&
|
||||
COMMAND_RETURN_KILL != handlePendingSignals()) {
|
||||
unsigned flags;
|
||||
g_timeout_add(5 * 60 * 1000, timer_save_state_file, NULL);
|
||||
|
||||
syncPlayerAndPlaylist();
|
||||
client_manager_expire();
|
||||
reap_update_task();
|
||||
/* run the main loop */
|
||||
|
||||
/* send "idle" notificaions to all subscribed
|
||||
clients */
|
||||
flags = idle_get();
|
||||
if (flags != 0)
|
||||
client_manager_idle_add(flags);
|
||||
g_main_loop_run(main_loop);
|
||||
|
||||
if (g_timer_elapsed(save_state_timer, NULL) >= 5 * 60) {
|
||||
g_debug("Saving state file");
|
||||
write_state_file();
|
||||
g_timer_start(save_state_timer);
|
||||
}
|
||||
}
|
||||
/* cleanup */
|
||||
|
||||
g_main_loop_unref(main_loop);
|
||||
|
||||
g_timer_destroy(save_state_timer);
|
||||
|
||||
|
@ -20,25 +20,15 @@
|
||||
|
||||
#include "main_notify.h"
|
||||
#include "utils.h"
|
||||
#include "ioops.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct ioOps main_notify_IO;
|
||||
static int main_pipe[2];
|
||||
GThread *main_task;
|
||||
|
||||
static int ioops_fdset(fd_set * rfds,
|
||||
G_GNUC_UNUSED fd_set * wfds,
|
||||
G_GNUC_UNUSED fd_set * efds)
|
||||
{
|
||||
FD_SET(main_pipe[0], rfds);
|
||||
return main_pipe[0];
|
||||
}
|
||||
|
||||
static void consume_pipe(void)
|
||||
{
|
||||
char buffer[256];
|
||||
@ -48,20 +38,20 @@ static void consume_pipe(void)
|
||||
FATAL("error reading from pipe: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
static int ioops_consume(int fd_count, fd_set * rfds,
|
||||
G_GNUC_UNUSED fd_set * wfds,
|
||||
G_GNUC_UNUSED fd_set * efds)
|
||||
static gboolean
|
||||
main_notify_event(G_GNUC_UNUSED GIOChannel *source,
|
||||
G_GNUC_UNUSED GIOCondition condition,
|
||||
G_GNUC_UNUSED gpointer data)
|
||||
{
|
||||
if (FD_ISSET(main_pipe[0], rfds)) {
|
||||
consume_pipe();
|
||||
FD_CLR(main_pipe[0], rfds);
|
||||
fd_count--;
|
||||
}
|
||||
return fd_count;
|
||||
consume_pipe();
|
||||
main_notify_triggered();
|
||||
return true;
|
||||
}
|
||||
|
||||
void init_main_notify(void)
|
||||
{
|
||||
GIOChannel *channel;
|
||||
|
||||
main_task = g_thread_self();
|
||||
|
||||
if (pipe(main_pipe) < 0)
|
||||
@ -69,15 +59,15 @@ void init_main_notify(void)
|
||||
if (set_nonblocking(main_pipe[1]) < 0)
|
||||
g_error("Couldn't set non-blocking I/O: %s", strerror(errno));
|
||||
|
||||
main_notify_IO.fdset = ioops_fdset;
|
||||
main_notify_IO.consume = ioops_consume;
|
||||
registerIO(&main_notify_IO);
|
||||
channel = g_io_channel_unix_new(main_pipe[0]);
|
||||
g_io_add_watch(channel, G_IO_IN, main_notify_event, NULL);
|
||||
g_io_channel_unref(channel);
|
||||
|
||||
main_task = g_thread_self();
|
||||
}
|
||||
|
||||
void deinit_main_notify(void)
|
||||
{
|
||||
deregisterIO(&main_notify_IO);
|
||||
xclose(main_pipe[0]);
|
||||
xclose(main_pipe[1]);
|
||||
}
|
||||
|
@ -37,4 +37,7 @@ void main_notify_lock(void);
|
||||
|
||||
void main_notify_unlock(void);
|
||||
|
||||
void
|
||||
main_notify_triggered(void);
|
||||
|
||||
#endif /* MAIN_NOTIFY_H */
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "zeroconf-internal.h"
|
||||
#include "listen.h"
|
||||
#include "utils.h"
|
||||
#include "ioops.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@ -31,148 +30,18 @@
|
||||
#include <avahi-common/malloc.h>
|
||||
#include <avahi-common/error.h>
|
||||
|
||||
#include <avahi-glib/glib-watch.h>
|
||||
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "avahi"
|
||||
|
||||
static struct ioOps zeroConfIo;
|
||||
|
||||
static char *avahiName;
|
||||
static int avahiRunning;
|
||||
static AvahiPoll avahiPoll;
|
||||
static AvahiGLibPoll *avahi_glib_poll;
|
||||
static const AvahiPoll *avahi_poll;
|
||||
static AvahiClient *avahiClient;
|
||||
static AvahiEntryGroup *avahiGroup;
|
||||
|
||||
static int avahiFdset(fd_set * rfds, fd_set * wfds, fd_set * efds);
|
||||
static int avahiFdconsume(int fdCount, fd_set * rfds, fd_set * wfds,
|
||||
fd_set * efds);
|
||||
|
||||
struct AvahiWatch {
|
||||
struct AvahiWatch *prev;
|
||||
struct AvahiWatch *next;
|
||||
int fd;
|
||||
AvahiWatchEvent requestedEvent;
|
||||
AvahiWatchEvent observedEvent;
|
||||
AvahiWatchCallback callback;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
struct AvahiTimeout {
|
||||
struct AvahiTimeout *prev;
|
||||
struct AvahiTimeout *next;
|
||||
struct timeval expiry;
|
||||
int enabled;
|
||||
AvahiTimeoutCallback callback;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
static AvahiWatch *avahiWatchList;
|
||||
static AvahiTimeout *avahiTimeoutList;
|
||||
|
||||
static AvahiWatch *avahiWatchNew(G_GNUC_UNUSED const AvahiPoll * api, int fd,
|
||||
AvahiWatchEvent event,
|
||||
AvahiWatchCallback callback, void *userdata)
|
||||
{
|
||||
struct AvahiWatch *newWatch = xmalloc(sizeof(struct AvahiWatch));
|
||||
|
||||
newWatch->fd = fd;
|
||||
newWatch->requestedEvent = event;
|
||||
newWatch->observedEvent = 0;
|
||||
newWatch->callback = callback;
|
||||
newWatch->userdata = userdata;
|
||||
|
||||
/* Insert at front of list */
|
||||
newWatch->next = avahiWatchList;
|
||||
avahiWatchList = newWatch;
|
||||
newWatch->prev = NULL;
|
||||
if (newWatch->next)
|
||||
newWatch->next->prev = newWatch;
|
||||
|
||||
return newWatch;
|
||||
}
|
||||
|
||||
static void avahiWatchUpdate(AvahiWatch * w, AvahiWatchEvent event)
|
||||
{
|
||||
assert(w != NULL);
|
||||
w->requestedEvent = event;
|
||||
}
|
||||
|
||||
static AvahiWatchEvent avahiWatchGetEvents(AvahiWatch * w)
|
||||
{
|
||||
assert(w != NULL);
|
||||
return w->observedEvent;
|
||||
}
|
||||
|
||||
static void avahiWatchFree(AvahiWatch * w)
|
||||
{
|
||||
assert(w != NULL);
|
||||
|
||||
if (avahiWatchList == w)
|
||||
avahiWatchList = w->next;
|
||||
else if (w->prev != NULL)
|
||||
w->prev->next = w->next;
|
||||
|
||||
free(w);
|
||||
}
|
||||
|
||||
static void avahiCheckExpiry(AvahiTimeout * t)
|
||||
{
|
||||
assert(t != NULL);
|
||||
if (t->enabled) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (timercmp(&now, &(t->expiry), >)) {
|
||||
t->enabled = 0;
|
||||
t->callback(t, t->userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void avahiTimeoutUpdate(AvahiTimeout * t, const struct timeval *tv)
|
||||
{
|
||||
assert(t != NULL);
|
||||
if (tv) {
|
||||
t->enabled = 1;
|
||||
t->expiry.tv_sec = tv->tv_sec;
|
||||
t->expiry.tv_usec = tv->tv_usec;
|
||||
} else {
|
||||
t->enabled = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void avahiTimeoutFree(AvahiTimeout * t)
|
||||
{
|
||||
assert(t != NULL);
|
||||
|
||||
if (avahiTimeoutList == t)
|
||||
avahiTimeoutList = t->next;
|
||||
else if (t->prev != NULL)
|
||||
t->prev->next = t->next;
|
||||
|
||||
free(t);
|
||||
}
|
||||
|
||||
static AvahiTimeout *avahiTimeoutNew(G_GNUC_UNUSED const AvahiPoll * api,
|
||||
const struct timeval *tv,
|
||||
AvahiTimeoutCallback callback,
|
||||
void *userdata)
|
||||
{
|
||||
struct AvahiTimeout *newTimeout = xmalloc(sizeof(struct AvahiTimeout));
|
||||
|
||||
newTimeout->callback = callback;
|
||||
newTimeout->userdata = userdata;
|
||||
|
||||
avahiTimeoutUpdate(newTimeout, tv);
|
||||
|
||||
/* Insert at front of list */
|
||||
newTimeout->next = avahiTimeoutList;
|
||||
avahiTimeoutList = newTimeout;
|
||||
newTimeout->prev = NULL;
|
||||
if (newTimeout->next)
|
||||
newTimeout->next->prev = newTimeout;
|
||||
|
||||
return newTimeout;
|
||||
}
|
||||
|
||||
static void avahiRegisterService(AvahiClient * c);
|
||||
|
||||
/* Callback when the EntryGroup changes state */
|
||||
@ -297,7 +166,7 @@ static void avahiClientCallback(AvahiClient * c, AvahiClientState state,
|
||||
if (avahiClient)
|
||||
avahi_client_free(avahiClient);
|
||||
avahiClient =
|
||||
avahi_client_new(&avahiPoll,
|
||||
avahi_client_new(avahi_poll,
|
||||
AVAHI_CLIENT_NO_FAIL,
|
||||
avahiClientCallback, NULL,
|
||||
&reason);
|
||||
@ -342,84 +211,6 @@ static void avahiClientCallback(AvahiClient * c, AvahiClientState state,
|
||||
}
|
||||
}
|
||||
|
||||
static int avahiFdset(fd_set * rfds, fd_set * wfds, fd_set * efds)
|
||||
{
|
||||
AvahiWatch *w;
|
||||
int maxfd = -1;
|
||||
if (!avahiRunning)
|
||||
return maxfd;
|
||||
for (w = avahiWatchList; w != NULL; w = w->next) {
|
||||
if (w->requestedEvent & AVAHI_WATCH_IN) {
|
||||
FD_SET(w->fd, rfds);
|
||||
}
|
||||
if (w->requestedEvent & AVAHI_WATCH_OUT) {
|
||||
FD_SET(w->fd, wfds);
|
||||
}
|
||||
if (w->requestedEvent & AVAHI_WATCH_ERR) {
|
||||
FD_SET(w->fd, efds);
|
||||
}
|
||||
if (w->requestedEvent & AVAHI_WATCH_HUP) {
|
||||
g_warning("No support for HUP events! (ignoring)");
|
||||
}
|
||||
|
||||
if (w->fd > maxfd)
|
||||
maxfd = w->fd;
|
||||
}
|
||||
return maxfd;
|
||||
}
|
||||
|
||||
static int avahiFdconsume(int fdCount, fd_set * rfds, fd_set * wfds,
|
||||
fd_set * efds)
|
||||
{
|
||||
int retval = fdCount;
|
||||
AvahiTimeout *t;
|
||||
AvahiWatch *w = avahiWatchList;
|
||||
|
||||
while (w != NULL && retval > 0) {
|
||||
AvahiWatch *current = w;
|
||||
current->observedEvent = 0;
|
||||
if (FD_ISSET(current->fd, rfds)) {
|
||||
current->observedEvent |= AVAHI_WATCH_IN;
|
||||
FD_CLR(current->fd, rfds);
|
||||
retval--;
|
||||
}
|
||||
if (FD_ISSET(current->fd, wfds)) {
|
||||
current->observedEvent |= AVAHI_WATCH_OUT;
|
||||
FD_CLR(current->fd, wfds);
|
||||
retval--;
|
||||
}
|
||||
if (FD_ISSET(current->fd, efds)) {
|
||||
current->observedEvent |= AVAHI_WATCH_ERR;
|
||||
FD_CLR(current->fd, efds);
|
||||
retval--;
|
||||
}
|
||||
|
||||
/* Advance to the next one right now, in case the callback
|
||||
* removes itself
|
||||
*/
|
||||
w = w->next;
|
||||
|
||||
if (current->observedEvent && avahiRunning) {
|
||||
current->callback(current, current->fd,
|
||||
current->observedEvent,
|
||||
current->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
t = avahiTimeoutList;
|
||||
while (t != NULL && avahiRunning) {
|
||||
AvahiTimeout *current = t;
|
||||
|
||||
/* Advance to the next one right now, in case the callback
|
||||
* removes itself
|
||||
*/
|
||||
t = t->next;
|
||||
avahiCheckExpiry(current);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void init_avahi(const char *serviceName)
|
||||
{
|
||||
int error;
|
||||
@ -432,16 +223,10 @@ void init_avahi(const char *serviceName)
|
||||
|
||||
avahiRunning = 1;
|
||||
|
||||
avahiPoll.userdata = NULL;
|
||||
avahiPoll.watch_new = avahiWatchNew;
|
||||
avahiPoll.watch_update = avahiWatchUpdate;
|
||||
avahiPoll.watch_get_events = avahiWatchGetEvents;
|
||||
avahiPoll.watch_free = avahiWatchFree;
|
||||
avahiPoll.timeout_new = avahiTimeoutNew;
|
||||
avahiPoll.timeout_update = avahiTimeoutUpdate;
|
||||
avahiPoll.timeout_free = avahiTimeoutFree;
|
||||
avahi_glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
|
||||
avahi_poll = avahi_glib_poll_get(avahi_glib_poll);
|
||||
|
||||
avahiClient = avahi_client_new(&avahiPoll, AVAHI_CLIENT_NO_FAIL,
|
||||
avahiClient = avahi_client_new(avahi_poll, AVAHI_CLIENT_NO_FAIL,
|
||||
avahiClientCallback, NULL, &error);
|
||||
|
||||
if (!avahiClient) {
|
||||
@ -450,10 +235,6 @@ void init_avahi(const char *serviceName)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
zeroConfIo.fdset = avahiFdset;
|
||||
zeroConfIo.consume = avahiFdconsume;
|
||||
registerIO(&zeroConfIo);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
@ -463,7 +244,6 @@ fail:
|
||||
void avahi_finish(void)
|
||||
{
|
||||
g_debug("Shutting down interface");
|
||||
deregisterIO(&zeroConfIo);
|
||||
|
||||
if (avahiGroup) {
|
||||
avahi_entry_group_free(avahiGroup);
|
||||
@ -475,6 +255,11 @@ void avahi_finish(void)
|
||||
avahiClient = NULL;
|
||||
}
|
||||
|
||||
if (avahi_glib_poll != NULL) {
|
||||
avahi_glib_poll_free(avahi_glib_poll);
|
||||
avahi_glib_poll = NULL;
|
||||
}
|
||||
|
||||
avahi_free(avahiName);
|
||||
avahiName = NULL;
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
#include "zeroconf-internal.h"
|
||||
#include "listen.h"
|
||||
#include "ioops.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@ -27,51 +26,8 @@
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "bonjour"
|
||||
|
||||
static struct ioOps zeroConfIo;
|
||||
|
||||
static DNSServiceRef dnsReference;
|
||||
|
||||
static int
|
||||
dnsRegisterFdset(fd_set *rfds, G_GNUC_UNUSED fd_set *wfds,
|
||||
G_GNUC_UNUSED fd_set *efds)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (dnsReference == NULL)
|
||||
return -1;
|
||||
|
||||
fd = DNSServiceRefSockFD(dnsReference);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
FD_SET(fd, rfds);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
dnsRegisterFdconsume(int fdCount, fd_set *rfds,
|
||||
G_GNUC_UNUSED fd_set *wfds, G_GNUC_UNUSED fd_set *efds)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (dnsReference == NULL)
|
||||
return -1;
|
||||
|
||||
fd = DNSServiceRefSockFD(dnsReference);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
if (FD_ISSET(fd, rfds)) {
|
||||
FD_CLR(fd, rfds);
|
||||
|
||||
DNSServiceProcessResult(dnsReference);
|
||||
|
||||
return fdCount - 1;
|
||||
}
|
||||
|
||||
return fdCount;
|
||||
}
|
||||
static GIOChannel *bonjour_channel;
|
||||
|
||||
static void
|
||||
dnsRegisterCallback(G_GNUC_UNUSED DNSServiceRef sdRef,
|
||||
@ -84,14 +40,22 @@ dnsRegisterCallback(G_GNUC_UNUSED DNSServiceRef sdRef,
|
||||
if (errorCode != kDNSServiceErr_NoError) {
|
||||
g_warning("Failed to register zeroconf service.");
|
||||
|
||||
DNSServiceRefDeallocate(dnsReference);
|
||||
dnsReference = NULL;
|
||||
deregisterIO(&zeroConfIo);
|
||||
bonjour_finish();
|
||||
} else {
|
||||
g_debug("Registered zeroconf service with name '%s'", name);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
bonjour_channel_event(G_GNUC_UNUSED GIOChannel *source,
|
||||
G_GNUC_UNUSED GIOCondition condition,
|
||||
G_GNUC_UNUSED gpointer data)
|
||||
{
|
||||
DNSServiceProcessResult(dnsReference);
|
||||
|
||||
return dnsReference != NULL;
|
||||
}
|
||||
|
||||
void init_zeroconf_osx(const char *serviceName)
|
||||
{
|
||||
DNSServiceErrorType error = DNSServiceRegister(&dnsReference,
|
||||
@ -112,14 +76,17 @@ void init_zeroconf_osx(const char *serviceName)
|
||||
return;
|
||||
}
|
||||
|
||||
zeroConfIo.fdset = dnsRegisterFdset;
|
||||
zeroConfIo.consume = dnsRegisterFdconsume;
|
||||
registerIO(&zeroConfIo);
|
||||
bonjour_channel = g_io_channel_unix_new(DNSServiceRefSockFD(dnsReference));
|
||||
g_io_add_watch(bonjour_channel, G_IO_IN, bonjour_channel_event, NULL);
|
||||
}
|
||||
|
||||
void bonjour_finish(void)
|
||||
{
|
||||
deregisterIO(&zeroConfIo);
|
||||
if (bonjour_channel != NULL) {
|
||||
g_io_channel_unref(bonjour_channel);
|
||||
bonjour_channel = NULL;
|
||||
}
|
||||
|
||||
if (dnsReference != NULL) {
|
||||
DNSServiceRefDeallocate(dnsReference);
|
||||
dnsReference = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user