Added support for Avahi mDNS advertisement

This commit is contained in:
Daniel P. Berrange 2007-09-19 01:56:55 +00:00
parent c79514fda0
commit 8f4e48edff
10 changed files with 777 additions and 13 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
View 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
View 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__ */

View File

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