mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +00:00
Added support for Avahi mDNS advertisement
This commit is contained in:
parent
c79514fda0
commit
8f4e48edff
11
ChangeLog
11
ChangeLog
@ -1,3 +1,14 @@
|
||||
Tue Sep 18 21:34:00 EST 2007 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* configure.in: Added checks for locating Avahi.
|
||||
* qemud/mdns.c, qemud/mdns.h, qemud/Makefile.am: Convenience API to
|
||||
bridge between state machine provided by Avahi APIs, and the libvirt
|
||||
daemon.
|
||||
* qemud/qemud.c, qemud/internal.h: Register the daemon as an mDNS
|
||||
service under _libvirt._tcp.
|
||||
* docs/libvir.html: Added notes on mdns config params.
|
||||
* libvirt.spec.in: Added avahi-devel as a BuildRequires
|
||||
|
||||
Tue Sep 18 20:42:00 EST 2007 Daniel P. Berrange <berrange@redhat.com>
|
||||
|
||||
* src/event.h, src/event.c: Added new APIs definitions for updating
|
||||
|
31
configure.in
31
configure.in
@ -21,6 +21,8 @@ AC_SUBST(LIBVIRT_VERSION)
|
||||
AC_SUBST(LIBVIRT_VERSION_INFO)
|
||||
AC_SUBST(LIBVIRT_VERSION_NUMBER)
|
||||
|
||||
AVAHI_REQUIRED="0.6.0"
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
@ -232,6 +234,9 @@ if test "$with_qemu" = "yes" ; then
|
||||
AC_MSG_ERROR([You must install kernel-headers in order to compile libvirt]))
|
||||
fi
|
||||
|
||||
dnl Need to test if pkg-config exists
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
dnl ==========================================================================
|
||||
dnl find libxml2 library, borrowed from xmlsec
|
||||
dnl ==========================================================================
|
||||
@ -300,6 +305,27 @@ AC_CHECK_TYPE(gnutls_session,
|
||||
[enable GnuTLS 1.0 compatibility macros]),,
|
||||
[#include <gnutls/gnutls.h>])
|
||||
|
||||
|
||||
dnl Avahi library
|
||||
AC_ARG_WITH(avahi,
|
||||
[ --with-avahi use avahi to advertise remote daemon],
|
||||
[],
|
||||
[with_avahi=check])
|
||||
|
||||
if test "$with_avahi" = "check" -a "x$PKG_CONFIG" != "x" ; then
|
||||
PKG_CHECK_EXISTS(avahi-client >= $AVAHI_REQUIRED, [with_avahi=yes], [with_avahi=no])
|
||||
fi
|
||||
|
||||
AVAHI_CFLAGS=
|
||||
AVAHI_LIBS=
|
||||
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 presense])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_AVAHI, [test "$with_avahi" = "yes"])
|
||||
AC_SUBST(AVAHI_CFLAGS)
|
||||
AC_SUBST(AVAHI_LIBS)
|
||||
|
||||
dnl virsh libraries
|
||||
AC_CHECK_LIB(curses, initscr,
|
||||
[VIRSH_LIBS="$VIRSH_LIBS -lcurses"],
|
||||
@ -485,6 +511,11 @@ AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([Libraries])
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([ libxml: $LIBXML_CFLAGS $LIBXML_LIBS])
|
||||
if test "$with_avahi" = "yes" ; then
|
||||
AC_MSG_NOTICE([ avahi: $AVAHI_CFLAGS $AVAHI_LIBS])
|
||||
else
|
||||
AC_MSG_NOTICE([ avahi: no])
|
||||
fi
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([Miscellaneous])
|
||||
AC_MSG_NOTICE([])
|
||||
|
@ -2191,6 +2191,25 @@ Blank lines and comments beginning with <code>#</code> are ignored.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> mdns_adv <i>[0|1]</i> </td>
|
||||
<td> 1 (advertise with mDNS) </td>
|
||||
<td>
|
||||
If set to 1 then the virtualization service will be advertised over
|
||||
mDNS to hosts on the local LAN segment.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> mdns_name <i>"name"</i> </td>
|
||||
<td> "Virtualization Host HOSTNAME" </td>
|
||||
<td>
|
||||
The name to advertise for this host with Avahi mDNS. The default
|
||||
includes the machine's short hostname. This must be unique to the
|
||||
local LAN segment.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> tls_no_verify_certificate <i>[0|1]</i> </td>
|
||||
<td> 0 (certificates are verified) </td>
|
||||
|
@ -471,6 +471,19 @@ Blank lines and comments beginning with <code>#</code> are ignored.
|
||||
<td>
|
||||
The port number or service name to listen on for unencrypted TCP connections.
|
||||
</td>
|
||||
</tr><tr><td> mdns_adv <i>[0|1]</i> </td>
|
||||
<td> 1 (advertise with mDNS) </td>
|
||||
<td>
|
||||
If set to 1 then the virtualization service will be advertised over
|
||||
mDNS to hosts on the local LAN segment.
|
||||
</td>
|
||||
</tr><tr><td> mdns_name <i>"name"</i> </td>
|
||||
<td> "Virtualization Host HOSTNAME" </td>
|
||||
<td>
|
||||
The name to advertise for this host with Avahi mDNS. The default
|
||||
includes the machine's short hostname. This must be unique to the
|
||||
local LAN segment.
|
||||
</td>
|
||||
</tr><tr><td> tls_no_verify_certificate <i>[0|1]</i> </td>
|
||||
<td> 0 (certificates are verified) </td>
|
||||
<td>
|
||||
|
@ -22,6 +22,7 @@ BuildRequires: readline-devel
|
||||
BuildRequires: ncurses-devel
|
||||
BuildRequires: gettext
|
||||
BuildRequires: gnutls-devel
|
||||
BuildRequires: avahi-devel
|
||||
Obsoletes: libvir
|
||||
ExclusiveArch: i386 x86_64 ia64
|
||||
|
||||
|
@ -5,12 +5,25 @@ UUID=$(shell uuidgen)
|
||||
|
||||
sbin_PROGRAMS = libvirtd
|
||||
|
||||
# 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 \
|
||||
mdns.c mdns.h
|
||||
|
||||
libvirtd_SOURCES = \
|
||||
qemud.c internal.h \
|
||||
protocol.h protocol.c \
|
||||
remote_protocol.h remote_protocol.c \
|
||||
remote.c \
|
||||
event.c event.h
|
||||
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 +37,12 @@ libvirtd_LDFLAGS = $(WARN_CFLAGS) $(LIBXML_LIBS)
|
||||
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)
|
||||
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,16 +61,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 $@
|
||||
|
@ -111,7 +111,7 @@ struct qemud_socket {
|
||||
int readonly;
|
||||
/* If set, TLS is required on this socket. */
|
||||
int tls;
|
||||
|
||||
int port;
|
||||
struct qemud_socket *next;
|
||||
};
|
||||
|
||||
@ -124,6 +124,9 @@ struct qemud_server {
|
||||
int sigread;
|
||||
char logDir[PATH_MAX];
|
||||
unsigned int shutdown : 1;
|
||||
#ifdef HAVE_AVAHI
|
||||
struct libvirtd_mdns *mdns;
|
||||
#endif
|
||||
};
|
||||
|
||||
void qemudLog(int priority, const char *fmt, ...)
|
||||
|
504
qemud/mdns.c
Normal file
504
qemud/mdns.c
Normal file
@ -0,0 +1,504 @@
|
||||
/*
|
||||
* 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@redhat.com>
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "../src/internal.h"
|
||||
|
||||
#define AVAHI_DEBUG(fmt, ...) qemudDebug("AVAHI: " fmt, __VA_ARGS__)
|
||||
|
||||
struct libvirtd_mdns_entry {
|
||||
char *type;
|
||||
int port;
|
||||
struct libvirtd_mdns_entry *next;
|
||||
};
|
||||
|
||||
struct libvirtd_mdns_group {
|
||||
struct libvirtd_mdns *mdns;
|
||||
AvahiEntryGroup *handle;
|
||||
char *name;
|
||||
struct libvirtd_mdns_entry *entry;
|
||||
struct libvirtd_mdns_group *next;
|
||||
};
|
||||
|
||||
struct libvirtd_mdns {
|
||||
AvahiClient *client;
|
||||
AvahiPoll *poller;
|
||||
struct libvirtd_mdns_group *group;
|
||||
};
|
||||
|
||||
/* Avahi API requires this struct names in the app :-( */
|
||||
struct AvahiWatch {
|
||||
int fd;
|
||||
int revents;
|
||||
AvahiWatchCallback callback;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
/* Avahi API requires this struct names in the app :-( */
|
||||
struct AvahiTimeout {
|
||||
int timer;
|
||||
AvahiTimeoutCallback callback;
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
|
||||
static void libvirtd_mdns_create_services(struct libvirtd_mdns_group *group);
|
||||
|
||||
/* Called whenever the entry group state changes */
|
||||
static void libvirtd_mdns_group_callback(AvahiEntryGroup *g ATTRIBUTE_UNUSED, AvahiEntryGroupState state, void *userdata) {
|
||||
struct libvirtd_mdns_group *group = (struct libvirtd_mdns_group *)userdata;
|
||||
|
||||
switch (state) {
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||
/* The entry group has been established successfully */
|
||||
AVAHI_DEBUG("Group '%s' established", group->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(group->name);
|
||||
free(group->name);
|
||||
group->name = n;
|
||||
|
||||
AVAHI_DEBUG("Group name collision, renaming service to '%s'", group->name);
|
||||
|
||||
/* And recreate the services */
|
||||
libvirtd_mdns_create_services(group);
|
||||
}
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_FAILURE :
|
||||
AVAHI_DEBUG("Group failure: %s", avahi_strerror(avahi_client_errno(group->mdns->client)));
|
||||
|
||||
/* 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 libvirtd_mdns_create_services(struct libvirtd_mdns_group *group) {
|
||||
struct libvirtd_mdns *mdns = group->mdns;
|
||||
struct libvirtd_mdns_entry *entry;
|
||||
int ret;
|
||||
AVAHI_DEBUG("Adding services to '%s'", group->name);
|
||||
|
||||
/* If we've no services to advertise, just reset the group to make
|
||||
* sure it is emptied of any previously advertised services */
|
||||
if (!group->entry) {
|
||||
if (group->handle)
|
||||
avahi_entry_group_reset(group->handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this is the first time we're called, let's create a new entry group */
|
||||
if (!group->handle) {
|
||||
AVAHI_DEBUG("Creating initial group %s", group->name);
|
||||
if (!(group->handle = avahi_entry_group_new(mdns->client, libvirtd_mdns_group_callback, group))) {
|
||||
AVAHI_DEBUG("avahi_entry_group_new() failed: %s", avahi_strerror(avahi_client_errno(mdns->client)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
entry = group->entry;
|
||||
while (entry) {
|
||||
if ((ret = avahi_entry_group_add_service(group->handle,
|
||||
AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_UNSPEC,
|
||||
0,
|
||||
group->name,
|
||||
entry->type,
|
||||
NULL,
|
||||
NULL,
|
||||
entry->port,
|
||||
NULL)) < 0) {
|
||||
AVAHI_DEBUG("Failed to add %s service on port %d: %s",
|
||||
entry->type, entry->port, avahi_strerror(ret));
|
||||
avahi_entry_group_reset(group->handle);
|
||||
return;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
/* Tell the server to register the service */
|
||||
if ((ret = avahi_entry_group_commit(group->handle)) < 0) {
|
||||
avahi_entry_group_reset(group->handle);
|
||||
AVAHI_DEBUG("Failed to commit entry_group: %s", avahi_strerror(ret));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void libvirtd_mdns_client_callback(AvahiClient *c, AvahiClientState state, void *userdata) {
|
||||
struct libvirtd_mdns *mdns = (struct libvirtd_mdns *)userdata;
|
||||
struct libvirtd_mdns_group *group = mdns->group;
|
||||
if (!mdns->client)
|
||||
mdns->client = 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 */
|
||||
AVAHI_DEBUG("Client running %p", mdns->client);
|
||||
group = mdns->group;
|
||||
while (group) {
|
||||
libvirtd_mdns_create_services(group);
|
||||
group = group->next;
|
||||
}
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
AVAHI_DEBUG("Client failure: %s", avahi_strerror(avahi_client_errno(c)));
|
||||
libvirtd_mdns_stop(mdns);
|
||||
libvirtd_mdns_start(mdns);
|
||||
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. */
|
||||
AVAHI_DEBUG("Client collision/connecting %p", mdns->client);
|
||||
group = mdns->group;
|
||||
while (group) {
|
||||
if (group->handle)
|
||||
avahi_entry_group_reset(group->handle);
|
||||
group = group->next;
|
||||
}
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_CONNECTING:
|
||||
AVAHI_DEBUG("Client connecting.... %p", mdns->client);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void libvirtd_mdns_watch_dispatch(int fd, int events, void *opaque)
|
||||
{
|
||||
AvahiWatch *w = (AvahiWatch*)opaque;
|
||||
AVAHI_DEBUG("Dispatch watch FD %d Event %d", fd, events);
|
||||
w->revents = events;
|
||||
w->callback(w, fd, events, w->userdata);
|
||||
}
|
||||
|
||||
static AvahiWatch *libvirtd_mdns_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;
|
||||
|
||||
AVAHI_DEBUG("New handle %p FD %d Event %d", w, w->fd, event);
|
||||
if (virEventAddHandleImpl(fd, event, libvirtd_mdns_watch_dispatch, w) < 0) {
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static void libvirtd_mdns_watch_update(AvahiWatch *w, AvahiWatchEvent event)
|
||||
{
|
||||
AVAHI_DEBUG("Update handle %p FD %d Event %d", w, w->fd, event);
|
||||
virEventUpdateHandleImpl(w->fd, event);
|
||||
}
|
||||
|
||||
static AvahiWatchEvent libvirtd_mdns_watch_get_events(AvahiWatch *w)
|
||||
{
|
||||
AVAHI_DEBUG("Get handle events %p %d", w, w->fd);
|
||||
return w->revents;
|
||||
}
|
||||
|
||||
static void libvirtd_mdns_watch_free(AvahiWatch *w)
|
||||
{
|
||||
AVAHI_DEBUG("Free handle %p %d", w, w->fd);
|
||||
virEventRemoveHandleImpl(w->fd);
|
||||
free(w);
|
||||
}
|
||||
|
||||
static void libvirtd_mdns_timeout_dispatch(int timer ATTRIBUTE_UNUSED, void *opaque)
|
||||
{
|
||||
AvahiTimeout *t = (AvahiTimeout*)opaque;
|
||||
AVAHI_DEBUG("Dispatch timeout %p %d", t, timer);
|
||||
virEventUpdateTimeoutImpl(t->timer, -1);
|
||||
t->callback(t, t->userdata);
|
||||
}
|
||||
|
||||
static AvahiTimeout *libvirtd_mdns_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;
|
||||
AVAHI_DEBUG("Add timeout %p TV %p", t, tv);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AVAHI_DEBUG("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);
|
||||
if (tv) {
|
||||
thenms = (tv->tv_sec * 1000ll) + (tv->tv_usec/1000ll);
|
||||
timeout = thenms > nowms ? nowms - thenms : 0;
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
} else {
|
||||
timeout = -1;
|
||||
}
|
||||
|
||||
t->timer = virEventAddTimeoutImpl(timeout, libvirtd_mdns_timeout_dispatch, t);
|
||||
t->callback = cb;
|
||||
t->userdata = userdata;
|
||||
|
||||
if (t->timer < 0) {
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void libvirtd_mdns_timeout_update(AvahiTimeout *t, const struct timeval *tv)
|
||||
{
|
||||
struct timeval now;
|
||||
long long nowms, thenms, timeout;
|
||||
AVAHI_DEBUG("Update timeout %p TV %p", t, tv);
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
free(t);
|
||||
return;
|
||||
}
|
||||
|
||||
nowms = (now.tv_sec * 1000ll) + (now.tv_usec / 1000ll);
|
||||
if (tv) {
|
||||
thenms = ((tv->tv_sec * 1000ll) + (tv->tv_usec/1000ll));
|
||||
timeout = thenms > nowms ? nowms - thenms : 0;
|
||||
if (timeout < 0)
|
||||
timeout = 0;
|
||||
} else {
|
||||
timeout = -1;
|
||||
}
|
||||
|
||||
virEventUpdateTimeoutImpl(t->timer, timeout);
|
||||
}
|
||||
|
||||
static void libvirtd_mdns_timeout_free(AvahiTimeout *t)
|
||||
{
|
||||
AVAHI_DEBUG("Free timeout %p", t);
|
||||
virEventRemoveTimeoutImpl(t->timer);
|
||||
free(t);
|
||||
}
|
||||
|
||||
|
||||
static AvahiPoll *libvirtd_create_poll(void)
|
||||
{
|
||||
AvahiPoll *p = malloc(sizeof(AvahiPoll));
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->userdata = NULL;
|
||||
|
||||
p->watch_new = libvirtd_mdns_watch_new;
|
||||
p->watch_update = libvirtd_mdns_watch_update;
|
||||
p->watch_get_events = libvirtd_mdns_watch_get_events;
|
||||
p->watch_free = libvirtd_mdns_watch_free;
|
||||
|
||||
p->timeout_new = libvirtd_mdns_timeout_new;
|
||||
p->timeout_update = libvirtd_mdns_timeout_update;
|
||||
p->timeout_free = libvirtd_mdns_timeout_free;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct libvirtd_mdns *libvirtd_mdns_new(void)
|
||||
{
|
||||
struct libvirtd_mdns *mdns = malloc(sizeof(struct libvirtd_mdns));
|
||||
if (!mdns)
|
||||
return NULL;
|
||||
memset(mdns, 0, sizeof(*mdns));
|
||||
|
||||
/* Allocate main loop object */
|
||||
if (!(mdns->poller = libvirtd_create_poll())) {
|
||||
free(mdns);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mdns;
|
||||
}
|
||||
|
||||
int libvirtd_mdns_start(struct libvirtd_mdns *mdns)
|
||||
{
|
||||
int error;
|
||||
AVAHI_DEBUG("Starting client %p", mdns);
|
||||
mdns->client = avahi_client_new(mdns->poller, AVAHI_CLIENT_NO_FAIL, libvirtd_mdns_client_callback, mdns, &error);
|
||||
|
||||
if (!mdns->client) {
|
||||
AVAHI_DEBUG("Failed to create mDNS client: %s", avahi_strerror(error));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct libvirtd_mdns_group *libvirtd_mdns_add_group(struct libvirtd_mdns *mdns, const char *name) {
|
||||
struct libvirtd_mdns_group *group = malloc(sizeof(struct libvirtd_mdns_group));
|
||||
|
||||
AVAHI_DEBUG("Adding group '%s'", name);
|
||||
if (!group)
|
||||
return NULL;
|
||||
|
||||
memset(group, 0, sizeof(*group));
|
||||
if (!(group->name = strdup(name))) {
|
||||
free(group);
|
||||
return NULL;
|
||||
}
|
||||
group->mdns = mdns;
|
||||
group->next = mdns->group;
|
||||
mdns->group = group;
|
||||
return group;
|
||||
}
|
||||
|
||||
void libvirtd_mdns_remove_group(struct libvirtd_mdns *mdns, struct libvirtd_mdns_group *group) {
|
||||
struct libvirtd_mdns_group *tmp = mdns->group, *prev = NULL;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp == group) {
|
||||
free(group->name);
|
||||
if (prev)
|
||||
prev->next = group->next;
|
||||
else
|
||||
group->mdns->group = group->next;
|
||||
free(group);
|
||||
return;
|
||||
}
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
struct libvirtd_mdns_entry *libvirtd_mdns_add_entry(struct libvirtd_mdns_group *group, const char *type, int port) {
|
||||
struct libvirtd_mdns_entry *entry = malloc(sizeof(struct libvirtd_mdns_entry));
|
||||
|
||||
AVAHI_DEBUG("Adding entry %s %d to group %s", type, port, group->name);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
entry->port = port;
|
||||
if (!(entry->type = strdup(type))) {
|
||||
free(entry);
|
||||
return NULL;
|
||||
}
|
||||
entry->next = group->entry;
|
||||
group->entry = entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void libvirtd_mdns_remove_entry(struct libvirtd_mdns_group *group, struct libvirtd_mdns_entry *entry) {
|
||||
struct libvirtd_mdns_entry *tmp = group->entry, *prev = NULL;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp == entry) {
|
||||
free(entry->type);
|
||||
if (prev)
|
||||
prev->next = entry->next;
|
||||
else
|
||||
group->entry = entry->next;
|
||||
return;
|
||||
}
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
void libvirtd_mdns_stop(struct libvirtd_mdns *mdns)
|
||||
{
|
||||
struct libvirtd_mdns_group *group = mdns->group;
|
||||
while (group) {
|
||||
if (group->handle) {
|
||||
avahi_entry_group_free(group->handle);
|
||||
group->handle = NULL;
|
||||
}
|
||||
group = group->next;
|
||||
}
|
||||
if (mdns->client)
|
||||
avahi_client_free(mdns->client);
|
||||
mdns->client = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* indent-tabs-mode: nil
|
||||
* c-indent-level: 4
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 4
|
||||
* End:
|
||||
*/
|
96
qemud/mdns.h
Normal file
96
qemud/mdns.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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@redhat.com>
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#ifndef __VIRTD_MDNS_H__
|
||||
#define __VIRTD_MDNS_H__
|
||||
|
||||
struct libvirtd_mdns;
|
||||
struct libvirtd_mdns_group;
|
||||
struct libvirtd_mdns_entry;
|
||||
|
||||
/**
|
||||
* Prepares a new mdns manager object for use
|
||||
*/
|
||||
struct libvirtd_mdns *libvirtd_mdns_new(void);
|
||||
|
||||
/**
|
||||
* Starts the mdns client, advertizing any groups/entries currently registered
|
||||
*
|
||||
* @mdns: manager to start advertizing
|
||||
*
|
||||
* Starts the mdns client. Services may not be immediately visible, since
|
||||
* it may asynchronously wait for the mdns service to startup
|
||||
*
|
||||
* returns -1 upon failure, 0 upon success.
|
||||
*/
|
||||
int libvirtd_mdns_start(struct libvirtd_mdns *mdns);
|
||||
|
||||
/**
|
||||
* Stops the mdns client, removing any advertizements
|
||||
*
|
||||
* @mdns: manager to start advertizing
|
||||
*
|
||||
*/
|
||||
void libvirtd_mdns_stop(struct libvirtd_mdns *mdns);
|
||||
|
||||
/**
|
||||
* Adds a group container for advertizement
|
||||
*
|
||||
* @mdns manager to attach the group to
|
||||
* @name unique human readable service name
|
||||
*
|
||||
* returns the group record, or NULL upon failure
|
||||
*/
|
||||
struct libvirtd_mdns_group *libvirtd_mdns_add_group(struct libvirtd_mdns *mdns, const char *name);
|
||||
|
||||
/**
|
||||
* Removes a group container from advertizement
|
||||
*
|
||||
* @mdns amanger to detatch group from
|
||||
* @group group to remove
|
||||
*/
|
||||
void libvirtd_mdns_remove_group(struct libvirtd_mdns *mdns, struct libvirtd_mdns_group *group);
|
||||
|
||||
/**
|
||||
* Adds a service entry in a group
|
||||
*
|
||||
* @group group to attach the entry to
|
||||
* @type service type string
|
||||
* @port tcp port number
|
||||
*
|
||||
* returns the service record, or NULL upon failure
|
||||
*/
|
||||
struct libvirtd_mdns_entry *libvirtd_mdns_add_entry(struct libvirtd_mdns_group *group, const char *type, int port);
|
||||
|
||||
/**
|
||||
* Removes a service entry from a group
|
||||
*
|
||||
* @group group to deteach service entry from
|
||||
* @entry service entry to remove
|
||||
*/
|
||||
void libvirtd_mdns_remove_entry(struct libvirtd_mdns_group *group, struct libvirtd_mdns_entry *entry);
|
||||
|
||||
#endif /* __VIRTD_MDNS_H__ */
|
@ -56,6 +56,9 @@
|
||||
#include "../src/remote_internal.h"
|
||||
#include "../src/conf.h"
|
||||
#include "event.h"
|
||||
#ifdef HAVE_AVAHI
|
||||
#include "mdns.h"
|
||||
#endif
|
||||
|
||||
static int godaemon = 0; /* -d: Be a daemon */
|
||||
static int verbose = 0; /* -v: Verbose mode */
|
||||
@ -69,6 +72,11 @@ static int listen_tcp = 0;
|
||||
static const char *tls_port = LIBVIRTD_TLS_PORT;
|
||||
static const char *tcp_port = LIBVIRTD_TCP_PORT;
|
||||
|
||||
#ifdef HAVE_AVAHI
|
||||
static int mdns_adv = 1;
|
||||
static const char *mdns_name = NULL;
|
||||
#endif
|
||||
|
||||
static int tls_no_verify_certificate = 0;
|
||||
static int tls_no_verify_address = 0;
|
||||
static const char **tls_allowed_ip_list = 0;
|
||||
@ -448,6 +456,7 @@ static int qemudListenUnix(struct qemud_server *server,
|
||||
}
|
||||
|
||||
sock->readonly = readonly;
|
||||
sock->port = -1;
|
||||
|
||||
if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
qemudLog(QEMUD_ERR, "Failed to create socket: %s",
|
||||
@ -570,6 +579,9 @@ remoteListenTCP (struct qemud_server *server,
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < nfds; ++i) {
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t salen = sizeof(sa);
|
||||
|
||||
sock = calloc (1, sizeof *sock);
|
||||
|
||||
if (!sock) {
|
||||
@ -586,6 +598,16 @@ remoteListenTCP (struct qemud_server *server,
|
||||
sock->fd = fds[i];
|
||||
sock->tls = tls;
|
||||
|
||||
if (getsockname(sock->fd, (struct sockaddr *)(&sa), &salen) < 0)
|
||||
return -1;
|
||||
|
||||
if (sa.ss_family == AF_INET)
|
||||
sock->port = htons(((struct sockaddr_in*)&sa)->sin_port);
|
||||
else if (sa.ss_family == AF_INET6)
|
||||
sock->port = htons(((struct sockaddr_in6*)&sa)->sin6_port);
|
||||
else
|
||||
sock->port = -1;
|
||||
|
||||
if (qemudSetCloseExec(sock->fd) < 0 ||
|
||||
qemudSetNonBlock(sock->fd) < 0)
|
||||
return -1;
|
||||
@ -665,6 +687,7 @@ static int qemudInitPaths(struct qemud_server *server,
|
||||
|
||||
static struct qemud_server *qemudInitialize(int sigread) {
|
||||
struct qemud_server *server;
|
||||
struct qemud_socket *sock;
|
||||
char sockname[PATH_MAX];
|
||||
char roSockname[PATH_MAX];
|
||||
|
||||
@ -709,11 +732,55 @@ static struct qemud_server *qemudInitialize(int sigread) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_AVAHI
|
||||
if (getuid() == 0 && mdns_adv) {
|
||||
struct libvirtd_mdns_group *group;
|
||||
int port = 0;
|
||||
|
||||
server->mdns = libvirtd_mdns_new();
|
||||
|
||||
if (!mdns_name) {
|
||||
char groupname[64], localhost[HOST_NAME_MAX+1], *tmp;
|
||||
/* Extract the host part of the potentially FQDN */
|
||||
gethostname(localhost, HOST_NAME_MAX);
|
||||
localhost[HOST_NAME_MAX] = '\0';
|
||||
if ((tmp = strchr(localhost, '.')))
|
||||
*tmp = '\0';
|
||||
snprintf(groupname, sizeof(groupname)-1, "Virtualization Host %s", localhost);
|
||||
groupname[sizeof(groupname)-1] = '\0';
|
||||
group = libvirtd_mdns_add_group(server->mdns, groupname);
|
||||
} else {
|
||||
group = libvirtd_mdns_add_group(server->mdns, mdns_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* See if there's a TLS enabled port we can advertise. Cowardly
|
||||
* don't bother to advertise TCP since we don't want people using
|
||||
* them for real world apps
|
||||
*/
|
||||
sock = server->sockets;
|
||||
while (sock) {
|
||||
if (sock->port != -1 && sock->tls) {
|
||||
port = sock->port;
|
||||
break;
|
||||
}
|
||||
sock = sock->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the primary entry - we choose SSH because its most likely to always
|
||||
* be available
|
||||
*/
|
||||
libvirtd_mdns_add_entry(group, "_libvirt._tcp", port);
|
||||
libvirtd_mdns_start(server->mdns);
|
||||
}
|
||||
#endif
|
||||
|
||||
return server;
|
||||
|
||||
cleanup:
|
||||
if (server) {
|
||||
struct qemud_socket *sock = server->sockets;
|
||||
sock = server->sockets;
|
||||
while (sock) {
|
||||
close(sock->fd);
|
||||
sock = sock->next;
|
||||
@ -1489,6 +1556,16 @@ remoteReadConfigFile (const char *filename)
|
||||
CHECK_TYPE ("tcp_port", VIR_CONF_STRING);
|
||||
tcp_port = p ? strdup (p->str) : tcp_port;
|
||||
|
||||
#ifdef HAVE_AVAHI
|
||||
p = virConfGetValue (conf, "mdns_adv");
|
||||
CHECK_TYPE ("mdns_adv", VIR_CONF_LONG);
|
||||
mdns_adv = p ? p->l : mdns_adv;
|
||||
|
||||
p = virConfGetValue (conf, "mdns_name");
|
||||
CHECK_TYPE ("mdns_name", VIR_CONF_STRING);
|
||||
mdns_name = p ? strdup (p->str) : NULL;
|
||||
#endif
|
||||
|
||||
p = virConfGetValue (conf, "tls_no_verify_certificate");
|
||||
CHECK_TYPE ("tls_no_verify_certificate", VIR_CONF_LONG);
|
||||
tls_no_verify_certificate = p ? p->l : tls_no_verify_certificate;
|
||||
|
Loading…
x
Reference in New Issue
Block a user