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 <[EMAIL PROTECTED]>
+ */
+
+#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 <[EMAIL PROTECTED]>
+ */
+
+#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
[email protected]
https://www.redhat.com/mailman/listinfo/libvir-list