This API is merely a convenience API, i.e. when managing clients connected to
daemon's servers, we should know (convenience) which server the specific client
is connected to. This implies a client-side representation of a server along
with a basic API to let the administrating client know what servers are actually
available on the daemon.
---
daemon/Makefile.am | 2 +-
daemon/admin.c | 55 +++++++++++++++
daemon/admin_server.c | 79 +++++++++++++++++++++
daemon/admin_server.h | 33 +++++++++
include/libvirt/libvirt-admin.h | 7 ++
src/admin/admin_protocol.x | 18 ++++-
src/admin_protocol-structs | 15 ++++
src/libvirt-admin.c | 148 ++++++++++++++++++++++++++++++++++++++++
src/libvirt_admin_private.syms | 2 +
src/libvirt_admin_public.syms | 3 +
src/rpc/virnetdaemon.c | 13 ++++
src/rpc/virnetdaemon.h | 2 +
src/rpc/virnetserver.c | 12 ++++
src/rpc/virnetserver.h | 3 +
14 files changed, 390 insertions(+), 2 deletions(-)
create mode 100644 daemon/admin_server.c
create mode 100644 daemon/admin_server.h
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 5b13960..d255c89 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -129,7 +129,7 @@ libvirtd_conf_la_LIBADD = $(LIBXML_LIBS)
noinst_LTLIBRARIES += libvirtd_admin.la
libvirtd_admin_la_SOURCES = \
- admin.c admin.h
+ admin.c admin.h admin_server.c admin_server.h
libvirtd_admin_la_CFLAGS = \
$(AM_CFLAGS) \
diff --git a/daemon/admin.c b/daemon/admin.c
index 6899318..0db7806 100644
--- a/daemon/admin.c
+++ b/daemon/admin.c
@@ -28,6 +28,7 @@
#include "admin_protocol.h"
#include "admin.h"
+#include "admin_server.h"
#include "datatypes.h"
#include "viralloc.h"
#include "virerror.h"
@@ -77,6 +78,15 @@ remoteAdmClientInitHook(virNetServerClientPtr client ATTRIBUTE_UNUSED,
return priv;
}
+/* Helpers */
+
+static void
+make_nonnull_server(admin_nonnull_server *srv_dst,
+ virAdmServerPtr srv_src)
+{
+ ignore_value(VIR_STRDUP_QUIET(srv_dst->name, srv_src->name));
+}
+
/* Functions */
static int
adminDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
@@ -123,4 +133,49 @@ adminConnectGetLibVersion(virNetDaemonPtr dmn ATTRIBUTE_UNUSED,
return 0;
}
+static int
+adminDispatchConnectListServers(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ admin_connect_list_servers_args *args,
+ admin_connect_list_servers_ret *ret)
+{
+ virAdmServerPtr *servers = NULL;
+ int nservers = 0;
+ int rv = -1;
+ size_t i;
+ struct daemonAdmClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if ((nservers =
+ adminDaemonListServers(priv->dmn,
+ args->need_results ? &servers : NULL,
+ args->flags)) < 0)
+ goto cleanup;
+
+ if (servers && nservers) {
+ if (VIR_ALLOC_N(ret->servers.servers_val, nservers) < 0)
+ goto cleanup;
+
+ ret->servers.servers_len = nservers;
+ for (i = 0; i < nservers; i++)
+ make_nonnull_server(ret->servers.servers_val + i, servers[i]);
+ } else {
+ ret->servers.servers_len = 0;
+ ret->servers.servers_val = NULL;
+ }
+
+ ret->ret = nservers;
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ if (servers && nservers > 0)
+ for (i = 0; i < nservers; i++)
+ virObjectUnref(servers[i]);
+ VIR_FREE(servers);
+ return rv;
+}
#include "admin_dispatch.h"
diff --git a/daemon/admin_server.c b/daemon/admin_server.c
new file mode 100644
index 0000000..0cdd6b3
--- /dev/null
+++ b/daemon/admin_server.c
@@ -0,0 +1,79 @@
+/*
+ * admin_server.c: admin methods to manage daemons and clients
+ *
+ * Copyright (C) 2014-2015 Red Hat, Inc.
+ *
+ * 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, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author: Martin Kletzander <mkletzan(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include "admin_server.h"
+#include "datatypes.h"
+#include "viralloc.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virnetdaemon.h"
+#include "virnetserver.h"
+#include "virstring.h"
+
+#define VIR_FROM_THIS VIR_FROM_ADMIN
+
+VIR_LOG_INIT("daemon.admin_server");
+
+int
+adminDaemonListServers(virNetDaemonPtr dmn,
+ virAdmServerPtr **servers,
+ unsigned int flags)
+{
+ int ret = -1;
+ const char *name = NULL;
+ virNetServerPtr *srv_objs = NULL;
+ virAdmServerPtr *srvs = NULL;
+ size_t i;
+ size_t nsrvs = 0;
+
+ virCheckFlags(0, -1);
+
+ nsrvs = virNetDaemonGetServers(dmn, &srv_objs);
+ if (servers) {
+ if (VIR_ALLOC_N(srvs, nsrvs + 1) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nsrvs; i++) {
+ virNetServerPtr srv = srv_objs[i];
+
+ name = virNetServerGetName(srv);
+ virObjectLock(srv);
+ if (!(srvs[i] = virAdmGetServer(NULL, name))) {
+ virObjectUnlock(srv);
+ goto cleanup;
+ }
+
+ virObjectUnlock(srv);
+ }
+
+ *servers = srvs;
+ srvs = NULL;
+ }
+
+ ret = nsrvs;
+
+ cleanup:
+ virObjectListFree(srvs);
+ return ret;
+}
diff --git a/daemon/admin_server.h b/daemon/admin_server.h
new file mode 100644
index 0000000..9558802
--- /dev/null
+++ b/daemon/admin_server.h
@@ -0,0 +1,33 @@
+/*
+ * admin_server.h: admin methods to manage daemons and clients
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * 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, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author: Martin Kletzander <mkletzan(a)redhat.com>
+ */
+
+#ifndef __LIBVIRTD_ADMIN_SERVER_H__
+# define __LIBVIRTD_ADMIN_SERVER_H__
+
+# include "rpc/virnetdaemon.h"
+
+int
+adminDaemonListServers(virNetDaemonPtr dmn,
+ virAdmServerPtr **servers,
+ unsigned int flags);
+
+#endif /* __LIBVIRTD_ADMIN_SERVER_H__ */
diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h
index 23420c7..d75aad4 100644
--- a/include/libvirt/libvirt-admin.h
+++ b/include/libvirt/libvirt-admin.h
@@ -58,6 +58,11 @@ typedef virAdmServer *virAdmServerPtr;
virAdmConnectPtr virAdmConnectOpen(const char *name, unsigned int flags);
int virAdmConnectClose(virAdmConnectPtr conn);
+int virAdmConnectListServers(virAdmConnectPtr conn,
+ virAdmServerPtr **servers,
+ unsigned int flags);
+
+int virAdmServerFree(virAdmServerPtr srv);
int virAdmConnectRef(virAdmConnectPtr conn);
int virAdmConnectIsAlive(virAdmConnectPtr conn);
@@ -87,6 +92,8 @@ int virAdmConnectRegisterCloseCallback(virAdmConnectPtr conn,
int virAdmConnectUnregisterCloseCallback(virAdmConnectPtr conn,
virAdmConnectCloseFunc cb);
+const char *virAdmGetServerName(virAdmServerPtr srv);
+
# ifdef __cplusplus
}
# endif
diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x
index 2f1f534..14ab2a3 100644
--- a/src/admin/admin_protocol.x
+++ b/src/admin/admin_protocol.x
@@ -53,6 +53,16 @@ struct admin_connect_get_lib_version_ret {
unsigned hyper libVer;
};
+struct admin_connect_list_servers_args {
+ unsigned int need_results;
+ unsigned int flags;
+};
+
+struct admin_connect_list_servers_ret {
+ admin_nonnull_server servers<ADMIN_SERVER_LIST_MAX>;
+ unsigned int ret;
+};
+
/* Define the program number, protocol version and procedure numbers here. */
const ADMIN_PROGRAM = 0x06900690;
const ADMIN_PROTOCOL_VERSION = 1;
@@ -88,5 +98,11 @@ enum admin_procedure {
/**
* @generate: both
*/
- ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3
+ ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3,
+
+ /**
+ * @generate: none
+ * @priority: high
+ */
+ ADMIN_PROC_CONNECT_LIST_SERVERS = 4
};
diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs
index 809379b..8f2633a 100644
--- a/src/admin_protocol-structs
+++ b/src/admin_protocol-structs
@@ -1,12 +1,27 @@
/* -*- c -*- */
+struct admin_nonnull_server {
+ admin_nonnull_string name;
+};
struct admin_connect_open_args {
u_int flags;
};
struct admin_connect_get_lib_version_ret {
uint64_t libVer;
};
+struct admin_connect_list_servers_args {
+ u_int need_results;
+ u_int flags;
+};
+struct admin_connect_list_servers_ret {
+ struct {
+ u_int servers_len;
+ admin_nonnull_server * servers_val;
+ } servers;
+ u_int ret;
+};
enum admin_procedure {
ADMIN_PROC_CONNECT_OPEN = 1,
ADMIN_PROC_CONNECT_CLOSE = 2,
ADMIN_PROC_CONNECT_GET_LIB_VERSION = 3,
+ ADMIN_PROC_CONNECT_LIST_SERVERS = 4,
};
diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c
index 6e6da81..35fbcd0 100644
--- a/src/libvirt-admin.c
+++ b/src/libvirt-admin.c
@@ -45,6 +45,13 @@ VIR_LOG_INIT("libvirt-admin");
#include "admin_remote.c"
+/* Helpers */
+static virAdmServerPtr
+get_nonnull_server(virAdmConnectPtr conn, admin_nonnull_server server)
+{
+ return virAdmGetServer(conn, server.name);
+}
+
static bool virAdmGlobalError;
static virOnceControl virAdmGlobalOnce = VIR_ONCE_CONTROL_INITIALIZER;
@@ -549,7 +556,148 @@ int virAdmConnectGetLibVersion(virAdmConnectPtr conn,
goto error;
return 0;
+ error:
+ virDispatchError(NULL);
+ return -1;
+}
+
+static int
+remoteAdminConnectListServers(virAdmConnectPtr conn,
+ virAdmServerPtr **servers,
+ unsigned int flags)
+{
+ int rv = -1;
+ size_t i;
+ virAdmServerPtr *tmp_srvs = NULL;
+ remoteAdminPrivPtr priv = conn->privateData;
+ admin_connect_list_servers_args args;
+ admin_connect_list_servers_ret ret;
+
+ args.need_results = !!servers;
+ args.flags = flags;
+
+ memset(&ret, 0, sizeof(ret));
+ if (call(conn,
+ 0,
+ ADMIN_PROC_CONNECT_LIST_SERVERS,
+ (xdrproc_t) xdr_admin_connect_list_servers_args,
+ (char *) &args,
+ (xdrproc_t) xdr_admin_connect_list_servers_ret,
+ (char *) &ret) == -1)
+ goto done;
+
+ if (ret.servers.servers_len > ADMIN_SERVER_LIST_MAX) {
+ virReportError(VIR_ERR_RPC,
+ _("Too many servers '%d' for limit
'%d'"),
+ ret.servers.servers_len, ADMIN_SERVER_LIST_MAX);
+ goto cleanup;
+ }
+
+ if (servers) {
+ if (VIR_ALLOC_N(tmp_srvs, ret.servers.servers_len + 1) < 0)
+ goto cleanup;
+
+ for (i = 0; i < ret.servers.servers_len; i++) {
+ tmp_srvs[i] = get_nonnull_server(conn, ret.servers.servers_val[i]);
+ if (!tmp_srvs[i])
+ goto cleanup;
+ }
+ *servers = tmp_srvs;
+ tmp_srvs = NULL;
+ }
+
+ rv = ret.ret;
+
+ cleanup:
+ if (tmp_srvs) {
+ for (i = 0; i < ret.servers.servers_len; i++)
+ virObjectUnref(tmp_srvs[i]);
+ VIR_FREE(tmp_srvs);
+ }
+
+ xdr_free((xdrproc_t) xdr_admin_connect_list_servers_ret, (char *) &ret);
+
+ done:
+ virObjectUnlock(priv);
+ return rv;
+}
+
+
+/**
+ * virAdmGetServerName:
+ * @srv: a server object
+ *
+ * Get the public name for specified server
+ *
+ * Returns a pointer to the name or NULL. The string doesn't need to be
+ * deallocated since its lifetime will be the same as the server object.
+ */
+const char *
+virAdmGetServerName(virAdmServerPtr srv)
+{
+ VIR_DEBUG("server=%p", srv);
+ virResetLastError();
+ virCheckAdmServerReturn(srv, NULL);
+
+ return srv->name;
+}
+
+/**
+ * virAdmServerFree:
+ * @srv: server object
+ *
+ * Release the server object. The running instance is kept alive.
+ * The data structure is freed and should not be used thereafter.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int virAdmServerFree(virAdmServerPtr srv)
+{
+ VIR_DEBUG("server=%p", srv);
+
+ virResetLastError();
+ virCheckAdmServerReturn(srv, -1);
+
+ virObjectUnref(srv);
+ return 0;
+}
+
+/**
+ * virAdmConnectListServers:
+ * @conn: daemon connection reference
+ * @servers: Pointer to a list to store an array containing objects or NULL
+ * if the list is not required (number of servers only)
+ * @flags: bitwise-OR of virAdmConnectListServersFlags
+ *
+ * Collect list of all servers provided by daemon the client is connected to.
+ *
+ * Returns the number of servers available on daemon side or -1 in case of a
+ * failure, setting @servers to NULL. There is a guaranteed extra element set
+ * to NULL in the @servers list returned to make the iteration easier, excluding
+ * this extra element from the final count.
+ * Caller is responsible to call virAdmServerFree() on each list element,
+ * followed by freeing @servers.
+ */
+int
+virAdmConnectListServers(virAdmConnectPtr conn,
+ virAdmServerPtr **servers,
+ unsigned int flags)
+{
+ int ret = -1;
+
+ VIR_DEBUG("conn=%p, servers=%p, flags=%x", conn, servers, flags);
+
+ virResetLastError();
+
+ if (servers)
+ *servers = NULL;
+
+ virCheckAdmConnectReturn(conn, -1);
+ if ((ret = remoteAdminConnectListServers(conn, servers, flags)) < 0)
+ goto error;
+
+ return ret;
error:
virDispatchError(NULL);
return -1;
diff --git a/src/libvirt_admin_private.syms b/src/libvirt_admin_private.syms
index 31f1f8d..ae6b9dd 100644
--- a/src/libvirt_admin_private.syms
+++ b/src/libvirt_admin_private.syms
@@ -7,6 +7,8 @@
# admin/admin_protocol.x
xdr_admin_connect_get_lib_version_ret;
+xdr_admin_connect_list_servers_args;
+xdr_admin_connect_list_servers_ret;
xdr_admin_connect_open_args;
# datatypes.h
diff --git a/src/libvirt_admin_public.syms b/src/libvirt_admin_public.syms
index 33b1db4..7963550 100644
--- a/src/libvirt_admin_public.syms
+++ b/src/libvirt_admin_public.syms
@@ -21,4 +21,7 @@ LIBVIRT_ADMIN_1.3.0 {
virAdmConnectGetLibVersion;
virAdmConnectRegisterCloseCallback;
virAdmConnectUnregisterCloseCallback;
+ virAdmConnectListServers;
+ virAdmGetServerName;
+ virAdmServerFree;
};
diff --git a/src/rpc/virnetdaemon.c b/src/rpc/virnetdaemon.c
index 5324873..9adde69 100644
--- a/src/rpc/virnetdaemon.c
+++ b/src/rpc/virnetdaemon.c
@@ -204,6 +204,19 @@ virNetDaemonGetServer(virNetDaemonPtr dmn,
return srv;
}
+size_t
+virNetDaemonGetServers(virNetDaemonPtr dmn,
+ virNetServerPtr **servers)
+{
+ size_t nservers;
+
+ virObjectLock(dmn);
+ nservers = dmn->nservers;
+ *servers = dmn->servers;
+ virObjectUnlock(dmn);
+
+ return nservers;
+}
virNetServerPtr
virNetDaemonAddServerPostExec(virNetDaemonPtr dmn,
const char *serverName,
diff --git a/src/rpc/virnetdaemon.h b/src/rpc/virnetdaemon.h
index bb7de29..12a90c0 100644
--- a/src/rpc/virnetdaemon.h
+++ b/src/rpc/virnetdaemon.h
@@ -81,5 +81,7 @@ bool virNetDaemonHasClients(virNetDaemonPtr dmn);
virNetServerPtr virNetDaemonGetServer(virNetDaemonPtr dmn,
int subServerID);
+size_t virNetDaemonGetServers(virNetDaemonPtr dmn,
+ virNetServerPtr **servers);
#endif /* __VIR_NET_DAEMON_H__ */
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index 2e06dcc..bcc9fbb 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -831,6 +831,18 @@ virNetServerHasClients(virNetServerPtr srv)
return ret;
}
+const char *
+virNetServerGetName(virNetServerPtr srv)
+{
+ const char *name;
+
+ virObjectLock(srv);
+ name = srv->name;
+ virObjectUnlock(srv);
+
+ return name;
+}
+
void
virNetServerProcessClients(virNetServerPtr srv)
{
diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h
index 60707d1..c30d622 100644
--- a/src/rpc/virnetserver.h
+++ b/src/rpc/virnetserver.h
@@ -87,4 +87,7 @@ void virNetServerUpdateServices(virNetServerPtr srv, bool enabled);
int virNetServerStart(virNetServerPtr srv);
+const char *virNetServerGetName(virNetServerPtr srv);
+unsigned int virNetServerGetID(virNetServerPtr srv);
+
#endif /* __VIR_NET_SERVER_H__ */
--
2.4.3