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:
Max Kellermann 2008-12-30 19:24:39 +01:00
parent 03e650aa9e
commit 71e7ce5d8e
13 changed files with 182 additions and 576 deletions

View File

@ -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])

View File

@ -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 \

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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]);
}

View File

@ -37,4 +37,7 @@ void main_notify_lock(void);
void main_notify_unlock(void);
void
main_notify_triggered(void);
#endif /* MAIN_NOTIFY_H */

View File

@ -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;
}

View File

@ -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;