All the really trendy network services these days broadcast their presence on the LAN using mDNS. In Linux world this means becoming an Avahi client and registering our services. virt-manager is also able to become an Avahi client and browser for services. So you'll be able to let the user just pick a host straight off a list instead of typing in hostname. The attached patch does two things: - Extends our event loop implementation so it can modify the event mask associated with an FD, and the timeout associated with a timer. While you could simulate this with an add & remove, this has the possibility of failure (from malloc). Merely updating an existing event can be done without failure. Avahi needs this ability for its event loop integration - Added qemu/mdns.c file to actually provide the service information. This has two parts. The first section of code is taken straight from one of the Avahi example programs. The second section is a implementaiton of the Avahi event loop contract in terms of our event API - it works very nicely which says good things about design of our event loop Some things... - I arbitrarily picked a service type of '_libvirtd._tcp'. The docs on picking service types seem non-existant on Avahi website, but it seems to be common to use service name from /etc/services and protocol both prefixed with _. - I advertise two subtypes, of '_xen.libvirtd._tcp' and '_qemu.libvirtd._tcp' What I actually want todo is to be able to probe the libvirt local drivers to auto-discover what virtualization platforms are available. A sort of lightweight virConnectOpen which merely returns TRUE/FALSE and doesn't actually allocate a virConnectPtr object. Need to extend the internal driver API for this. - I want to advertise whether the server is configured with TLS certs or not, so remote clients can automatically choose to use SSH urls with the remote driver if neccessary. - Let the admin turn advertisement on/off in the config file because some people may not like it on their LAN. If you fancy trying it, avahi-browse --all from another host on the LAN should show the service being advertised. The advertisements do not cross LAN routers by default. Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
Index: configure.in =================================================================== RCS file: /data/cvs/libvirt/configure.in,v retrieving revision 1.81 diff -u -p -r1.81 configure.in --- configure.in 21 Aug 2007 14:59:47 -0000 1.81 +++ configure.in 14 Sep 2007 02:11:10 -0000 @@ -33,6 +33,10 @@ VERSION=${LIBVIRT_VERSION} AM_INIT_AUTOMAKE(libvirt, $VERSION) +AVAHI_REQUIRED=0.6.0 + +PKG_PROG_PKG_CONFIG() + dnl Checks for programs. AC_PROG_CC AC_PROG_INSTALL @@ -265,7 +269,7 @@ AC_ARG_WITH(libxml, [ --with-libxml=[PF if test "z$with_libxml" = "zno" ; then AC_MSG_CHECKING(for libxml2 libraries >= $LIBXML_MIN_VERSION) AC_MSG_ERROR(libxml2 >= $LIBXML_MIN_VERSION is required for $XMLSEC_PACKAGE) -elif test "z$with_libxml" = "z" -a "z$PKG_CONFIG_ENABLED" = "zyes" ; then +elif test "z$with_libxml" = "z" ; then PKG_CHECK_MODULES(LIBXML, libxml-2.0 >= $LIBXML_MIN_VERSION, [LIBXML_FOUND=yes], [LIBXML_FOUND=no]) @@ -424,6 +428,30 @@ AC_SUBST(PYTHON_VERSION) AC_SUBST(PYTHON_INCLUDES) AC_SUBST(PYTHON_SITE_PACKAGES) + +AC_ARG_WITH(avahi, + [ --with-avahi use Avahi to broadcast server presence], + [], + [with_avahi=check]) + +if test "$with_avahi" = "check"; then + AC_MSG_CHECKING([if Avahi >= $AVAHI_REQUIRED is available]) + PKG_CHECK_EXISTS(avahi-client >= $AVAHI_REQUIRED, [have_avahi=yes], [have_avahi=no]) + AC_MSG_RESULT([$have_avahi]) + with_avahi="$have_avahi" +fi + +if test "$with_avahi" = "yes" ; then + PKG_CHECK_MODULES(AVAHI, avahi-client >= $AVAHI_REQUIRED) + AC_DEFINE_UNQUOTED(HAVE_AVAHI, 1, [whether Avahi is used to broadcast server prescence]) +else + AVAHI_CFLAGS= + AVAHI_LIBS= +fi +AM_CONDITIONAL(HAVE_AVAHI, [test "$with_avahi" = "yes"]) +AC_SUBST(AVAHI_CFLAGS) +AC_SUBST(AVAHI_LIBS) + AC_MSG_CHECKING([whether this host is running a Xen kernel]) RUNNING_XEN= if test -d /proc/sys/xen Index: qemud/Makefile.am =================================================================== RCS file: /data/cvs/libvirt/qemud/Makefile.am,v retrieving revision 1.29 diff -u -p -r1.29 Makefile.am --- qemud/Makefile.am 27 Jun 2007 00:12:29 -0000 1.29 +++ qemud/Makefile.am 14 Sep 2007 02:11:17 -0000 @@ -3,6 +3,17 @@ INCLUDES = @LIBXML_CFLAGS@ UUID=$(shell uuidgen) +# Distribute the generated files so that rpcgen isn't required on the +# target machine (although almost any Unix machine will have it). +EXTRA_DIST = libvirtd.init.in libvirtd.sysconf default-network.xml \ + protocol.x remote_protocol.x \ + protocol.c protocol.h \ + remote_protocol.c remote_protocol.h \ + remote_generate_stubs.pl rpcgen_fix.pl \ + remote_dispatch_prototypes.h \ + remote_dispatch_localvars.h \ + remote_dispatch_proc_switch.h + sbin_PROGRAMS = libvirtd libvirtd_SOURCES = \ @@ -11,6 +22,7 @@ libvirtd_SOURCES = \ remote_protocol.h remote_protocol.c \ remote.c \ event.c event.h + #-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L libvirtd_CFLAGS = \ -I$(top_srcdir)/include -I$(top_builddir)/include $(LIBXML_CFLAGS) \ @@ -24,6 +36,16 @@ libvirtd_LDFLAGS = $(WARN_CFLAGS) $(LIBX libvirtd_DEPENDENCIES = ../src/libvirt.la libvirtd_LDADD = ../src/libvirt.la + +if HAVE_AVAHI +libvirtd_SOURCES += mdns.c mdns.h +libvirtd_CFLAGS += $(AVAHI_CFLAGS) +libvirtd_LDADD += $(AVAHI_LIBS) +else +EXTRA_DIST += mdns.c mdns.h +endif + + install-data-local: install-init mkdir -p $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart $(INSTALL_DATA) $(srcdir)/default-network.xml $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml @@ -42,17 +64,6 @@ uninstall-local: uninstall-init rmdir $(DESTDIR)$(localstatedir)/run/libvirt || : rmdir $(DESTDIR)$(localstatedir)/lib/libvirt || : -# Distribute the generated files so that rpcgen isn't required on the -# target machine (although almost any Unix machine will have it). -EXTRA_DIST = libvirtd.init.in libvirtd.sysconf default-network.xml \ - protocol.x remote_protocol.x \ - protocol.c protocol.h \ - remote_protocol.c remote_protocol.h \ - remote_generate_stubs.pl rpcgen_fix.pl \ - remote_dispatch_prototypes.h \ - remote_dispatch_localvars.h \ - remote_dispatch_proc_switch.h - .x.c: rm -f $@ rpcgen -c -o $@ $< Index: qemud/event.c =================================================================== RCS file: /data/cvs/libvirt/qemud/event.c,v retrieving revision 1.2 diff -u -p -r1.2 event.c --- qemud/event.c 26 Jun 2007 22:51:01 -0000 1.2 +++ qemud/event.c 14 Sep 2007 02:11:18 -0000 @@ -77,10 +77,10 @@ static int nextTimer = 0; * For this reason we only ever append to existing list. */ int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, void *opaque) { - qemudDebug("Add handle %d %d %p %p\n", fd, events, cb, opaque); + qemudDebug("Add handle %d %d %p %p", fd, events, cb, opaque); if (eventLoop.handlesCount == eventLoop.handlesAlloc) { struct virEventHandle *tmp; - qemudDebug("Used %d handle slots, adding %d more\n", + qemudDebug("Used %d handle slots, adding %d more", eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); tmp = realloc(eventLoop.handles, sizeof(struct virEventHandle) * @@ -103,6 +103,15 @@ int virEventAddHandleImpl(int fd, int ev return 0; } +void virEventUpdateHandleImpl(int fd, int events) { + int i; + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].fd == fd) { + eventLoop.handles[i].events = events; + } + } +} + /* * Unregister a callback from a file handle * NB, it *must* be safe to call this from within a callback @@ -111,13 +120,13 @@ int virEventAddHandleImpl(int fd, int ev */ int virEventRemoveHandleImpl(int fd) { int i; - qemudDebug("Remove handle %d\n", fd); + qemudDebug("Remove handle %d", fd); for (i = 0 ; i < eventLoop.handlesCount ; i++) { if (eventLoop.handles[i].deleted) continue; if (eventLoop.handles[i].fd == fd) { - qemudDebug("mark delete %d\n", i); + qemudDebug("mark delete %d", i); eventLoop.handles[i].deleted = 1; return 0; } @@ -140,7 +149,7 @@ int virEventAddTimeoutImpl(int timeout, if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) { struct virEventTimeout *tmp; - qemudDebug("Used %d timeout slots, adding %d more\n", + qemudDebug("Used %d timeout slots, adding %d more", eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); tmp = realloc(eventLoop.timeouts, sizeof(struct virEventTimeout) * @@ -158,15 +167,33 @@ int virEventAddTimeoutImpl(int timeout, eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque; eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0; eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt = - timeout + + timeout ? timeout + (((unsigned long long)tv.tv_sec)*1000) + - (((unsigned long long)tv.tv_usec)/1000); + (((unsigned long long)tv.tv_usec)/1000) : 0; eventLoop.timeoutsCount++; return nextTimer-1; } +void virEventUpdateTimeoutImpl(int timer, int timeout) { + struct timeval tv; + int i; + qemudDebug("Updating timer %d timeout with %d ms period", timer, timeout); + if (gettimeofday(&tv, NULL) < 0) { + return; + } + + for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { + if (eventLoop.timeouts[i].timer == timer) { + eventLoop.timeouts[i].expiresAt = + timeout ? timeout + + (((unsigned long long)tv.tv_sec)*1000) + + (((unsigned long long)tv.tv_usec)/1000) : 0; + } + } +} + /* * Unregister a callback for a timer * NB, it *must* be safe to call this from within a callback @@ -199,7 +226,7 @@ static int virEventCalculateTimeout(int /* Figure out if we need a timeout */ for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { - if (eventLoop.timeouts[i].deleted) + if (eventLoop.timeouts[i].deleted || !eventLoop.timeouts[i].timeout) continue; qemudDebug("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt); @@ -256,7 +283,7 @@ static int virEventMakePollFDs(struct po fds[nfds].fd = eventLoop.handles[i].fd; fds[nfds].events = eventLoop.handles[i].events; fds[nfds].revents = 0; - qemudDebug("Wait for %d %d\n", eventLoop.handles[i].fd, eventLoop.handles[i].events); + qemudDebug("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events); nfds++; } @@ -291,7 +318,7 @@ static int virEventDispatchTimeouts(void (((unsigned long long)tv.tv_usec)/1000); for (i = 0 ; i < ntimeouts ; i++) { - if (eventLoop.timeouts[i].deleted) + if (eventLoop.timeouts[i].deleted || !eventLoop.timeouts[i].timeout) continue; if (eventLoop.timeouts[i].expiresAt <= now) { @@ -322,12 +349,12 @@ static int virEventDispatchHandles(struc for (i = 0 ; i < nhandles ; i++) { if (eventLoop.handles[i].deleted) { - qemudDebug("Skip deleted %d\n", eventLoop.handles[i].fd); + qemudDebug("Skip deleted %d", eventLoop.handles[i].fd); continue; } if (fds[i].revents) { - qemudDebug("Dispatch %d %d %p\n", fds[i].fd, fds[i].revents, eventLoop.handles[i].opaque); + qemudDebug("Dispatch %d %d %p", fds[i].fd, fds[i].revents, eventLoop.handles[i].opaque); (eventLoop.handles[i].cb)(fds[i].fd, fds[i].revents, eventLoop.handles[i].opaque); } @@ -365,7 +392,7 @@ static int virEventCleanupTimeouts(void) /* Release some memory if we've got a big chunk free */ if ((eventLoop.timeoutsAlloc - EVENT_ALLOC_EXTENT) > eventLoop.timeoutsCount) { struct virEventTimeout *tmp; - qemudDebug("Releasing %d out of %d timeout slots used, releasing %d\n", + qemudDebug("Releasing %d out of %d timeout slots used, releasing %d", eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); tmp = realloc(eventLoop.timeouts, sizeof(struct virEventTimeout) * @@ -406,7 +433,7 @@ static int virEventCleanupHandles(void) /* Release some memory if we've got a big chunk free */ if ((eventLoop.handlesAlloc - EVENT_ALLOC_EXTENT) > eventLoop.handlesCount) { struct virEventHandle *tmp; - qemudDebug("Releasing %d out of %d handles slots used, releasing %d\n", + qemudDebug("Releasing %d out of %d handles slots used, releasing %d", eventLoop.handlesCount, eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); tmp = realloc(eventLoop.handles, sizeof(struct virEventHandle) * @@ -437,9 +464,9 @@ int virEventRunOnce(void) { } retry: - qemudDebug("Poll on %d handles %p timeout %d\n", nfds, fds, timeout); + qemudDebug("Poll on %d handles %p timeout %d", nfds, fds, timeout); ret = poll(fds, nfds, timeout); - qemudDebug("Poll got %d event\n", ret); + qemudDebug("Poll got %d event", ret); if (ret < 0) { if (errno == EINTR) { goto retry; Index: qemud/event.h =================================================================== RCS file: /data/cvs/libvirt/qemud/event.h,v retrieving revision 1.2 diff -u -p -r1.2 event.h --- qemud/event.h 26 Jun 2007 22:51:01 -0000 1.2 +++ qemud/event.h 14 Sep 2007 02:11:18 -0000 @@ -37,7 +37,7 @@ * returns -1 if the file handle cannot be registered, 0 upon success */ int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, void *opaque); - +void virEventUpdateHandleImpl(int fd, int events); /** * virEventRemoveHandleImpl: unregister a callback from a file handle * @@ -58,6 +58,7 @@ int virEventRemoveHandleImpl(int fd); * integer timer id upon success */ int virEventAddTimeoutImpl(int timeout, virEventTimeoutCallback cb, void *opaque); +void virEventUpdateTimeoutImpl(int timer, int timeout); /** * virEventRemoveTimeoutImpl: unregister a callback for a timer Index: qemud/internal.h =================================================================== RCS file: /data/cvs/libvirt/qemud/internal.h,v retrieving revision 1.34 diff -u -p -r1.34 internal.h --- qemud/internal.h 9 Aug 2007 20:19:12 -0000 1.34 +++ qemud/internal.h 14 Sep 2007 02:11:18 -0000 @@ -29,6 +29,10 @@ #include <gnutls/x509.h> #include "../src/gnutls_1_0_compat.h" +#ifdef HAVE_AVAHI +#include <avahi-client/client.h> +#endif + #include "protocol.h" #include "remote_protocol.h" #include "../config.h" @@ -115,6 +119,10 @@ struct qemud_socket { struct qemud_socket *next; }; +struct qemud_mdns { +// +}; + /* Main server state */ struct qemud_server { int nsockets; @@ -124,6 +132,9 @@ struct qemud_server { int sigread; char logDir[PATH_MAX]; unsigned int shutdown : 1; +#ifdef HAVE_AVAHI + AvahiClient *mdns_client; +#endif }; void qemudLog(int priority, const char *fmt, ...) Index: qemud/mdns.c =================================================================== RCS file: qemud/mdns.c diff -N qemud/mdns.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ qemud/mdns.c 14 Sep 2007 02:11:19 -0000 @@ -0,0 +1,367 @@ +/* + * mdns.c: advertise libvirt hypervisor connections + * + * Copyright (C) 2007 Daniel P. Berrange + * + * Derived from Avahi example service provider code. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include <avahi-client/client.h> +#include <avahi-client/publish.h> + +#include <avahi-common/alternative.h> +#include <avahi-common/simple-watch.h> +#include <avahi-common/malloc.h> +#include <avahi-common/error.h> +#include <avahi-common/timeval.h> + +#include "mdns.h" +#include "event.h" +#include "../src/remote_internal.h" + +#if 1 +static AvahiEntryGroup *group = NULL; +char *name; +static void create_services(AvahiClient *c); + +static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) { + assert(g == group || group == NULL); + + /* Called whenever the entry group state changes */ + + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + /* The entry group has been established successfully */ + fprintf(stderr, "Service '%s' successfully established.\n", name); + break; + + case AVAHI_ENTRY_GROUP_COLLISION : { + char *n; + + /* A service name collision happened. Let's pick a new name */ + n = avahi_alternative_service_name(name); + avahi_free(name); + name = n; + + fprintf(stderr, "Service name collision, renaming service to '%s'\n", name); + + /* And recreate the services */ + create_services(avahi_entry_group_get_client(g)); + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE : + fprintf(stderr, "Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g)))); + + /* Some kind of failure happened while we were registering our services */ + //avahi_simple_poll_quit(simple_poll); + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + } +} + +static void create_services(AvahiClient *c) { + int ret; + assert(c); + + /* If this is the first time we're called, let's create a new entry group */ + if (!group) { + if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) { + fprintf(stderr, "avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_client_errno(c))); + goto fail; + } + } + + fprintf(stderr, "Adding service '%s'\n", name); + + /* Add the service for IPP */ + if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_libvirtd._tcp", NULL, NULL, LIBVIRTD_TLS_PORT_NUM, NULL)) < 0) { + fprintf(stderr, "Failed to add _libvirtd._tcp service: %s\n", avahi_strerror(ret)); + goto fail; + } + if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_libvirtd._tcp", NULL, "_qemu._sub._libvirtd._tcp")) < 0) { + fprintf(stderr, "Failed to add _qemu._libvirtd._tcp service: %s\n", avahi_strerror(ret)); + goto fail; + } + if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_libvirtd._tcp", NULL, "_xen._sub._libvirtd._tcp")) < 0) { + fprintf(stderr, "Failed to add _xen._libvirtd._tcp service: %s\n", avahi_strerror(ret)); + goto fail; + } + + /* Tell the server to register the service */ + if ((ret = avahi_entry_group_commit(group)) < 0) { + fprintf(stderr, "Failed to commit entry_group: %s\n", avahi_strerror(ret)); + goto fail; + } + + fail: + return; +} + + +static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) { + assert(c); + + /* Called whenever the client or server state changes */ + + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + /* The server has startup successfully and registered its host + * name on the network, so it's time to create our services */ + if (!group) + create_services(c); + break; + + case AVAHI_CLIENT_FAILURE: + fprintf(stderr, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c))); + //avahi_simple_poll_quit(simple_poll); + break; + + case AVAHI_CLIENT_S_COLLISION: + /* Let's drop our registered services. When the server is back + * in AVAHI_SERVER_RUNNING state we will register them + * again with the new host name. */ + + /* Fallthrough */ + + case AVAHI_CLIENT_S_REGISTERING: + + /* The server records are now being established. This + * might be caused by a host name change. We need to wait + * for our own records to register until the host name is + * properly esatblished. */ + if (group) + avahi_entry_group_reset(group); + break; + + case AVAHI_CLIENT_CONNECTING: + ; + } +} + +#endif + +struct AvahiWatch { + int fd; + int revents; + AvahiWatchCallback callback; + void *userdata; +}; + +struct AvahiTimeout { + int timer; + AvahiTimeoutCallback callback; + void *userdata; +}; + +static void libvirtd_avahi_watch_dispatch(int fd, int events, void *opaque) +{ + AvahiWatch *w = (AvahiWatch*)opaque; + qemudDebug("Dispatch watch %d", fd); + w->revents = events; + w->callback(w, fd, events, w->userdata); +} + +static AvahiWatch *libvirtd_avahi_watch_new(const AvahiPoll *api ATTRIBUTE_UNUSED, + int fd, AvahiWatchEvent event, AvahiWatchCallback cb, void *userdata) { + AvahiWatch *w = malloc(sizeof(AvahiWatch)); + if (!w) + return NULL; + + w->fd = fd; + w->revents = 0; + w->callback = cb; + w->userdata = userdata; + + qemudDebug("New handle %p %d", w, w->fd); + if (virEventAddHandleImpl(fd, event, libvirtd_avahi_watch_dispatch, w) < 0) { + free(w); + return NULL; + } + + return w; +} + +static void libvirtd_avahi_watch_update(AvahiWatch *w, AvahiWatchEvent event) { + qemudDebug("Update handle %p %d", w, w->fd); + virEventUpdateHandleImpl(w->fd, event); +} + +static AvahiWatchEvent libvirtd_avahi_watch_get_events(AvahiWatch *w) { + qemudDebug("Get handle events %p %d", w, w->fd); + return w->revents; +} + +static void libvirtd_avahi_watch_free(AvahiWatch *w) { + qemudDebug("Free handle %p %d", w, w->fd); + virEventRemoveHandleImpl(w->fd); + free(w); +} + +static void libvirtd_avahi_timeout_dispatch(int timer, void *opaque) +{ + AvahiTimeout *t = (AvahiTimeout*)opaque; + qemudDebug("Dispatch timeout %p %d", t, timer); + virEventRemoveTimeoutImpl(t->timer); + t->callback(t, t->userdata); +} + +static AvahiTimeout *libvirtd_avahi_timeout_new(const AvahiPoll *api ATTRIBUTE_UNUSED, + const struct timeval *tv, AvahiTimeoutCallback cb, void *userdata) { + AvahiTimeout *t = malloc(sizeof(AvahiTimeout)); + struct timeval now; + long long nowms, thenms, timeout; + qemudDebug("Add timeout %p", t); + if (!t) + return NULL; + + if (gettimeofday(&now, NULL) < 0) { + free(t); + return NULL; + } + + qemudDebug("Trigger timed for %d %d %d %d", + (int)now.tv_sec, (int)now.tv_usec, + (int)(tv ? tv->tv_sec : 0), (int)(tv ? tv->tv_usec : 0)); + nowms = (now.tv_sec * 1000ll) + (now.tv_usec / 1000ll); + thenms = tv ? ((tv->tv_sec * 1000ll) + (tv->tv_usec/1000ll)) : 0; + timeout = thenms ? thenms - nowms : 0; + if (thenms && timeout <= 0) + timeout = 1; + + t->timer = virEventAddTimeoutImpl(timeout, libvirtd_avahi_timeout_dispatch, t); + t->callback = cb; + t->userdata = userdata; + + if (t->timer < 0) { + free(t); + return NULL; + } + + return t; +} + +static void libvirtd_avahi_timeout_update(AvahiTimeout *t, const struct timeval *tv) { + struct timeval now; + long long nowms, thenms, timeout; + qemudDebug("Update timeout %p", t); + if (gettimeofday(&now, NULL) < 0) { + free(t); + return; + } + + nowms = (now.tv_sec * 1000ll) + (now.tv_usec / 1000ll); + thenms = tv ? ((tv->tv_sec * 1000ll) + (tv->tv_usec/1000ll)) : 0; + timeout = thenms ? nowms-thenms : 0; + if (thenms && timeout <= 0) + timeout = 1; + + virEventUpdateTimeoutImpl(t->timer, timeout); +} + +static void libvirtd_avahi_timeout_free(AvahiTimeout *t) { + qemudDebug("Free timeout %p", t); + virEventRemoveTimeoutImpl(t->timer); + free(t); +} + + +static AvahiPoll *libvirtd_create_poll(struct qemud_server *server) { + AvahiPoll *p = malloc(sizeof(AvahiPoll)); + if (!p) + return NULL; + + p->userdata = server; + + p->watch_new = libvirtd_avahi_watch_new; + p->watch_update = libvirtd_avahi_watch_update; + p->watch_get_events = libvirtd_avahi_watch_get_events; + p->watch_free = libvirtd_avahi_watch_free; + + p->timeout_new = libvirtd_avahi_timeout_new; + p->timeout_update = libvirtd_avahi_timeout_update; + p->timeout_free = libvirtd_avahi_timeout_free; + + return p; +} + +int libvirtd_init_mdns(struct qemud_server *server) { + AvahiClient *client = NULL; + AvahiPoll *poller = NULL; + int error; + + /* Allocate main loop object */ + if (!(poller = libvirtd_create_poll(server))) { + fprintf(stderr, "Failed to create poll object.\n"); + goto fail; + } + + if (!(name = strdup("Virtualization Provider"))) { + fprintf(stderr, "Failed to alloc name"); + goto fail; + } + + /* Allocate a new client */ + client = avahi_client_new(poller, 0, client_callback, NULL, &error); + + /* Check wether creating the client object succeeded */ + if (!client) { + fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error)); + goto fail; + } + + server->mdns_client = client; + + return 0; + +fail: + /* Cleanup things */ + + if (client) + avahi_client_free(client); + + if (poller) + free(poller); + + if (name) + free(name); + + return -1; +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ Index: qemud/mdns.h =================================================================== RCS file: qemud/mdns.h diff -N qemud/mdns.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ qemud/mdns.h 14 Sep 2007 02:11:19 -0000 @@ -0,0 +1,27 @@ +/* + * mdns.c: advertise libvirt hypervisor connections + * + * Copyright (C) 2007 Daniel P. Berrange + * + * Derived from Avahi example service provider code. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Daniel P. Berrange <berrange@xxxxxxxxxx> + */ + +#include "internal.h" + +int libvirtd_init_mdns(struct qemud_server *server); Index: qemud/qemud.c =================================================================== RCS file: /data/cvs/libvirt/qemud/qemud.c,v retrieving revision 1.56 diff -u -p -r1.56 qemud.c --- qemud/qemud.c 7 Aug 2007 13:24:22 -0000 1.56 +++ qemud/qemud.c 14 Sep 2007 02:11:19 -0000 @@ -56,6 +56,9 @@ #include "../src/remote_internal.h" #include "../src/conf.h" #include "event.h" +#if HAVE_AVAHI +#include "mdns.h" +#endif static int godaemon = 0; /* -d: Be a daemon */ static int verbose = 0; /* -v: Verbose mode */ @@ -688,8 +691,10 @@ static struct qemud_server *qemudInitial goto cleanup; __virEventRegisterImpl(virEventAddHandleImpl, + virEventUpdateHandleImpl, virEventRemoveHandleImpl, virEventAddTimeoutImpl, + virEventUpdateTimeoutImpl, virEventRemoveTimeoutImpl); virStateInitialize(); @@ -707,6 +712,10 @@ static struct qemud_server *qemudInitial } } +#if HAVE_AVAHI + libvirtd_init_mdns(server); +#endif + return server; cleanup: Index: src/event.c =================================================================== RCS file: /data/cvs/libvirt/src/event.c,v retrieving revision 1.1 diff -u -p -r1.1 event.c --- src/event.c 26 Jun 2007 22:51:01 -0000 1.1 +++ src/event.c 14 Sep 2007 02:11:21 -0000 @@ -27,8 +27,10 @@ #include <stdlib.h> static virEventAddHandleFunc addHandleImpl = NULL; +static virEventUpdateHandleFunc updateHandleImpl = NULL; static virEventRemoveHandleFunc removeHandleImpl = NULL; static virEventAddTimeoutFunc addTimeoutImpl = NULL; +static virEventUpdateTimeoutFunc updateTimeoutImpl = NULL; static virEventRemoveTimeoutFunc removeTimeoutImpl = NULL; int virEventAddHandle(int fd, int events, virEventHandleCallback cb, void *opaque) { @@ -38,6 +40,10 @@ int virEventAddHandle(int fd, int events return addHandleImpl(fd, events, cb, opaque); } +void virEventUpdateHandle(int fd, int events) { + updateHandleImpl(fd, events); +} + int virEventRemoveHandle(int fd) { if (!removeHandleImpl) return -1; @@ -52,6 +58,10 @@ int virEventAddTimeout(int timeout, virE return addTimeoutImpl(timeout, cb, opaque); } +void virEventUpdateTimeout(int timer, int timeout) { + updateTimeoutImpl(timer, timeout); +} + int virEventRemoveTimeout(int timer) { if (!removeTimeoutImpl) return -1; @@ -60,12 +70,16 @@ int virEventRemoveTimeout(int timer) { } void __virEventRegisterImpl(virEventAddHandleFunc addHandle, - virEventRemoveHandleFunc removeHandle, - virEventAddTimeoutFunc addTimeout, - virEventRemoveTimeoutFunc removeTimeout) { + virEventUpdateHandleFunc updateHandle, + virEventRemoveHandleFunc removeHandle, + virEventAddTimeoutFunc addTimeout, + virEventUpdateTimeoutFunc updateTimeout, + virEventRemoveTimeoutFunc removeTimeout) { addHandleImpl = addHandle; + updateHandleImpl = updateHandle; removeHandleImpl = removeHandle; addTimeoutImpl = addTimeout; + updateTimeoutImpl = updateTimeout; removeTimeoutImpl = removeTimeout; } Index: src/event.h =================================================================== RCS file: /data/cvs/libvirt/src/event.h,v retrieving revision 1.1 diff -u -p -r1.1 event.h --- src/event.h 26 Jun 2007 22:51:01 -0000 1.1 +++ src/event.h 14 Sep 2007 02:11:21 -0000 @@ -47,6 +47,16 @@ typedef void (*virEventHandleCallback)(i int virEventAddHandle(int fd, int events, virEventHandleCallback cb, void *opaque); /** + * virEventUpdateHandle: change an event mask for monitoring file handle events + * + * @fd: file handle whose events to change + * @events: bitset of events to wach from POLLnnn constants + * + * This cannot fail if + */ +void virEventUpdateHandle(int fd, int events); + +/** * virEventRemoveHandle: unregister a callback from a file handle * * @fd: file handle to stop monitoring for events @@ -75,6 +85,19 @@ typedef void (*virEventTimeoutCallback)( */ int virEventAddTimeout(int timeout, virEventTimeoutCallback cb, void *opaque); + +/** + * virEventAddTimeout: update the timeout for a timer event + * + * @timer: timer whose timeout to update + * @timeout: timeout between events in milliseconds + * + * This cannot fail + */ +void virEventUpdateTimeout(int timer, int timeout); + + + /** * virEventRemoveTimeout: unregister a callback for a timer * @@ -85,14 +108,18 @@ int virEventAddTimeout(int timeout, virE int virEventRemoveTimeout(int timer); typedef int (*virEventAddHandleFunc)(int, int, virEventHandleCallback, void *); +typedef void (*virEventUpdateHandleFunc)(int, int); typedef int (*virEventRemoveHandleFunc)(int); typedef int (*virEventAddTimeoutFunc)(int, virEventTimeoutCallback, void *); +typedef void (*virEventUpdateTimeoutFunc)(int, int); typedef int (*virEventRemoveTimeoutFunc)(int); void __virEventRegisterImpl(virEventAddHandleFunc addHandle, + virEventUpdateHandleFunc updateHandle, virEventRemoveHandleFunc removeHandle, virEventAddTimeoutFunc addTimeout, + virEventUpdateTimeoutFunc updateTimeout, virEventRemoveTimeoutFunc removeTimeout); #define virEventRegisterImpl(ah,rh,at,rt) __virEventRegisterImpl(ah,rh,at,rt) Index: src/remote_internal.h =================================================================== RCS file: /data/cvs/libvirt/src/remote_internal.h,v retrieving revision 1.2 diff -u -p -r1.2 remote_internal.h --- src/remote_internal.h 26 Jun 2007 23:48:47 -0000 1.2 +++ src/remote_internal.h 14 Sep 2007 02:11:23 -0000 @@ -33,7 +33,9 @@ extern "C" { int remoteRegister (void); #define LIBVIRTD_TLS_PORT "16514" +#define LIBVIRTD_TLS_PORT_NUM 16514 #define LIBVIRTD_TCP_PORT "16509" +#define LIBVIRTD_TCP_PORT_NUM 16509 #define LIBVIRTD_PRIV_UNIX_SOCKET LOCAL_STATE_DIR "/run/libvirt/libvirt-sock" #define LIBVIRTD_PRIV_UNIX_SOCKET_RO LOCAL_STATE_DIR "/run/libvirt/libvirt-sock-ro" #define LIBVIRTD_USER_UNIX_SOCKET "/.libvirt/libvirt-sock"
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list