Allow RPC servers to advertize themselves using MDNS, via Avahi * src/rpc/virnetserver.c, src/rpc/virnetserver.h: Allow registration of MDNS services via avahi * src/rpc/virnetserverservice.c, src/rpc/virnetserverservice.h: Add API to fetch the listen port number * src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Add API to fetch the local port number * src/rpc/virnetservermdns.c, src/rpc/virnetservermdns.h: Represent an MDNS advertisement --- cfg.mk | 3 + src/Makefile.am | 9 + src/rpc/virnetserver.c | 47 +++- src/rpc/virnetserver.h | 4 +- src/rpc/virnetservermdns.c | 617 +++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetservermdns.h | 109 ++++++++ src/rpc/virnetserverservice.c | 8 + src/rpc/virnetserverservice.h | 2 + src/rpc/virnetsocket.c | 6 + src/rpc/virnetsocket.h | 2 + 10 files changed, 805 insertions(+), 2 deletions(-) create mode 100644 src/rpc/virnetservermdns.c create mode 100644 src/rpc/virnetservermdns.h diff --git a/cfg.mk b/cfg.mk index 436970c..8c71154 100644 --- a/cfg.mk +++ b/cfg.mk @@ -117,6 +117,9 @@ useless_free_options = \ --name=virNetMessageFree \ --name=virNetServerFree \ --name=virNetServerClientFree \ + --name=virNetServerMDNSFree \ + --name=virNetServerMDNSEntryFree \ + --name=virNetServerMDNSGroupFree \ --name=virNetServerProgramFree \ --name=virNetServerServiceFree \ --name=virNetSocketFree \ diff --git a/src/Makefile.am b/src/Makefile.am index 0ab4ffd..38b815b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1255,10 +1255,19 @@ libvirt_net_rpc_server_la_SOURCES = \ rpc/virnetserverservice.h rpc/virnetserverservice.c \ rpc/virnetserverclient.h rpc/virnetserverclient.c \ rpc/virnetserver.h rpc/virnetserver.c +if HAVE_AVAHI +libvirt_net_rpc_server_la_SOURCES += \ + rpc/virnetservermdns.h rpc/virnetservermdns.c +else +EXTRA_DIST += \ + rpc/virnetservermdns.h rpc/virnetservermdns.c +endif libvirt_net_rpc_server_la_CFLAGS = \ + $(AVAHI_CFLAGS) \ $(AM_CFLAGS) libvirt_net_rpc_server_la_LDFLAGS = \ $(AM_LDFLAGS) \ + $(AVAHI_LIBS) \ $(CYGWIN_EXTRA_LDFLAGS) \ $(MINGW_EXTRA_LDFLAGS)l libvirt_net_rpc_server_la_LIBADD = \ diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 547bab3..f78f8d6 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -35,6 +35,9 @@ #include "util.h" #include "files.h" #include "event.h" +#if HAVE_AVAHI +#include "virnetservermdns.h" +#endif #define VIR_FROM_THIS VIR_FROM_RPC @@ -75,6 +78,12 @@ struct _virNetServer { int sigwrite; int sigwatch; + char *mdnsGroupName; +#if HAVE_AVAHI + virNetServerMDNSPtr mdns; + virNetServerMDNSGroupPtr mdnsGroup; +#endif + size_t nservices; virNetServerServicePtr *services; @@ -260,6 +269,7 @@ static void virNetServerFatalSignal(int sig, siginfo_t * siginfo ATTRIBUTE_UNUSE virNetServerPtr virNetServerNew(size_t min_workers, size_t max_workers, size_t max_clients, + const char *mdnsGroupName, virNetServerClientInitHook clientInitHook) { virNetServerPtr srv; @@ -282,6 +292,19 @@ virNetServerPtr virNetServerNew(size_t min_workers, srv->clientInitHook = clientInitHook; srv->privileged = geteuid() == 0 ? true : false; + if (!(srv->mdnsGroupName = strdup(mdnsGroupName))) { + virReportOOMError(); + goto error; + } +#if HAVE_AVAHI + if (srv->mdnsGroupName) { + if (!(srv->mdns = virNetServerMDNSNew())) + goto error; + if (!(srv->mdnsGroup = virNetServerMDNSAddGroup(srv->mdns, mdnsGroupName))) + goto error; + } +#endif + if (virMutexInit(&srv->lock) < 0) { virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("cannot initialize mutex")); @@ -503,13 +526,26 @@ error: int virNetServerAddService(virNetServerPtr srv, - virNetServerServicePtr svc) + virNetServerServicePtr svc, + const char *mdnsEntryName ATTRIBUTE_UNUSED) { virNetServerLock(srv); if (VIR_EXPAND_N(srv->services, srv->nservices, 1) < 0) goto no_memory; +#if HAVE_AVAHI + if (mdnsEntryName) { + int port = virNetServerServiceGetPort(svc); + virNetServerMDNSEntryPtr entry; + + if (!(entry = virNetServerMDNSAddEntry(srv->mdnsGroup, + mdnsEntryName, + port))) + goto error; + } +#endif + srv->services[srv->nservices-1] = svc; virNetServerServiceRef(svc); @@ -522,6 +558,9 @@ int virNetServerAddService(virNetServerPtr srv, no_memory: virReportOOMError(); +#if HAVE_AVAHI +error: +#endif virNetServerUnlock(srv); return -1; } @@ -591,6 +630,12 @@ void virNetServerRun(virNetServerPtr srv) virNetServerLock(srv); +#if HAVE_AVAHI + if (srv->mdns && + virNetServerMDNSStart(srv->mdns) < 0) + goto cleanup; +#endif + if (srv->autoShutdownTimeout && (timerid = virEventAddTimeout(-1, virNetServerAutoShutdownTimer, diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index d8d7c8e..ed09ecf 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -38,6 +38,7 @@ typedef int (*virNetServerClientInitHook)(virNetServerPtr srv, virNetServerPtr virNetServerNew(size_t min_workers, size_t max_workers, size_t max_clients, + const char *mdnsGroupName, virNetServerClientInitHook clientInitHook); typedef int (*virNetServerAutoShutdownFunc)(virNetServerPtr srv, void *opaque); @@ -59,7 +60,8 @@ int virNetServerAddSignalHandler(virNetServerPtr srv, void *opaque); int virNetServerAddService(virNetServerPtr srv, - virNetServerServicePtr svc); + virNetServerServicePtr svc, + const char *mdnsEntryName); int virNetServerAddProgram(virNetServerPtr srv, virNetServerProgramPtr prog); diff --git a/src/rpc/virnetservermdns.c b/src/rpc/virnetservermdns.c new file mode 100644 index 0000000..c6faa3e --- /dev/null +++ b/src/rpc/virnetservermdns.c @@ -0,0 +1,617 @@ +/* + * virnetservermdns.c: advertise server sockets + * + * Copyright (C) 2011 Red Hat, Inc. + * 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 <config.h> + +#include <time.h> +#include <stdio.h> +#include <stdlib.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 "virnetservermdns.h" +#include "event.h" +#include "event_poll.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +struct _virNetServerMDNSEntry { + char *type; + int port; + virNetServerMDNSEntryPtr next; +}; + +struct _virNetServerMDNSGroup { + virNetServerMDNSPtr mdns; + AvahiEntryGroup *handle; + char *name; + virNetServerMDNSEntryPtr entry; + virNetServerMDNSGroupPtr next; +}; + +struct _virNetServerMDNS { + AvahiClient *client; + AvahiPoll *poller; + virNetServerMDNSGroupPtr group; +}; + +/* Avahi API requires this struct name in the app :-( */ +struct AvahiWatch { + int watch; + int fd; + int revents; + AvahiWatchCallback callback; + void *userdata; +}; + +/* Avahi API requires this struct name in the app :-( */ +struct AvahiTimeout { + int timer; + AvahiTimeoutCallback callback; + void *userdata; +}; + +static void virNetServerMDNSCreateServices(virNetServerMDNSGroupPtr group); + +/* Called whenever the entry group state changes */ +static void virNetServerMDNSGroupCallback(AvahiEntryGroup *g ATTRIBUTE_UNUSED, + AvahiEntryGroupState state, + void *data) +{ + virNetServerMDNSGroupPtr group = data; + + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED: + /* The entry group has been established successfully */ + VIR_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); + VIR_FREE(group->name); + group->name = n; + + VIR_DEBUG("Group name collision, renaming service to '%s'", group->name); + + /* And recreate the services */ + virNetServerMDNSCreateServices(group); + } + break; + + case AVAHI_ENTRY_GROUP_FAILURE : + VIR_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 virNetServerMDNSCreateServices(virNetServerMDNSGroupPtr group) +{ + virNetServerMDNSPtr mdns = group->mdns; + virNetServerMDNSEntryPtr entry; + int ret; + VIR_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) { + VIR_DEBUG("Creating initial group %s", group->name); + if (!(group->handle = + avahi_entry_group_new(mdns->client, + virNetServerMDNSGroupCallback, + group))) { + VIR_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) { + VIR_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); + VIR_DEBUG("Failed to commit entry_group: %s", + avahi_strerror(ret)); + return; + } +} + + +static void virNetServerMDNSClientCallback(AvahiClient *c, + AvahiClientState state, + void *data) +{ + virNetServerMDNSPtr mdns = data; + virNetServerMDNSGroupPtr group; + if (!mdns->client) + mdns->client = c; + + VIR_DEBUG("Callback state=%d", state); + + /* 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 */ + VIR_DEBUG("Client running %p", mdns->client); + group = mdns->group; + while (group) { + virNetServerMDNSCreateServices(group); + group = group->next; + } + break; + + case AVAHI_CLIENT_FAILURE: + VIR_DEBUG("Client failure: %s", + avahi_strerror(avahi_client_errno(c))); + virNetServerMDNSStop(mdns); + virNetServerMDNSStart(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 established. */ + VIR_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: + VIR_DEBUG("Client connecting.... %p", mdns->client); + ; + } +} + + +static void virNetServerMDNSWatchDispatch(int watch, int fd, int events, void *opaque) +{ + AvahiWatch *w = opaque; + int fd_events = virEventPollToNativeEvents(events); + VIR_DEBUG("Dispatch watch %d FD %d Event %d", watch, fd, fd_events); + w->revents = fd_events; + w->callback(w, fd, fd_events, w->userdata); +} + +static void virNetServerMDNSWatchDofree(void *w) +{ + VIR_FREE(w); +} + + +static AvahiWatch *virNetServerMDNSWatchNew(const AvahiPoll *api ATTRIBUTE_UNUSED, + int fd, AvahiWatchEvent event, + AvahiWatchCallback cb, void *userdata) +{ + AvahiWatch *w; + virEventHandleType hEvents; + if (VIR_ALLOC(w) < 0) { + virReportOOMError(); + return NULL; + } + + w->fd = fd; + w->revents = 0; + w->callback = cb; + w->userdata = userdata; + + VIR_DEBUG("New handle %p FD %d Event %d", w, w->fd, event); + hEvents = virEventPollFromNativeEvents(event); + if ((w->watch = virEventAddHandle(fd, hEvents, + virNetServerMDNSWatchDispatch, + w, + virNetServerMDNSWatchDofree)) < 0) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Failed to add watch for fd %d events %d"), fd, hEvents); + VIR_FREE(w); + return NULL; + } + + return w; +} + +static void virNetServerMDNSWatchUpdate(AvahiWatch *w, AvahiWatchEvent event) +{ + VIR_DEBUG("Update handle %p FD %d Event %d", w, w->fd, event); + virEventUpdateHandle(w->watch, event); +} + +static AvahiWatchEvent virNetServerMDNSWatchGetEvents(AvahiWatch *w) +{ + VIR_DEBUG("Get handle events %p %d", w, w->fd); + return w->revents; +} + +static void virNetServerMDNSWatchFree(AvahiWatch *w) +{ + VIR_DEBUG("Free handle %p %d", w, w->fd); + virEventRemoveHandle(w->watch); +} + +static void virNetServerMDNSTimeoutDispatch(int timer ATTRIBUTE_UNUSED, void *opaque) +{ + AvahiTimeout *t = (AvahiTimeout*)opaque; + VIR_DEBUG("Dispatch timeout %p %d", t, timer); + virEventUpdateTimeout(t->timer, -1); + t->callback(t, t->userdata); +} + +static void virNetServerMDNSTimeoutDofree(void *t) +{ + VIR_FREE(t); +} + +static AvahiTimeout *virNetServerMDNSTimeoutNew(const AvahiPoll *api ATTRIBUTE_UNUSED, + const struct timeval *tv, + AvahiTimeoutCallback cb, + void *userdata) +{ + AvahiTimeout *t; + struct timeval now; + long long nowms, thenms, timeout; + VIR_DEBUG("Add timeout TV %p", tv); + if (VIR_ALLOC(t) < 0) { + virReportOOMError(); + return NULL; + } + + if (gettimeofday(&now, NULL) < 0) { + virReportSystemError(errno, "%s", + _("Unable to get current time")); + VIR_FREE(t); + return NULL; + } + + VIR_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 = virEventAddTimeout(timeout, + virNetServerMDNSTimeoutDispatch, + t, + virNetServerMDNSTimeoutDofree); + t->callback = cb; + t->userdata = userdata; + + if (t->timer < 0) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Failed to add timer with timeout %d"), (int)timeout); + VIR_FREE(t); + return NULL; + } + + return t; +} + +static void virNetServerMDNSTimeoutUpdate(AvahiTimeout *t, const struct timeval *tv) +{ + struct timeval now; + long long nowms, thenms, timeout; + VIR_DEBUG("Update timeout %p TV %p", t, tv); + if (gettimeofday(&now, NULL) < 0) { + VIR_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; + } + + virEventUpdateTimeout(t->timer, timeout); +} + +static void virNetServerMDNSTimeoutFree(AvahiTimeout *t) +{ + VIR_DEBUG("Free timeout %p", t); + virEventRemoveTimeout(t->timer); +} + + +static AvahiPoll *virNetServerMDNSCreatePoll(void) +{ + AvahiPoll *p; + if (VIR_ALLOC(p) < 0) { + virReportOOMError(); + return NULL; + } + + p->userdata = NULL; + + p->watch_new = virNetServerMDNSWatchNew; + p->watch_update = virNetServerMDNSWatchUpdate; + p->watch_get_events = virNetServerMDNSWatchGetEvents; + p->watch_free = virNetServerMDNSWatchFree; + + p->timeout_new = virNetServerMDNSTimeoutNew; + p->timeout_update = virNetServerMDNSTimeoutUpdate; + p->timeout_free = virNetServerMDNSTimeoutFree; + + return p; +} + + +virNetServerMDNS *virNetServerMDNSNew(void) +{ + virNetServerMDNS *mdns; + if (VIR_ALLOC(mdns) < 0) + return NULL; + + /* Allocate main loop object */ + if (!(mdns->poller = virNetServerMDNSCreatePoll())) { + VIR_FREE(mdns); + return NULL; + } + + return mdns; +} + + +int virNetServerMDNSStart(virNetServerMDNS *mdns) +{ + int error; + VIR_DEBUG("Starting client %p", mdns); + mdns->client = avahi_client_new(mdns->poller, + AVAHI_CLIENT_NO_FAIL, + virNetServerMDNSClientCallback, + mdns, &error); + + if (!mdns->client) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Failed to create mDNS client: %s"), + avahi_strerror(error)); + return -1; + } + + return 0; +} + + +virNetServerMDNSGroupPtr virNetServerMDNSAddGroup(virNetServerMDNS *mdns, + const char *name) +{ + virNetServerMDNSGroupPtr group; + + VIR_DEBUG("Adding group '%s'", name); + if (VIR_ALLOC(group) < 0) { + virReportOOMError(); + return NULL; + } + + if (!(group->name = strdup(name))) { + VIR_FREE(group); + virReportOOMError(); + return NULL; + } + group->mdns = mdns; + group->next = mdns->group; + mdns->group = group; + return group; +} + + +void virNetServerMDNSRemoveGroup(virNetServerMDNSPtr mdns, + virNetServerMDNSGroupPtr group) +{ + virNetServerMDNSGroupPtr tmp = mdns->group, prev = NULL; + + while (tmp) { + if (tmp == group) { + VIR_FREE(group->name); + if (prev) + prev->next = group->next; + else + group->mdns->group = group->next; + VIR_FREE(group); + return; + } + prev = tmp; + tmp = tmp->next; + } +} + + +virNetServerMDNSEntryPtr virNetServerMDNSAddEntry(virNetServerMDNSGroupPtr group, + const char *type, + int port) +{ + virNetServerMDNSEntryPtr entry; + + VIR_DEBUG("Adding entry %s %d to group %s", type, port, group->name); + if (VIR_ALLOC(entry) < 0) { + virReportOOMError(); + return NULL; + } + + entry->port = port; + if (!(entry->type = strdup(type))) { + VIR_FREE(entry); + virReportOOMError(); + return NULL; + } + entry->next = group->entry; + group->entry = entry; + return entry; +} + + +void virNetServerMDNSRemoveEntry(virNetServerMDNSGroupPtr group, + virNetServerMDNSEntryPtr entry) +{ + virNetServerMDNSEntryPtr tmp = group->entry, prev = NULL; + + while (tmp) { + if (tmp == entry) { + VIR_FREE(entry->type); + if (prev) + prev->next = entry->next; + else + group->entry = entry->next; + return; + } + prev = tmp; + tmp = tmp->next; + } +} + + +void virNetServerMDNSStop(virNetServerMDNSPtr mdns) +{ + virNetServerMDNSGroupPtr 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; +} + + +void virNetServerMDNSFree(virNetServerMDNSPtr mdns) +{ + virNetServerMDNSGroupPtr group, tmp; + + if (!mdns) + return; + + group = mdns->group; + while (group) { + tmp = group->next; + virNetServerMDNSGroupFree(group); + group = tmp; + } + + VIR_FREE(mdns); +} + + +void virNetServerMDNSGroupFree(virNetServerMDNSGroupPtr grp) +{ + virNetServerMDNSEntryPtr entry, tmp; + + if (!grp) + return; + + entry = grp->entry; + while (entry) { + tmp = entry->next; + virNetServerMDNSEntryFree(entry); + entry = tmp; + } + + VIR_FREE(grp); +} + + +void virNetServerMDNSEntryFree(virNetServerMDNSEntryPtr entry) +{ + if (!entry) + return; + + VIR_FREE(entry); +} + + diff --git a/src/rpc/virnetservermdns.h b/src/rpc/virnetservermdns.h new file mode 100644 index 0000000..6261aef --- /dev/null +++ b/src/rpc/virnetservermdns.h @@ -0,0 +1,109 @@ +/* + * virnetservermdns.c: advertise server sockets + * + * Copyright (C) 2011 Red Hat, Inc. + * 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> + */ + +#ifndef __VIR_NET_SERVER_MDNS_H__ +# define __VIR_NET_SERVER_MDNS_H__ + +#include "internal.h" + +typedef struct _virNetServerMDNS virNetServerMDNS; +typedef virNetServerMDNS *virNetServerMDNSPtr; +typedef struct _virNetServerMDNSGroup virNetServerMDNSGroup; +typedef virNetServerMDNSGroup *virNetServerMDNSGroupPtr; +typedef struct _virNetServerMDNSEntry virNetServerMDNSEntry; +typedef virNetServerMDNSEntry *virNetServerMDNSEntryPtr; + + +/** + * Prepares a new mdns manager object for use + */ +virNetServerMDNSPtr virNetServerMDNSNew(void); + +/** + * Starts the mdns client, advertising any groups/entries currently registered + * + * @mdns: manager to start advertising + * + * 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 virNetServerMDNSStart(virNetServerMDNSPtr mdns); + +/** + * Stops the mdns client, removing any advertisements + * + * @mdns: manager to start advertising + * + */ +void virNetServerMDNSStop(virNetServerMDNSPtr mdns); + +/** + * Adds a group container for advertisement + * + * @mdns manager to attach the group to + * @name unique human readable service name + * + * returns the group record, or NULL upon failure + */ +virNetServerMDNSGroupPtr virNetServerMDNSAddGroup(virNetServerMDNSPtr mdns, + const char *name); + +/** + * Removes a group container from advertisement + * + * @mdns amanger to detach group from + * @group group to remove + */ +void virNetServerMDNSRemoveGroup(virNetServerMDNSPtr mdns, + virNetServerMDNSGroupPtr 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 + */ +virNetServerMDNSEntryPtr virNetServerMDNSAddEntry(virNetServerMDNSGroupPtr group, + const char *type, int port); + +/** + * Removes a service entry from a group + * + * @group group to detach service entry from + * @entry service entry to remove + */ +void virNetServerMDNSRemoveEntry(virNetServerMDNSGroupPtr group, + virNetServerMDNSEntryPtr entry); + +void virNetServerMDNSFree(virNetServerMDNSPtr ptr); +void virNetServerMDNSGroupFree(virNetServerMDNSGroupPtr ptr); +void virNetServerMDNSEntryFree(virNetServerMDNSEntryPtr ptr); + +#endif /* __VIR_NET_SERVER_MDNS_H__ */ diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c index 0cc65c3..e5a47b0 100644 --- a/src/rpc/virnetserverservice.c +++ b/src/rpc/virnetserverservice.c @@ -187,6 +187,14 @@ error: } +int virNetServerServiceGetPort(virNetServerServicePtr svc) +{ + /* We're assuming if there are multiple sockets + * for IPv4 & 6, then they are all on same port */ + return virNetSocketGetPort(svc->socks[0]); +} + + int virNetServerServiceGetAuth(virNetServerServicePtr svc) { return svc->auth; diff --git a/src/rpc/virnetserverservice.h b/src/rpc/virnetserverservice.h index b8ccd55..378fa0b 100644 --- a/src/rpc/virnetserverservice.h +++ b/src/rpc/virnetserverservice.h @@ -48,6 +48,8 @@ virNetServerServicePtr virNetServerServiceNewUNIX(const char *path, bool readonly, virNetTLSContextPtr tls); +int virNetServerServiceGetPort(virNetServerServicePtr svc); + int virNetServerServiceGetAuth(virNetServerServicePtr svc); bool virNetServerServiceIsReadonly(virNetServerServicePtr svc); diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index daa40f4..3c0867f 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -693,6 +693,12 @@ bool virNetSocketIsLocal(virNetSocketPtr sock) } +int virNetSocketGetPort(virNetSocketPtr sock) +{ + return virSocketGetPort(&sock->localAddr); +} + + #ifdef SO_PEERCRED int virNetSocketGetLocalIdentity(virNetSocketPtr sock, uid_t *uid, diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h index 59ff288..356d6c6 100644 --- a/src/rpc/virnetsocket.h +++ b/src/rpc/virnetsocket.h @@ -77,6 +77,8 @@ int virNetSocketNewConnectExternal(const char **cmdargv, int virNetSocketGetFD(virNetSocketPtr sock); bool virNetSocketIsLocal(virNetSocketPtr sock); +int virNetSocketGetPort(virNetSocketPtr sock); + int virNetSocketGetLocalIdentity(virNetSocketPtr sock, uid_t *uid, pid_t *pid); -- 1.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list