[libvirt] [RFCv2 PoCv1 PATCH 00/15] Just Admin API

*** BLURB *** ... Just kidding :) Sooo... After very very VERY long time, here's a draft of an admin interface that is supposed to open up new possibilities to be done on a live daemon. The aim here is to create some first inches of that API in order to open up the possibility of new API function creation to more people. I already spent so much time explaining so much of that that I don't know what else to point at in here. Maybe the fact that last three patches are just an example on how this might work. Of course there won't be any functions like listClientIDs with the need of getting each client info by another API. There's going to be e.g. virAdmClientInfo and virAdmGetClients() will return the list of them, etc. Long story short, let's not repeat past mistakes ;) With all that said, feel free to hate, love, comment or just try out compiling this series and let me know how many things I've missed and screwed up (hopefully zero). Martin Kletzander (15): util: add virJSONValueCopy util: Add virabstracts file for keeping abstract classes datatypes: Use abstract connect class in virConnect Break virNetServer into virNetSubServers Teach gendispatch how to handle admin dispatching files Add admin protocol Build client headers for admin protocol Add admin error domain Add libvirt-admin library Add XML files with admin API specification Add configuration options for permissions on daemon's admin socket Add support for admin API in libvirt daemon rpc: Add virNetSubServerGetNClients admin: Add virAdmHello function Example virt-admin .gitignore | 5 + Makefile.am | 4 +- cfg.mk | 11 +- configure.ac | 19 +- daemon/Makefile.am | 33 +- daemon/admin_server.c | 119 +++++ daemon/admin_server.h | 36 ++ daemon/libvirtd-config.c | 5 +- daemon/libvirtd-config.h | 1 + daemon/libvirtd.aug | 1 + daemon/libvirtd.c | 138 ++++-- daemon/libvirtd.conf | 8 + daemon/libvirtd.h | 14 +- daemon/remote.c | 194 ++++----- daemon/test_libvirtd.aug.in | 1 + docs/Makefile.am | 23 +- docs/apibuild.py | 10 +- include/libvirt/Makefile.am | 6 +- include/libvirt/libvirt-admin.h | 63 +++ include/libvirt/virterror.h | 3 +- libvirt-admin.pc.in | 13 + libvirt.spec.in | 10 + po/POTFILES.in | 3 + src/Makefile.am | 134 +++++- src/admin/admin_protocol.x | 73 ++++ src/admin_protocol-structs | 17 + src/datatypes.c | 39 +- src/datatypes.h | 45 +- src/internal.h | 1 + src/libvirt-admin.c | 363 ++++++++++++++++ src/libvirt-host.c | 3 +- src/libvirt_admin.syms | 19 + src/libvirt_private.syms | 6 + src/libvirt_remote.syms | 17 +- src/locking/lock_daemon.c | 40 +- src/locking/lock_daemon_dispatch.c | 18 +- src/lxc/lxc_controller.c | 18 +- src/rpc/gendispatch.pl | 141 +++--- src/rpc/virnetserver.c | 859 +++++++++++++------------------------ src/rpc/virnetserver.h | 61 +-- src/rpc/virnetserverprogram.c | 12 +- src/rpc/virnetserverprogram.h | 9 +- src/rpc/virnetsubserver.c | 672 +++++++++++++++++++++++++++++ src/rpc/virnetsubserver.h | 78 ++++ src/util/virabstracts.c | 100 +++++ src/util/virabstracts.h | 57 +++ src/util/virerror.c | 95 ++-- src/util/virerror.h | 4 +- src/util/virjson.c | 65 ++- src/util/virjson.h | 4 +- tests/confdata/libvirtd.conf | 6 + tests/confdata/libvirtd.out | 5 + tests/jsontest.c | 111 +++++ tools/virt-admin/Makefile.am | 70 +++ tools/virt-admin/virt-admin.c | 68 +++ tools/virt-admin/virt-admin.pod | 43 ++ 56 files changed, 3092 insertions(+), 881 deletions(-) create mode 100644 daemon/admin_server.c create mode 100644 daemon/admin_server.h create mode 100644 include/libvirt/libvirt-admin.h create mode 100644 libvirt-admin.pc.in create mode 100644 src/admin/admin_protocol.x create mode 100644 src/admin_protocol-structs create mode 100644 src/libvirt-admin.c create mode 100644 src/libvirt_admin.syms create mode 100644 src/rpc/virnetsubserver.c create mode 100644 src/rpc/virnetsubserver.h create mode 100644 src/util/virabstracts.c create mode 100644 src/util/virabstracts.h create mode 100644 tools/virt-admin/Makefile.am create mode 100644 tools/virt-admin/virt-admin.c create mode 100644 tools/virt-admin/virt-admin.pod -- 2.3.5

Faster version of virJSONValueFromString(virJSONValueToString()). Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virjson.c | 65 ++++++++++++++++++++++++++- src/util/virjson.h | 4 +- tests/jsontest.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index aafc385..0335313 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1573,6 +1573,7 @@ virJSONValueArrayAppend; virJSONValueArrayGet; virJSONValueArraySize; virJSONValueArraySteal; +virJSONValueCopy; virJSONValueFree; virJSONValueFromString; virJSONValueGetArrayAsBitmap; diff --git a/src/util/virjson.c b/src/util/virjson.c index c8d761f..40ec613 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -1,7 +1,7 @@ /* * virjson.c: JSON object parsing/formatting * - * Copyright (C) 2009-2010, 2012-2013 Red Hat, Inc. + * Copyright (C) 2009-2010, 2012-2015 Red Hat, Inc. * Copyright (C) 2009 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -1233,6 +1233,69 @@ virJSONValueObjectForeachKeyValue(virJSONValuePtr object, } +virJSONValuePtr +virJSONValueCopy(virJSONValuePtr in) +{ + size_t i; + virJSONValuePtr out = NULL; + + if (!in) + return NULL; + + switch ((virJSONType) in->type) { + case VIR_JSON_TYPE_OBJECT: + out = virJSONValueNewObject(); + if (!out) + return NULL; + for (i = 0; i < in->data.object.npairs; i++) { + virJSONValuePtr val = NULL; + if (!(val = virJSONValueCopy(in->data.object.pairs[i].value))) + goto error; + if (virJSONValueObjectAppend(out, in->data.object.pairs[i].key, + val) < 0) { + virJSONValueFree(val); + goto error; + } + } + break; + case VIR_JSON_TYPE_ARRAY: + out = virJSONValueNewArray(); + if (!out) + return NULL; + for (i = 0; i < in->data.array.nvalues; i++) { + virJSONValuePtr val = NULL; + if (!(val = virJSONValueCopy(in->data.array.values[i]))) + goto error; + if (virJSONValueArrayAppend(out, val) < 0) { + virJSONValueFree(val); + goto error; + } + } + break; + + /* No need to error out in the following cases */ + case VIR_JSON_TYPE_STRING: + out = virJSONValueNewString(in->data.string); + break; + case VIR_JSON_TYPE_NUMBER: + out = virJSONValueNewNumber(in->data.number); + break; + case VIR_JSON_TYPE_BOOLEAN: + out = virJSONValueNewBoolean(in->data.boolean); + break; + case VIR_JSON_TYPE_NULL: + out = virJSONValueNewNull(); + break; + } + + return out; + + error: + virJSONValueFree(out); + return NULL; +} + + #if WITH_YAJL static int virJSONParserInsertValue(virJSONParserPtr parser, diff --git a/src/util/virjson.h b/src/util/virjson.h index 9bb7461..e871b2e 100644 --- a/src/util/virjson.h +++ b/src/util/virjson.h @@ -1,7 +1,7 @@ /* * virjson.h: JSON object parsing/formatting * - * Copyright (C) 2009, 2012-2013 Red Hat, Inc. + * Copyright (C) 2009, 2012-2015 Red Hat, Inc. * Copyright (C) 2009 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -165,4 +165,6 @@ int virJSONValueObjectForeachKeyValue(virJSONValuePtr object, virJSONValueObjectIteratorFunc cb, void *opaque); +virJSONValuePtr virJSONValueCopy(virJSONValuePtr in); + #endif /* __VIR_JSON_H_ */ diff --git a/tests/jsontest.c b/tests/jsontest.c index a2a42e3..fca960f 100644 --- a/tests/jsontest.c +++ b/tests/jsontest.c @@ -131,6 +131,91 @@ testJSONAddRemove(const void *data) static int +testJSONCopy(const void *data) +{ + const struct testInfo *info = data; + virJSONValuePtr json = NULL; + virJSONValuePtr jsonCopy = NULL; + char *result = NULL; + char *resultCopy = NULL; + int ret = -1; + + json = virJSONValueFromString(info->doc); + if (!json) { + if (virTestGetVerbose()) + fprintf(stderr, "Failed to parse %s\n", info->doc); + ret = -1; + goto cleanup; + } + + jsonCopy = virJSONValueCopy(json); + if (!jsonCopy) { + if (virTestGetVerbose()) + fprintf(stderr, "Failed to copy JSON data\n"); + ret = -1; + goto cleanup; + } + + result = virJSONValueToString(json, false); + if (!result) { + if (virTestGetVerbose()) + fprintf(stderr, "Failed to format original JSON data\n"); + ret = -1; + goto cleanup; + } + + resultCopy = virJSONValueToString(json, false); + if (!resultCopy) { + if (virTestGetVerbose()) + fprintf(stderr, "Failed to format copied JSON data\n"); + ret = -1; + goto cleanup; + } + + if (STRNEQ(result, resultCopy)) { + if (virTestGetVerbose()) + virtTestDifference(stderr, result, resultCopy); + ret = -1; + goto cleanup; + } + + VIR_FREE(result); + VIR_FREE(resultCopy); + + result = virJSONValueToString(json, true); + if (!result) { + if (virTestGetVerbose()) + fprintf(stderr, "Failed to format original JSON data\n"); + ret = -1; + goto cleanup; + } + + resultCopy = virJSONValueToString(json, true); + if (!resultCopy) { + if (virTestGetVerbose()) + fprintf(stderr, "Failed to format copied JSON data\n"); + ret = -1; + goto cleanup; + } + + if (STRNEQ(result, resultCopy)) { + if (virTestGetVerbose()) + virtTestDifference(stderr, result, resultCopy); + ret = -1; + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(result); + VIR_FREE(resultCopy); + virJSONValueFree(json); + virJSONValueFree(jsonCopy); + return ret; +} + + +static int mymain(void) { int ret = 0; @@ -192,6 +277,32 @@ mymain(void) DO_TEST_FULL("add and remove", AddRemove, "[ 1 ]", NULL, false); + DO_TEST_FULL("copy and free", Copy, + "{\"return\": [{\"name\": \"quit\"}, {\"name\": \"eject\"}," + "{\"name\": \"change\"}, {\"name\": \"screendump\"}," + "{\"name\": \"stop\"}, {\"name\": \"cont\"}, {\"name\": " + "\"system_reset\"}, {\"name\": \"system_powerdown\"}, " + "{\"name\": \"device_add\"}, {\"name\": \"device_del\"}, " + "{\"name\": \"cpu\"}, {\"name\": \"memsave\"}, {\"name\": " + "\"pmemsave\"}, {\"name\": \"migrate\"}, {\"name\": " + "\"migrate_cancel\"}, {\"name\": \"migrate_set_speed\"}," + "{\"name\": \"client_migrate_info\"}, {\"name\": " + "\"migrate_set_downtime\"}, {\"name\": \"netdev_add\"}, " + "{\"name\": \"netdev_del\"}, {\"name\": \"block_resize\"}," + "{\"name\": \"balloon\"}, {\"name\": \"set_link\"}, {\"name\":" + "\"getfd\"}, {\"name\": \"closefd\"}, {\"name\": \"block_passwd\"}," + "{\"name\": \"set_password\"}, {\"name\": \"expire_password\"}," + "{\"name\": \"qmp_capabilities\"}, {\"name\": " + "\"human-monitor-command\"}, {\"name\": \"query-version\"}," + "{\"name\": \"query-commands\"}, {\"name\": \"query-chardev\"}," + "{\"name\": \"query-block\"}, {\"name\": \"query-blockstats\"}, " + "{\"name\": \"query-cpus\"}, {\"name\": \"query-pci\"}, {\"name\":" + "\"query-kvm\"}, {\"name\": \"query-status\"}, {\"name\": " + "\"query-mice\"}, {\"name\": \"query-vnc\"}, {\"name\": " + "\"query-spice\"}, {\"name\": \"query-name\"}, {\"name\": " + "\"query-uuid\"}, {\"name\": \"query-migrate\"}, {\"name\": " + "\"query-balloon\"}], \"id\": \"libvirt-2\"}", NULL, true); + DO_TEST_PARSE("almost nothing", "[]"); DO_TEST_PARSE_FAIL("nothing", ""); -- 2.3.5

The first class in this file is going to be an abstract connection class that holds a per-connection error inside. virConnect will be the first child class inheriting from this one. This is a separate file because virerror.c is going to depend on it and putting it into datatypes along with other connect classes would create a dependency on datatypes from the util library. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/Makefile.am | 3 +- src/libvirt_private.syms | 5 +++ src/util/virabstracts.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virabstracts.h | 57 +++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/util/virabstracts.c create mode 100644 src/util/virabstracts.h diff --git a/src/Makefile.am b/src/Makefile.am index 3c9eac6..5763659 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -## Copyright (C) 2005-2014 Red Hat, Inc. +## Copyright (C) 2005-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 @@ -89,6 +89,7 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ + util/virabstracts.c util/virabstracts.h \ util/viralloc.c util/viralloc.h \ util/virarch.h util/virarch.c \ util/viratomic.h util/viratomic.c \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0335313..ef5877b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1035,6 +1035,11 @@ virSecurityManagerStackAddNested; virSecurityManagerVerify; +# util/virabstracts.h +virClassForAbstractConnect; +virGetAbstractConnect; + + # util/viralloc.h virAlloc; virAllocN; diff --git a/src/util/virabstracts.c b/src/util/virabstracts.c new file mode 100644 index 0000000..f4c0829 --- /dev/null +++ b/src/util/virabstracts.c @@ -0,0 +1,100 @@ +/* + * virabstracts.c: abstract virClass definitions + * + * 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@redhat.com> + */ + +#include <config.h> + +#include "virabstracts.h" +#include "virerror.h" +#include "virlog.h" +#include "viralloc.h" +#include "viruuid.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("util"); + +virClassPtr virAbstractConnectClass; + +static void virAbstractConnectDispose(void *anyobj); + + +static int +virAbstractsOnceInit(void) +{ +#define DECLARE_CLASS(basename, parent) \ + if (!(basename ## Class = virClassNew(parent, \ + #basename, \ + sizeof(basename), \ + basename ## Dispose))) \ + return -1; + + + DECLARE_CLASS(virAbstractConnect, virClassForObjectLockable()); + + +#undef DECLARE_CLASS + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virAbstracts) + + +virClassPtr +virClassForAbstractConnect(void) +{ + if (virAbstractsInitialize() < 0) + return NULL; + + return virAbstractConnectClass; +} + + +/** + * virGetAbstractConnect: + * + * Allocates a new abstract connection object. + * + * Returns a pointer to the connection object, or NULL on error. + */ +void * +virGetAbstractConnect(virClassPtr klass) +{ + virAbstractConnectPtr ret; + + if (virAbstractsInitialize() < 0) + return NULL; + + if (!(ret = virObjectLockableNew(klass))) + return NULL; + + return ret; +} + + +static void +virAbstractConnectDispose(void *anyobj) +{ + virAbstractConnectPtr obj = anyobj; + + virResetError(&obj->err); +} diff --git a/src/util/virabstracts.h b/src/util/virabstracts.h new file mode 100644 index 0000000..4d12862 --- /dev/null +++ b/src/util/virabstracts.h @@ -0,0 +1,57 @@ +/* + * virabstracts.h: abstract virClass definitions + * + * 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@redhat.com> + */ + +#ifndef __VIR_ABSTRACTS_H_ +# define __VIR_ABSTRACTS_H_ + +# include "internal.h" +# include "virerror.h" +# include "virobject.h" + +virClassPtr virClassForAbstractConnect(void); + +void *virGetAbstractConnect(virClassPtr klass); + +typedef struct _virAbstractConnect virAbstractConnect; +typedef virAbstractConnect *virAbstractConnectPtr; + +/** + * _virAbstractConnect: + * + * Internal structure associated to a connection + */ +struct _virAbstractConnect { + virObjectLockable parent; + + /* + * Object lock must be acquired before accessing/changing any of + * members following this point, or changing the ref count of any + * virDomain/virNetwork object associated with this connection. + */ + + /* Per-connection error. */ + virError err; /* the last error */ + virErrorFunc handler; /* associated handlet */ + void *userData; /* the user data */ +}; + +#endif /* __VIR_ABSTRACTS_H__ */ -- 2.3.5

On Thu, Apr 16, 2015 at 04:46:37PM +0200, Martin Kletzander wrote:
The first class in this file is going to be an abstract connection class that holds a per-connection error inside. virConnect will be the first child class inheriting from this one.
This is a separate file because virerror.c is going to depend on it and putting it into datatypes along with other connect classes would create a dependency on datatypes from the util library.
So I can understand why you are doing this - you'll have the admin connection also inherit from this later, but....
+struct _virAbstractConnect { + virObjectLockable parent; + + /* + * Object lock must be acquired before accessing/changing any of + * members following this point, or changing the ref count of any + * virDomain/virNetwork object associated with this connection. + */ + + /* Per-connection error. */ + virError err; /* the last error */ + virErrorFunc handler; /* associated handlet */ + void *userData; /* the user data */
These fields are really legacy stuff that we no longer encourage the use of. These dated from before the time that we have thread-local error objects, and they cannot ever be safely accessed when using the virConnect in a multi-threaded context. So, if we're creating a new admin connection object, I'd really suggest we don't want to have these connection level error objects. Just mandate use of the thread-local errors for the admin connection IIUC, removing these error objects, would really kill the need for this virAbstractConnect class, as the admin connection could just inherit from virObjectLockable. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Fri, Apr 17, 2015 at 11:16:49AM +0100, Daniel P. Berrange wrote:
On Thu, Apr 16, 2015 at 04:46:37PM +0200, Martin Kletzander wrote:
The first class in this file is going to be an abstract connection class that holds a per-connection error inside. virConnect will be the first child class inheriting from this one.
This is a separate file because virerror.c is going to depend on it and putting it into datatypes along with other connect classes would create a dependency on datatypes from the util library.
So I can understand why you are doing this - you'll have the admin connection also inherit from this later, but....
+struct _virAbstractConnect { + virObjectLockable parent; + + /* + * Object lock must be acquired before accessing/changing any of + * members following this point, or changing the ref count of any + * virDomain/virNetwork object associated with this connection. + */ + + /* Per-connection error. */ + virError err; /* the last error */ + virErrorFunc handler; /* associated handlet */ + void *userData; /* the user data */
These fields are really legacy stuff that we no longer encourage the use of. These dated from before the time that we have thread-local error objects, and they cannot ever be safely accessed when using the virConnect in a multi-threaded context.
So, if we're creating a new admin connection object, I'd really suggest we don't want to have these connection level error objects. Just mandate use of the thread-local errors for the admin connection
IIUC, removing these error objects, would really kill the need for this virAbstractConnect class, as the admin connection could just inherit from virObjectLockable.
Yes, I wanted to dispatch errors on connections and just haven't realized it's not needed. Dropping two patches and changing four lines fixed this and it Just Works.

On 16.04.2015 16:46, Martin Kletzander wrote:
The first class in this file is going to be an abstract connection class that holds a per-connection error inside. virConnect will be the first child class inheriting from this one.
This is a separate file because virerror.c is going to depend on it and putting it into datatypes along with other connect classes would create a dependency on datatypes from the util library.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/Makefile.am | 3 +- src/libvirt_private.syms | 5 +++ src/util/virabstracts.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virabstracts.h | 57 +++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/util/virabstracts.c create mode 100644 src/util/virabstracts.h
You need to squash this in: diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index cd1e2df..9592de7 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -410,7 +410,7 @@ xenInotifyOpen(virConnectPtr conn, VIR_DEBUG("Building initial config cache"); if (priv->useXenConfigCache && xenXMConfigCacheRefresh(conn) < 0) { - VIR_DEBUG("Failed to enable XM config cache %s", conn->err.message); + VIR_DEBUG("Failed to enable XM config cache %s", conn->parent.err.message); return -1; } Michal

On Tue, Apr 21, 2015 at 06:41:36PM +0200, Michal Privoznik wrote:
On 16.04.2015 16:46, Martin Kletzander wrote:
The first class in this file is going to be an abstract connection class that holds a per-connection error inside. virConnect will be the first child class inheriting from this one.
This is a separate file because virerror.c is going to depend on it and putting it into datatypes along with other connect classes would create a dependency on datatypes from the util library.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/Makefile.am | 3 +- src/libvirt_private.syms | 5 +++ src/util/virabstracts.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virabstracts.h | 57 +++++++++++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/util/virabstracts.c create mode 100644 src/util/virabstracts.h
You need to squash this in:
Not really, this patch is removed from the series as there is no need for it. But thanks a lot for having a look ;)
diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c index cd1e2df..9592de7 100644 --- a/src/xen/xen_inotify.c +++ b/src/xen/xen_inotify.c @@ -410,7 +410,7 @@ xenInotifyOpen(virConnectPtr conn, VIR_DEBUG("Building initial config cache"); if (priv->useXenConfigCache && xenXMConfigCacheRefresh(conn) < 0) { - VIR_DEBUG("Failed to enable XM config cache %s", conn->err.message); + VIR_DEBUG("Failed to enable XM config cache %s", conn->parent.err.message); return -1; }
Michal

Make virConnectClass be a child of virAbstractConnectClass and adapt all error handling functions to that. This will allow us to create new connect classes that will just work with our error reporting. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/Makefile.am | 1 + src/datatypes.c | 9 ++--- src/datatypes.h | 8 ++--- src/libvirt-host.c | 3 +- src/util/virerror.c | 94 +++++++++++++++++++++++++++++++++++++++-------------- src/util/virerror.h | 4 +-- 6 files changed, 81 insertions(+), 38 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5763659..6d1b4fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2122,6 +2122,7 @@ if WITH_LXC noinst_LTLIBRARIES += libvirt-setuid-rpc-client.la libvirt_setuid_rpc_client_la_SOURCES = \ + util/virabstracts.c \ util/viralloc.c \ util/viratomic.c \ util/viratomic.h \ diff --git a/src/datatypes.c b/src/datatypes.c index 39f83d9..b21113e 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -72,8 +72,10 @@ virDataTypesOnceInit(void) DECLARE_CLASS_COMMON(basename, virClassForObject()) #define DECLARE_CLASS_LOCKABLE(basename) \ DECLARE_CLASS_COMMON(basename, virClassForObjectLockable()) +#define DECLARE_CLASS_CONNECT(basename) \ + DECLARE_CLASS_COMMON(basename, virClassForAbstractConnect()) - DECLARE_CLASS_LOCKABLE(virConnect); + DECLARE_CLASS_CONNECT(virConnect); DECLARE_CLASS_LOCKABLE(virConnectCloseCallbackData); DECLARE_CLASS(virDomain); DECLARE_CLASS(virDomainSnapshot); @@ -88,6 +90,7 @@ virDataTypesOnceInit(void) #undef DECLARE_CLASS_COMMON #undef DECLARE_CLASS_LOCKABLE +#undef DECLARE_CLASS_CONNECT #undef DECLARE_CLASS return 0; @@ -110,7 +113,7 @@ virGetConnect(void) if (virDataTypesInitialize() < 0) return NULL; - if (!(ret = virObjectLockableNew(virConnectClass))) + if (!(ret = virGetAbstractConnect(virConnectClass))) return NULL; if (!(ret->closeCallback = virObjectLockableNew(virConnectCloseCallbackDataClass))) @@ -138,8 +141,6 @@ virConnectDispose(void *obj) if (conn->driver) conn->driver->connectClose(conn); - virResetError(&conn->err); - virURIFree(conn->uri); if (conn->closeCallback) { diff --git a/src/datatypes.h b/src/datatypes.h index f1d01d5..9f95811 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -25,6 +25,7 @@ # include "internal.h" # include "driver.h" +# include "virabstracts.h" # include "virthread.h" # include "virobject.h" # include "viruuid.h" @@ -328,7 +329,7 @@ struct _virConnectCloseCallbackData { * Internal structure associated to a connection */ struct _virConnect { - virObjectLockable object; + virAbstractConnect parent; /* All the variables from here, until declared otherwise in one of * the following comments, are setup at time of connection open @@ -359,11 +360,6 @@ struct _virConnect { * virDomain/virNetwork object associated with this connection. */ - /* Per-connection error. */ - virError err; /* the last error */ - virErrorFunc handler; /* associated handlet */ - void *userData; /* the user data */ - /* Per-connection close callback */ virConnectCloseCallbackDataPtr closeCallback; }; diff --git a/src/libvirt-host.c b/src/libvirt-host.c index 03bee1f..74d9bef 100644 --- a/src/libvirt-host.c +++ b/src/libvirt-host.c @@ -51,7 +51,8 @@ VIR_LOG_INIT("libvirt.host"); int virConnectRef(virConnectPtr conn) { - VIR_DEBUG("conn=%p refs=%d", conn, conn ? conn->object.parent.u.s.refs : 0); + VIR_DEBUG("conn=%p refs=%d", conn, + conn ? conn->parent.parent.parent.u.s.refs : 0); virResetLastError(); diff --git a/src/util/virerror.c b/src/util/virerror.c index 73dae95..8696e31 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -27,6 +27,7 @@ #include <string.h> #include <stdarg.h> +#include "virabstracts.h" #include "virerror.h" #include "datatypes.h" #include "virlog.h" @@ -421,9 +422,10 @@ virResetLastError(void) virErrorPtr virConnGetLastError(virConnectPtr conn) { - if (conn == NULL) + if (!conn) return NULL; - return &conn->err; + + return &conn->parent.err; } /** @@ -458,17 +460,38 @@ virConnCopyLastError(virConnectPtr conn, virErrorPtr to) /* We can't guarantee caller has initialized it to zero */ memset(to, 0, sizeof(*to)); - if (conn == NULL) + if (!conn) return -1; + virObjectLock(conn); - if (conn->err.code == VIR_ERR_OK) + if (conn->parent.err.code == VIR_ERR_OK) virResetError(to); else - virCopyError(&conn->err, to); + virCopyError(&conn->parent.err, to); virObjectUnlock(conn); return to->code; } +static void +virAdmConnResetLastError(void *anyobj) +{ + virAbstractConnectPtr obj = anyobj; + + if (!virObjectIsClass(obj, virClassForAbstractConnect())) { + VIR_WARN("Object %p (%s) is not a virObjectLockable instance", + obj, + obj ? virClassName(obj->parent.parent.klass) : "(unknown)"); + return; + } + + if (!obj) + return; + + virObjectLock(obj); + virResetError(&obj->err); + virObjectUnlock(obj); +} + /** * virConnResetLastError: * @conn: pointer to the hypervisor connection @@ -481,11 +504,7 @@ virConnCopyLastError(virConnectPtr conn, virErrorPtr to) void virConnResetLastError(virConnectPtr conn) { - if (conn == NULL) - return; - virObjectLock(conn); - virResetError(&conn->err); - virObjectUnlock(conn); + virAdmConnResetLastError(conn); } /** @@ -504,6 +523,28 @@ virSetErrorFunc(void *userData, virErrorFunc handler) virUserData = userData; } +static void +virAbsConnSetErrorFunc(void *anyobj, void *userData, + virErrorFunc handler) +{ + virAbstractConnectPtr obj = anyobj; + + if (!virObjectIsClass(obj, virClassForAbstractConnect())) { + VIR_WARN("Object %p (%s) is not a virObjectLockable instance", + obj, + obj ? virClassName(obj->parent.parent.klass) : "(unknown)"); + return; + } + + if (!obj) + return; + + virObjectLock(obj); + obj->handler = handler; + obj->userData = userData; + virObjectUnlock(obj); +} + /** * virConnSetErrorFunc: * @conn: pointer to the hypervisor connection @@ -518,12 +559,7 @@ void virConnSetErrorFunc(virConnectPtr conn, void *userData, virErrorFunc handler) { - if (conn == NULL) - return; - virObjectLock(conn); - conn->handler = handler; - conn->userData = userData; - virObjectUnlock(conn); + virAbsConnSetErrorFunc(conn, userData, handler); } /** @@ -574,7 +610,7 @@ virDefaultErrorFunc(virErrorPtr err) /** * virDispatchError: - * @conn: pointer to the hypervisor connection + * @anyobj: pointer to connection (be it admin or hypervisor one) * * Internal helper to do final stage of error * reporting in public APIs. @@ -584,11 +620,19 @@ virDefaultErrorFunc(virErrorPtr err) * - Invoke the error callback functions */ void -virDispatchError(virConnectPtr conn) +virDispatchError(void *anyobj) { virErrorPtr err = virLastErrorObject(); virErrorFunc handler = virErrorHandler; void *userData = virUserData; + virAbstractConnectPtr obj = anyobj; + + if (obj && !virObjectIsClass(obj, virClassForAbstractConnect())) { + VIR_WARN("Object %p (%s) is not a virObjectLockable instance", + obj, + obj ? virClassName(obj->parent.parent.klass) : "(unknown)"); + return; + } /* Can only happen on OOM. */ if (!err) @@ -599,15 +643,15 @@ virDispatchError(virConnectPtr conn) virErrorGenericFailure(err); /* Copy the global error to per-connection error if needed */ - if (conn) { - virObjectLock(conn); - virCopyError(err, &conn->err); + if (obj) { + virObjectLock(obj); + virCopyError(err, &obj->err); - if (conn->handler != NULL) { - handler = conn->handler; - userData = conn->userData; + if (obj->handler != NULL) { + handler = obj->handler; + userData = obj->userData; } - virObjectUnlock(conn); + virObjectUnlock(obj); } /* Invoke the error callback functions */ diff --git a/src/util/virerror.h b/src/util/virerror.h index ad3a946..ccaff12 100644 --- a/src/util/virerror.h +++ b/src/util/virerror.h @@ -1,7 +1,7 @@ /* * virerror.h: error handling and reporting code for libvirt * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-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 @@ -174,7 +174,7 @@ void virReportOOMErrorFull(int domcode, virRaiseErrorObject(__FILE__, __FUNCTION__, __LINE__, obj) int virSetError(virErrorPtr newerr); -void virDispatchError(virConnectPtr conn); +void virDispatchError(void *anyobj); const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen); typedef int (*virErrorLogPriorityFunc)(virErrorPtr, int); -- 2.3.5

Each subserver has its own RPC programs, services, workers, keepalive, clients etc. Hence (possible) multiple subservers are properly separated. The part in remote.c is just mechanical, the same applies to most of the code movement from virnetserver.c to virnetsubserver.c. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- daemon/libvirtd.c | 47 +- daemon/remote.c | 194 ++++----- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_remote.syms | 16 +- src/locking/lock_daemon.c | 40 +- src/locking/lock_daemon_dispatch.c | 18 +- src/lxc/lxc_controller.c | 18 +- src/rpc/gendispatch.pl | 13 +- src/rpc/virnetserver.c | 859 +++++++++++++------------------------ src/rpc/virnetserver.h | 61 +-- src/rpc/virnetserverprogram.c | 12 +- src/rpc/virnetserverprogram.h | 9 +- src/rpc/virnetsubserver.c | 662 ++++++++++++++++++++++++++++ src/rpc/virnetsubserver.h | 76 ++++ 15 files changed, 1263 insertions(+), 764 deletions(-) create mode 100644 src/rpc/virnetsubserver.c create mode 100644 src/rpc/virnetsubserver.h diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 107b88d..e209e93 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1,7 +1,7 @@ /* * libvirtd.c: daemon start of day, guest process & i/o management * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -492,14 +492,14 @@ daemonSetupNetworking(virNetServerPtr srv, goto error; } - if (virNetServerAddService(srv, svc, + if (virNetServerAddService(srv, 0, svc, config->mdns_adv && !ipsock ? "_libvirt._tcp" : NULL) < 0) goto error; if (svcRO && - virNetServerAddService(srv, svcRO, NULL) < 0) + virNetServerAddService(srv, 0, svcRO, NULL) < 0) goto error; if (ipsock) { @@ -517,7 +517,7 @@ daemonSetupNetworking(virNetServerPtr srv, config->max_client_requests))) goto error; - if (virNetServerAddService(srv, svcTCP, + if (virNetServerAddService(srv, 0, svcTCP, config->mdns_adv ? "_libvirt._tcp" : NULL) < 0) goto error; } @@ -559,7 +559,7 @@ daemonSetupNetworking(virNetServerPtr srv, virObjectUnref(ctxt); goto error; } - if (virNetServerAddService(srv, svcTLS, + if (virNetServerAddService(srv, 0, svcTLS, config->mdns_adv && !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0) goto error; @@ -1334,19 +1334,24 @@ int main(int argc, char **argv) { goto cleanup; } - if (!(srv = virNetServerNew(config->min_workers, - config->max_workers, - config->prio_workers, - config->max_clients, - config->max_anonymous_clients, - config->keepalive_interval, - config->keepalive_count, - !!config->keepalive_required, - config->mdns_adv ? config->mdns_name : NULL, - remoteClientInitHook, - NULL, - remoteClientFreeFunc, - NULL))) { + if (!(srv = virNetServerNew(config->mdns_adv ? config->mdns_name : NULL))) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + + if (virNetServerAddSubServer(srv, + config->min_workers, + config->max_workers, + config->prio_workers, + config->max_clients, + config->max_anonymous_clients, + config->keepalive_interval, + config->keepalive_count, + !!config->keepalive_required, + remoteClientInitHook, + NULL, + remoteClientFreeFunc, + NULL) < 0) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } @@ -1374,7 +1379,7 @@ int main(int argc, char **argv) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } - if (virNetServerAddProgram(srv, remoteProgram) < 0) { + if (virNetServerAddProgram(srv, 0, remoteProgram) < 0) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } @@ -1386,7 +1391,7 @@ int main(int argc, char **argv) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } - if (virNetServerAddProgram(srv, lxcProgram) < 0) { + if (virNetServerAddProgram(srv, 0, lxcProgram) < 0) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } @@ -1398,7 +1403,7 @@ int main(int argc, char **argv) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } - if (virNetServerAddProgram(srv, qemuProgram) < 0) { + if (virNetServerAddProgram(srv, 0, qemuProgram) < 0) { ret = VIR_DAEMON_ERR_INIT; goto cleanup; } diff --git a/daemon/remote.c b/daemon/remote.c index 3a3f168..41d75cc 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1290,7 +1290,7 @@ void *remoteClientInitHook(virNetServerClientPtr client, /*----- Functions. -----*/ static int -remoteDispatchConnectOpen(virNetServerPtr server, +remoteDispatchConnectOpen(virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1309,7 +1309,8 @@ remoteDispatchConnectOpen(virNetServerPtr server, goto cleanup; } - if (virNetServerKeepAliveRequired(server) && !priv->keepalive_supported) { + if (virNetSubServerKeepAliveRequired(subserver) && + !priv->keepalive_supported) { virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("keepalive support is required to connect")); goto cleanup; @@ -1343,7 +1344,7 @@ remoteDispatchConnectOpen(virNetServerPtr server, static int -remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectClose(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED) @@ -1354,7 +1355,7 @@ remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetSchedulerType(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1548,7 +1549,7 @@ remoteDeserializeTypedParameters(remote_typed_param *args_params_val, } static int -remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetSchedulerParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1598,7 +1599,7 @@ remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUS } static int -remoteDispatchConnectListAllDomains(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectListAllDomains(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1656,7 +1657,7 @@ remoteDispatchConnectListAllDomains(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetSchedulerParametersFlags(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1707,7 +1708,7 @@ remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE } static int -remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMemoryStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1765,7 +1766,7 @@ remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainBlockPeek(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1819,7 +1820,7 @@ remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainBlockStatsFlags(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1882,7 +1883,7 @@ remoteDispatchDomainBlockStatsFlags(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMemoryPeek(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1934,7 +1935,7 @@ remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetSecurityLabel(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -1978,7 +1979,7 @@ remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetSecurityLabelList(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2037,7 +2038,7 @@ remoteDispatchDomainGetSecurityLabelList(virNetServerPtr server ATTRIBUTE_UNUSED } static int -remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeGetSecurityModel(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2076,7 +2077,7 @@ remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetVcpuPinInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2141,7 +2142,7 @@ remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainPinEmulator(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainPinEmulator(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2177,7 +2178,7 @@ remoteDispatchDomainPinEmulator(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetEmulatorPinInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2226,7 +2227,7 @@ remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetVcpus(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2307,7 +2308,7 @@ remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetIOThreadInfo(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetIOThreadInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2379,7 +2380,7 @@ remoteDispatchDomainGetIOThreadInfo(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigratePrepare(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2434,7 +2435,7 @@ remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigratePrepare2(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2486,7 +2487,7 @@ remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetMemoryParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2548,7 +2549,7 @@ remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetNumaParameters(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetNumaParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2610,7 +2611,7 @@ remoteDispatchDomainGetNumaParameters(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetBlkioParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2672,7 +2673,7 @@ remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeGetCPUStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2744,7 +2745,7 @@ remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeGetMemoryStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2816,7 +2817,7 @@ remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetBlockJobInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2856,7 +2857,7 @@ remoteDispatchDomainGetBlockJobInfo(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetBlockIoTune(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetBlockIoTune(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr hdr ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2920,7 +2921,7 @@ remoteDispatchDomainGetBlockIoTune(virNetServerPtr server ATTRIBUTE_UNUSED, /*-------------------------------------------------------------*/ static int -remoteDispatchAuthList(virNetServerPtr server, +remoteDispatchAuthList(virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -2950,7 +2951,7 @@ remoteDispatchAuthList(virNetServerPtr server, goto cleanup; VIR_INFO("Bypass polkit auth for privileged client %s", ident); virNetServerClientSetAuth(client, 0); - virNetServerTrackCompletedAuth(server); + virNetSubServerTrackCompletedAuth(subserver); auth = VIR_NET_SERVER_SERVICE_AUTH_NONE; VIR_FREE(ident); } @@ -2989,7 +2990,7 @@ remoteDispatchAuthList(virNetServerPtr server, * and gives the client a list of allowed mechanisms to choose */ static int -remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchAuthSaslInit(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3066,7 +3067,7 @@ remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED, * Returns 0 if ok, -1 on error, -2 if rejected */ static int -remoteSASLFinish(virNetServerPtr server, +remoteSASLFinish(virNetSubServerPtr subserver, virNetServerClientPtr client) { const char *identity; @@ -3092,7 +3093,7 @@ remoteSASLFinish(virNetServerPtr server, return -2; virNetServerClientSetAuth(client, 0); - virNetServerTrackCompletedAuth(server); + virNetSubServerTrackCompletedAuth(subserver); virNetServerClientSetSASLSession(client, priv->sasl); VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client)); @@ -3114,7 +3115,7 @@ remoteSASLFinish(virNetServerPtr server, * This starts the SASL authentication negotiation. */ static int -remoteDispatchAuthSaslStart(virNetServerPtr server, +remoteDispatchAuthSaslStart(virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3172,7 +3173,7 @@ remoteDispatchAuthSaslStart(virNetServerPtr server, ret->complete = 0; } else { /* Check username whitelist ACL */ - if ((err = remoteSASLFinish(server, client)) < 0) { + if ((err = remoteSASLFinish(subserver, client)) < 0) { if (err == -2) goto authdeny; else @@ -3212,7 +3213,7 @@ remoteDispatchAuthSaslStart(virNetServerPtr server, static int -remoteDispatchAuthSaslStep(virNetServerPtr server, +remoteDispatchAuthSaslStep(virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3270,7 +3271,7 @@ remoteDispatchAuthSaslStep(virNetServerPtr server, ret->complete = 0; } else { /* Check username whitelist ACL */ - if ((err = remoteSASLFinish(server, client)) < 0) { + if ((err = remoteSASLFinish(subserver, client)) < 0) { if (err == -2) goto authdeny; else @@ -3309,7 +3310,7 @@ remoteDispatchAuthSaslStep(virNetServerPtr server, } #else static int -remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchAuthSaslInit(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3322,7 +3323,7 @@ remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED, return -1; } static int -remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchAuthSaslStart(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3336,7 +3337,7 @@ remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED, return -1; } static int -remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchAuthSaslStep(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3354,7 +3355,7 @@ remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchAuthPolkit(virNetServerPtr server, +remoteDispatchAuthPolkit(virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3414,7 +3415,7 @@ remoteDispatchAuthPolkit(virNetServerPtr server, ret->complete = 1; virNetServerClientSetAuth(client, 0); - virNetServerTrackCompletedAuth(server); + virNetSubServerTrackCompletedAuth(subserver); virMutexUnlock(&priv->lock); return 0; @@ -3437,13 +3438,12 @@ remoteDispatchAuthPolkit(virNetServerPtr server, goto error; } - /*************************************************************** * NODE INFO APIS **************************************************************/ static int -remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeDeviceGetParent(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3494,7 +3494,7 @@ remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED, * Register / deregister events ***************************/ static int -remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectDomainEventRegister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -3557,7 +3557,7 @@ remoteDispatchConnectDomainEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED } static int -remoteDispatchConnectDomainEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectDomainEventDeregister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -3642,7 +3642,7 @@ remoteDispatchObjectEventSend(virNetServerClientPtr client, } static int -remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchSecretGetValue(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3680,7 +3680,7 @@ remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetState(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -3719,7 +3719,7 @@ remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED, * VIR_DRV_SUPPORTS_FEATURE(VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK), * and must not mix the two styles. */ static int -remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectDomainEventRegisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -3793,7 +3793,7 @@ remoteDispatchConnectDomainEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNU static int -remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectDomainEventCallbackRegisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -3870,7 +3870,7 @@ remoteDispatchConnectDomainEventCallbackRegisterAny(virNetServerPtr server ATTRI static int -remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectDomainEventDeregisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -3928,7 +3928,7 @@ remoteDispatchConnectDomainEventDeregisterAny(virNetServerPtr server ATTRIBUTE_U static int -remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -3974,7 +3974,7 @@ remoteDispatchConnectDomainEventCallbackDeregisterAny(virNetServerPtr server ATT static int -qemuDispatchDomainMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED, +qemuDispatchDomainMonitorCommand(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4009,7 +4009,7 @@ qemuDispatchDomainMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigrateBegin3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4060,7 +4060,7 @@ remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigratePrepare3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4116,7 +4116,7 @@ remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigratePerform3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4171,7 +4171,7 @@ remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigrateFinish3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4224,7 +4224,7 @@ remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigrateConfirm3(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4259,7 +4259,7 @@ remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED, } -static int remoteDispatchConnectSupportsFeature(virNetServerPtr server ATTRIBUTE_UNUSED, +static int remoteDispatchConnectSupportsFeature(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4310,7 +4310,7 @@ static int remoteDispatchConnectSupportsFeature(virNetServerPtr server ATTRIBUTE static int -remoteDispatchDomainOpenGraphics(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainOpenGraphics(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg, virNetMessageErrorPtr rerr, @@ -4351,7 +4351,7 @@ remoteDispatchDomainOpenGraphics(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainOpenGraphicsFd(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainOpenGraphicsFd(virNetSubServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg, virNetMessageErrorPtr rerr, @@ -4394,7 +4394,7 @@ remoteDispatchDomainOpenGraphicsFd(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetInterfaceParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4457,7 +4457,7 @@ remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server ATTRIBUTE_UNUS } static int -remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetCPUStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr hdr ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4528,7 +4528,7 @@ remoteDispatchDomainGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetDiskErrors(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4588,7 +4588,7 @@ remoteDispatchDomainGetDiskErrors(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainListAllSnapshots(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainListAllSnapshots(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4651,7 +4651,7 @@ remoteDispatchDomainListAllSnapshots(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSnapshotListAllChildren(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainSnapshotListAllChildren(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4719,7 +4719,7 @@ remoteDispatchDomainSnapshotListAllChildren(virNetServerPtr server ATTRIBUTE_UNU } static int -remoteDispatchConnectListAllStoragePools(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectListAllStoragePools(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4777,7 +4777,7 @@ remoteDispatchConnectListAllStoragePools(virNetServerPtr server ATTRIBUTE_UNUSED } static int -remoteDispatchStoragePoolListAllVolumes(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchStoragePoolListAllVolumes(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4840,7 +4840,7 @@ remoteDispatchStoragePoolListAllVolumes(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchConnectListAllNetworks(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectListAllNetworks(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4898,7 +4898,7 @@ remoteDispatchConnectListAllNetworks(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchConnectListAllInterfaces(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectListAllInterfaces(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -4956,7 +4956,7 @@ remoteDispatchConnectListAllInterfaces(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchConnectListAllNodeDevices(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectListAllNodeDevices(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5014,7 +5014,7 @@ remoteDispatchConnectListAllNodeDevices(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchConnectListAllNWFilters(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectListAllNWFilters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5072,7 +5072,7 @@ remoteDispatchConnectListAllNWFilters(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchConnectListAllSecrets(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectListAllSecrets(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5130,7 +5130,7 @@ remoteDispatchConnectListAllSecrets(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeGetMemoryParameters(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5187,7 +5187,7 @@ remoteDispatchNodeGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchNodeGetCPUMap(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeGetCPUMap(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5234,7 +5234,7 @@ remoteDispatchNodeGetCPUMap(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED, +lxcDispatchDomainOpenNamespace(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5284,7 +5284,7 @@ lxcDispatchDomainOpenNamespace(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetJobStats(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetJobStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5334,7 +5334,7 @@ remoteDispatchDomainGetJobStats(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigrateBegin3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5391,7 +5391,7 @@ remoteDispatchDomainMigrateBegin3Params(virNetServerPtr server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigratePrepare3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5451,7 +5451,7 @@ remoteDispatchDomainMigratePrepare3Params(virNetServerPtr server ATTRIBUTE_UNUSE } static int -remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigratePrepareTunnel3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg, virNetMessageErrorPtr rerr, @@ -5521,7 +5521,7 @@ remoteDispatchDomainMigratePrepareTunnel3Params(virNetServerPtr server ATTRIBUTE static int -remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigratePerform3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5582,7 +5582,7 @@ remoteDispatchDomainMigratePerform3Params(virNetServerPtr server ATTRIBUTE_UNUSE static int -remoteDispatchDomainMigrateFinish3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigrateFinish3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5642,7 +5642,7 @@ remoteDispatchDomainMigrateFinish3Params(virNetServerPtr server ATTRIBUTE_UNUSED static int -remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainMigrateConfirm3Params(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5693,7 +5693,7 @@ remoteDispatchDomainMigrateConfirm3Params(virNetServerPtr server ATTRIBUTE_UNUSE static int -remoteDispatchConnectGetCPUModelNames(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectGetCPUModelNames(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5745,7 +5745,7 @@ remoteDispatchConnectGetCPUModelNames(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainCreateXMLWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainCreateXMLWithFiles(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5792,7 +5792,7 @@ remoteDispatchDomainCreateXMLWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED, } -static int remoteDispatchDomainCreateWithFiles(virNetServerPtr server ATTRIBUTE_UNUSED, +static int remoteDispatchDomainCreateWithFiles(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -5843,7 +5843,7 @@ static int remoteDispatchDomainCreateWithFiles(virNetServerPtr server ATTRIBUTE_ static int -remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectNetworkEventRegisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -5920,7 +5920,7 @@ remoteDispatchConnectNetworkEventRegisterAny(virNetServerPtr server ATTRIBUTE_UN static int -remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectNetworkEventDeregisterAny(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -5966,7 +5966,7 @@ remoteDispatchConnectNetworkEventDeregisterAny(virNetServerPtr server ATTRIBUTE_ static int -qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED, +qemuDispatchConnectDomainMonitorEventRegister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -6038,7 +6038,7 @@ qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_U static int -qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE_UNUSED, +qemuDispatchConnectDomainMonitorEventDeregister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED, @@ -6084,7 +6084,7 @@ qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE } static int -remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetTime(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -6122,7 +6122,7 @@ remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeGetFreePages(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeGetFreePages(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -6235,7 +6235,7 @@ remoteSerializeDHCPLease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLea static int -remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNetworkGetDHCPLeases(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -6303,7 +6303,7 @@ remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchConnectGetAllDomainStats(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -6389,7 +6389,7 @@ remoteDispatchConnectGetAllDomainStats(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeAllocPages(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchNodeAllocPages(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -6426,7 +6426,7 @@ remoteDispatchNodeAllocPages(virNetServerPtr server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainGetFSInfo(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainGetFSInfo(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -6620,7 +6620,7 @@ remoteSerializeDomainInterface(virDomainInterfacePtr *ifaces, static int -remoteDispatchDomainInterfaceAddresses(virNetServerPtr server ATTRIBUTE_UNUSED, +remoteDispatchDomainInterfaceAddresses(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, diff --git a/po/POTFILES.in b/po/POTFILES.in index dd06ab3..af07e09 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -140,6 +140,7 @@ src/rpc/virnetservermdns.c src/rpc/virnetserverprogram.c src/rpc/virnetserverservice.c src/rpc/virnetsshsession.c +src/rpc/virnetsubserver.c src/rpc/virnettlscontext.c src/secret/secret_driver.c src/security/security_apparmor.c diff --git a/src/Makefile.am b/src/Makefile.am index 6d1b4fb..d6245bd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2487,6 +2487,7 @@ libvirt_net_rpc_server_la_SOURCES = \ rpc/virnetserverservice.h rpc/virnetserverservice.c \ rpc/virnetserverclient.h rpc/virnetserverclient.c \ rpc/virnetservermdns.h rpc/virnetservermdns.c \ + rpc/virnetsubserver.h rpc/virnetsubserver.c \ rpc/virnetserver.h rpc/virnetserver.c libvirt_net_rpc_server_la_CFLAGS = \ $(AVAHI_CFLAGS) \ diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms index 6b520b5..f7cf226 100644 --- a/src/libvirt_remote.syms +++ b/src/libvirt_remote.syms @@ -83,8 +83,8 @@ virNetServerAddShutdownInhibition; virNetServerAddSignalHandler; virNetServerAutoShutdown; virNetServerClose; +virNetServerGetSubServer; virNetServerIsPrivileged; -virNetServerKeepAliveRequired; virNetServerNew; virNetServerNewPostExecRestart; virNetServerPreExecRestart; @@ -205,6 +205,20 @@ virNetSocketUpdateIOCallback; virNetSocketWrite; +# rpc/virnetsubserver.h +virNetSubServerAddProgram; +virNetSubServerAddService; +virNetSubServerClose; +virNetSubServerHasClients; +virNetSubServerKeepAliveRequired; +virNetSubServerNew; +virNetSubServerPreExecRestart; +virNetSubServerProcessClients; +virNetSubServerTrackCompletedAuth; +virNetSubServerTrackPendingAuth; +virNetSubServerUpdateServices; + + # Let emacs know we want case-insensitive sorting # Local Variables: # sort-fold-case: t diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c index bb165c0..b3c5873 100644 --- a/src/locking/lock_daemon.c +++ b/src/locking/lock_daemon.c @@ -146,13 +146,17 @@ virLockDaemonNew(virLockDaemonConfigPtr config, bool privileged) return NULL; } - if (!(lockd->srv = virNetServerNew(1, 1, 0, config->max_clients, - config->max_clients, -1, 0, - false, NULL, - virLockDaemonClientNew, - virLockDaemonClientPreExecRestart, - virLockDaemonClientFree, - (void*)(intptr_t)(privileged ? 0x1 : 0x0)))) + if (!(lockd->srv = virNetServerNew(NULL))) + goto error; + + if (virNetServerAddSubServer(lockd->srv, 1, 1, 0, + config->max_clients, + config->max_clients, + -1, 0, false, + virLockDaemonClientNew, + virLockDaemonClientPreExecRestart, + virLockDaemonClientFree, + (void*)(intptr_t)(privileged ? 0x1 : 0x0)) < 0) goto error; if (!(lockd->lockspaces = virHashCreate(VIR_LOCK_DAEMON_NUM_LOCKSPACES, @@ -236,14 +240,18 @@ virLockDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged) goto error; } - if (!(lockd->srv = virNetServerNewPostExecRestart(child, - virLockDaemonClientNew, - virLockDaemonClientNewPostExecRestart, - virLockDaemonClientPreExecRestart, - virLockDaemonClientFree, - (void*)(intptr_t)(privileged ? 0x1 : 0x0)))) + if (!(lockd->srv = virNetServerNewPostExecRestart(child))) goto error; + if (virNetServerAddSubServerPostExec(lockd->srv, + virLockDaemonClientNew, + virLockDaemonClientNewPostExecRestart, + virLockDaemonClientPreExecRestart, + virLockDaemonClientFree, + (void*)(intptr_t)(privileged ? 0x1 : 0x0)) < 0) + goto error; + + return lockd; error: @@ -581,7 +589,7 @@ virLockDaemonSetupNetworkingSystemD(virNetServerPtr srv) false, 0, 1))) return -1; - if (virNetServerAddService(srv, svc, NULL) < 0) { + if (virNetServerAddService(srv, 0, svc, NULL) < 0) { virObjectUnref(svc); return -1; } @@ -603,7 +611,7 @@ virLockDaemonSetupNetworkingNative(virNetServerPtr srv, const char *sock_path) false, 0, 1))) return -1; - if (virNetServerAddService(srv, svc, NULL) < 0) { + if (virNetServerAddService(srv, 0, svc, NULL) < 0) { virObjectUnref(svc); return -1; } @@ -1366,7 +1374,7 @@ int main(int argc, char **argv) { ret = VIR_LOCK_DAEMON_ERR_INIT; goto cleanup; } - if (virNetServerAddProgram(lockDaemon->srv, lockProgram) < 0) { + if (virNetServerAddProgram(lockDaemon->srv, 0, lockProgram) < 0) { ret = VIR_LOCK_DAEMON_ERR_INIT; goto cleanup; } diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c index a7cee9d..ae59d28 100644 --- a/src/locking/lock_daemon_dispatch.c +++ b/src/locking/lock_daemon_dispatch.c @@ -1,7 +1,7 @@ /* * lock_daemon_dispatch.c: lock management daemon dispatch * - * Copyright (C) 2006-2012 Red Hat, Inc. + * Copyright (C) 2006-2012, 2014 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 @@ -38,7 +38,7 @@ VIR_LOG_INIT("locking.lock_daemon_dispatch"); #include "lock_daemon_dispatch_stubs.h" static int -virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchAcquireResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -98,7 +98,7 @@ virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNU static int -virLockSpaceProtocolDispatchCreateResource(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchCreateResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -147,7 +147,7 @@ virLockSpaceProtocolDispatchCreateResource(virNetServerPtr server ATTRIBUTE_UNUS static int -virLockSpaceProtocolDispatchDeleteResource(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchDeleteResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -196,7 +196,7 @@ virLockSpaceProtocolDispatchDeleteResource(virNetServerPtr server ATTRIBUTE_UNUS static int -virLockSpaceProtocolDispatchNew(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchNew(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -252,7 +252,7 @@ virLockSpaceProtocolDispatchNew(virNetServerPtr server ATTRIBUTE_UNUSED, static int -virLockSpaceProtocolDispatchRegister(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchRegister(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -298,7 +298,7 @@ virLockSpaceProtocolDispatchRegister(virNetServerPtr server ATTRIBUTE_UNUSED, static int -virLockSpaceProtocolDispatchReleaseResource(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchReleaseResource(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -349,7 +349,7 @@ virLockSpaceProtocolDispatchReleaseResource(virNetServerPtr server ATTRIBUTE_UNU static int -virLockSpaceProtocolDispatchRestrict(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchRestrict(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, @@ -388,7 +388,7 @@ virLockSpaceProtocolDispatchRestrict(virNetServerPtr server ATTRIBUTE_UNUSED, static int -virLockSpaceProtocolDispatchCreateLockSpace(virNetServerPtr server ATTRIBUTE_UNUSED, +virLockSpaceProtocolDispatchCreateLockSpace(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, virNetServerClientPtr client, virNetMessagePtr msg ATTRIBUTE_UNUSED, virNetMessageErrorPtr rerr, diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 2b5c9da..105a3dd 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2014 Red Hat, Inc. + * Copyright (C) 2010-2015 Red Hat, Inc. * Copyright IBM Corp. 2008 * * lxc_controller.c: linux container process controller @@ -854,13 +854,13 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl) LXC_STATE_DIR, ctrl->name) < 0) return -1; - if (!(ctrl->server = virNetServerNew(0, 0, 0, 1, - 0, -1, 0, false, - NULL, - virLXCControllerClientPrivateNew, - NULL, - virLXCControllerClientPrivateFree, - ctrl))) + if (!(ctrl->server = virNetServerNew(NULL))) + goto error; + + if (virNetServerAddSubServer(ctrl->server, + 0, 0, 0, 1, 0, -1, 0, false, + virLXCControllerClientPrivateNew, NULL, + virLXCControllerClientPrivateFree, ctrl) < 0) goto error; if (virSecurityManagerSetSocketLabel(ctrl->securityManager, ctrl->def) < 0) @@ -881,7 +881,7 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl) if (virSecurityManagerClearSocketLabel(ctrl->securityManager, ctrl->def) < 0) goto error; - if (virNetServerAddService(ctrl->server, svc, NULL) < 0) + if (virNetServerAddService(ctrl->server, 0, svc, NULL) < 0) goto error; virObjectUnref(svc); svc = NULL; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index b642d6e..199b38f 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -w # -# Copyright (C) 2010-2014 Red Hat, Inc. +# Copyright (C) 2010-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 @@ -403,7 +403,7 @@ elsif ($mode eq "server") { # First we print out a function declaration for the # real dispatcher body print "static int ${name}(\n"; - print " virNetServerPtr server,\n"; + print " virNetSubServerPtr subserver,\n"; print " virNetServerClientPtr client,\n"; print " virNetMessagePtr msg,\n"; print " virNetMessageErrorPtr rerr"; @@ -420,7 +420,7 @@ elsif ($mode eq "server") { # fixed function signature, for use in the dispatcher # table. This simply callers the real dispatcher method print "static int ${name}Helper(\n"; - print " virNetServerPtr server,\n"; + print " virNetSubServerPtr subserver,\n"; print " virNetServerClientPtr client,\n"; print " virNetMessagePtr msg,\n"; print " virNetMessageErrorPtr rerr,\n"; @@ -429,8 +429,9 @@ elsif ($mode eq "server") { print "{\n"; print " int rv;\n"; print " virThreadJobSet(\"$name\");\n"; - print " VIR_DEBUG(\"server=%p client=%p msg=%p rerr=%p args=%p ret=%p\", server, client, msg, rerr, args, ret);\n"; - print " rv = $name(server, client, msg, rerr"; + print " VIR_DEBUG(\"subserver=%p client=%p msg=%p rerr=%p args=%p ret=%p\", \n"; + print " subserver, client, msg, rerr, args, ret);\n"; + print " rv = $name(subserver, client, msg, rerr"; if ($argtype ne "void") { print ", args"; } @@ -851,7 +852,7 @@ elsif ($mode eq "server") { # print functions signature print "static int $name(\n"; - print " virNetServerPtr server ATTRIBUTE_UNUSED,\n"; + print " virNetSubServerPtr subserver ATTRIBUTE_UNUSED,\n"; print " virNetServerClientPtr client,\n"; print " virNetMessagePtr msg ATTRIBUTE_UNUSED,\n"; print " virNetMessageErrorPtr rerr"; diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c index 47d83ba..83cd9fe 100644 --- a/src/rpc/virnetserver.c +++ b/src/rpc/virnetserver.c @@ -1,7 +1,7 @@ /* * virnetserver.c: generic network RPC server * - * Copyright (C) 2006-2012, 2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -58,20 +58,9 @@ struct _virNetServerSignal { void *opaque; }; -typedef struct _virNetServerJob virNetServerJob; -typedef virNetServerJob *virNetServerJobPtr; - -struct _virNetServerJob { - virNetServerClientPtr client; - virNetMessagePtr msg; - virNetServerProgramPtr prog; -}; - struct _virNetServer { virObjectLockable parent; - virThreadPoolPtr workers; - bool privileged; size_t nsignals; @@ -84,21 +73,9 @@ struct _virNetServer { virNetServerMDNSPtr mdns; virNetServerMDNSGroupPtr mdnsGroup; - size_t nservices; - virNetServerServicePtr *services; - - size_t nprograms; - virNetServerProgramPtr *programs; - - size_t nclients; /* Current clients count */ - virNetServerClientPtr *clients; /* Clients */ - size_t nclients_max; /* Max allowed clients count */ - size_t nclients_unauth; /* Unauthenticated clients count */ - size_t nclients_unauth_max; /* Max allowed unauth clients count */ - - int keepaliveInterval; - unsigned int keepaliveCount; - bool keepaliveRequired; + size_t nsubservers; + virNetSubServerPtr *subservers; + virJSONValuePtr subsrvObject; bool quit; @@ -110,20 +87,11 @@ struct _virNetServer { size_t autoShutdownInhibitions; bool autoShutdownCallingInhibit; int autoShutdownInhibitFd; - - virNetServerClientPrivNew clientPrivNew; - virNetServerClientPrivPreExecRestart clientPrivPreExecRestart; - virFreeCallback clientPrivFree; - void *clientPrivOpaque; }; static virClassPtr virNetServerClass; static void virNetServerDispose(void *obj); -static void virNetServerUpdateServicesLocked(virNetServerPtr srv, - bool enabled); -static inline size_t virNetServerTrackPendingAuthLocked(virNetServerPtr srv); -static inline size_t virNetServerTrackCompletedAuthLocked(virNetServerPtr srv); static int virNetServerOnceInit(void) { @@ -139,221 +107,7 @@ static int virNetServerOnceInit(void) VIR_ONCE_GLOBAL_INIT(virNetServer) -static int virNetServerProcessMsg(virNetServerPtr srv, - virNetServerClientPtr client, - virNetServerProgramPtr prog, - virNetMessagePtr msg) -{ - int ret = -1; - if (!prog) { - /* Only send back an error for type == CALL. Other - * message types are not expecting replies, so we - * must just log it & drop them - */ - if (msg->header.type == VIR_NET_CALL || - msg->header.type == VIR_NET_CALL_WITH_FDS) { - if (virNetServerProgramUnknownError(client, - msg, - &msg->header) < 0) - goto cleanup; - } else { - VIR_INFO("Dropping client mesage, unknown program %d version %d type %d proc %d", - msg->header.prog, msg->header.vers, - msg->header.type, msg->header.proc); - /* Send a dummy reply to free up 'msg' & unblock client rx */ - virNetMessageClear(msg); - msg->header.type = VIR_NET_REPLY; - if (virNetServerClientSendMessage(client, msg) < 0) - goto cleanup; - } - goto done; - } - - if (virNetServerProgramDispatch(prog, - srv, - client, - msg) < 0) - goto cleanup; - - done: - ret = 0; - - cleanup: - return ret; -} - -static void virNetServerHandleJob(void *jobOpaque, void *opaque) -{ - virNetServerPtr srv = opaque; - virNetServerJobPtr job = jobOpaque; - - VIR_DEBUG("server=%p client=%p message=%p prog=%p", - srv, job->client, job->msg, job->prog); - - if (virNetServerProcessMsg(srv, job->client, job->prog, job->msg) < 0) - goto error; - - virObjectUnref(job->prog); - virObjectUnref(job->client); - VIR_FREE(job); - return; - - error: - virObjectUnref(job->prog); - virNetMessageFree(job->msg); - virNetServerClientClose(job->client); - virObjectUnref(job->client); - VIR_FREE(job); -} - -static int virNetServerDispatchNewMessage(virNetServerClientPtr client, - virNetMessagePtr msg, - void *opaque) -{ - virNetServerPtr srv = opaque; - virNetServerProgramPtr prog = NULL; - unsigned int priority = 0; - size_t i; - int ret = -1; - - VIR_DEBUG("server=%p client=%p message=%p", - srv, client, msg); - - virObjectLock(srv); - for (i = 0; i < srv->nprograms; i++) { - if (virNetServerProgramMatches(srv->programs[i], msg)) { - prog = srv->programs[i]; - break; - } - } - - if (srv->workers) { - virNetServerJobPtr job; - - if (VIR_ALLOC(job) < 0) - goto cleanup; - - job->client = client; - job->msg = msg; - - if (prog) { - virObjectRef(prog); - job->prog = prog; - priority = virNetServerProgramGetPriority(prog, msg->header.proc); - } - - ret = virThreadPoolSendJob(srv->workers, priority, job); - - if (ret < 0) { - VIR_FREE(job); - virObjectUnref(prog); - } - } else { - ret = virNetServerProcessMsg(srv, client, prog, msg); - } - - cleanup: - virObjectUnlock(srv); - - return ret; -} - - -static int virNetServerAddClient(virNetServerPtr srv, - virNetServerClientPtr client) -{ - virObjectLock(srv); - - if (srv->nclients >= srv->nclients_max) { - virReportError(VIR_ERR_RPC, - _("Too many active clients (%zu), dropping connection from %s"), - srv->nclients_max, virNetServerClientRemoteAddrString(client)); - goto error; - } - - if (virNetServerClientInit(client) < 0) - goto error; - - if (VIR_EXPAND_N(srv->clients, srv->nclients, 1) < 0) - goto error; - srv->clients[srv->nclients-1] = client; - virObjectRef(client); - - if (virNetServerClientNeedAuth(client)) - virNetServerTrackPendingAuthLocked(srv); - - if (srv->nclients_unauth_max && - srv->nclients_unauth == srv->nclients_unauth_max) { - /* Temporarily stop accepting new clients */ - VIR_INFO("Temporarily suspending services " - "due to max_anonymous_clients"); - virNetServerUpdateServicesLocked(srv, false); - } - - if (srv->nclients == srv->nclients_max) { - /* Temporarily stop accepting new clients */ - VIR_INFO("Temporarily suspending services due to max_clients"); - virNetServerUpdateServicesLocked(srv, false); - } - - virNetServerClientSetDispatcher(client, - virNetServerDispatchNewMessage, - srv); - - virNetServerClientInitKeepAlive(client, srv->keepaliveInterval, - srv->keepaliveCount); - - virObjectUnlock(srv); - return 0; - - error: - virObjectUnlock(srv); - return -1; -} - -static int virNetServerDispatchNewClient(virNetServerServicePtr svc, - virNetSocketPtr clientsock, - void *opaque) -{ - virNetServerPtr srv = opaque; - virNetServerClientPtr client; - - if (!(client = virNetServerClientNew(clientsock, - virNetServerServiceGetAuth(svc), - virNetServerServiceIsReadonly(svc), - virNetServerServiceGetMaxRequests(svc), -#if WITH_GNUTLS - virNetServerServiceGetTLSContext(svc), -#endif - srv->clientPrivNew, - srv->clientPrivPreExecRestart, - srv->clientPrivFree, - srv->clientPrivOpaque))) - return -1; - - if (virNetServerAddClient(srv, client) < 0) { - virNetServerClientClose(client); - virObjectUnref(client); - return -1; - } - virObjectUnref(client); - return 0; -} - - -virNetServerPtr virNetServerNew(size_t min_workers, - size_t max_workers, - size_t priority_workers, - size_t max_clients, - size_t max_anonymous_clients, - int keepaliveInterval, - unsigned int keepaliveCount, - bool keepaliveRequired, - const char *mdnsGroupName, - virNetServerClientPrivNew clientPrivNew, - virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, - virFreeCallback clientPrivFree, - void *clientPrivOpaque) +virNetServerPtr virNetServerNew(const char *mdnsGroupName) { virNetServerPtr srv; struct sigaction sig_action; @@ -364,23 +118,7 @@ virNetServerPtr virNetServerNew(size_t min_workers, if (!(srv = virObjectLockableNew(virNetServerClass))) return NULL; - if (max_workers && - !(srv->workers = virThreadPoolNew(min_workers, max_workers, - priority_workers, - virNetServerHandleJob, - srv))) - goto error; - - srv->nclients_max = max_clients; - srv->nclients_unauth_max = max_anonymous_clients; - srv->keepaliveInterval = keepaliveInterval; - srv->keepaliveCount = keepaliveCount; - srv->keepaliveRequired = keepaliveRequired; srv->sigwrite = srv->sigread = -1; - srv->clientPrivNew = clientPrivNew; - srv->clientPrivPreExecRestart = clientPrivPreExecRestart; - srv->clientPrivFree = clientPrivFree; - srv->clientPrivOpaque = clientPrivOpaque; srv->privileged = geteuid() == 0; srv->autoShutdownInhibitFd = -1; @@ -409,101 +147,198 @@ virNetServerPtr virNetServerNew(size_t min_workers, } -virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, - virNetServerClientPrivNew clientPrivNew, - virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart, - virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, - virFreeCallback clientPrivFree, - void *clientPrivOpaque) +int +virNetServerAddSubServer(virNetServerPtr srv, + size_t min_workers, + size_t max_workers, + size_t priority_workers, + size_t max_clients, + size_t max_anonymous_clients, + int keepaliveInterval, + unsigned int keepaliveCount, + bool keepaliveRequired, + virNetServerClientPrivNew clientPrivNew, + virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, + virFreeCallback clientPrivFree, + void *clientPrivOpaque) { - virNetServerPtr srv = NULL; - virJSONValuePtr clients; - virJSONValuePtr services; - size_t i; + int ret = -1; + virNetSubServerPtr subsrv = NULL; + + virObjectLock(srv); + + subsrv = virNetSubServerNew(min_workers, max_workers, priority_workers, + max_clients, max_anonymous_clients, + keepaliveInterval, keepaliveCount, + keepaliveRequired, clientPrivNew, + clientPrivPreExecRestart, clientPrivFree, + clientPrivOpaque); + + if (!subsrv || + VIR_APPEND_ELEMENT(srv->subservers, srv->nsubservers, subsrv) < 0) + goto cleanup; + + ret = srv->nsubservers - 1; + subsrv = NULL; + cleanup: + virObjectUnlock(srv); + VIR_FREE(subsrv); + return ret; +} + + +/* + * Separate function merely for the purpose of unified error + * reporting. + */ +static virNetSubServerPtr +virNetServerGetSubServerInternal(virNetServerPtr srv, + int subServerID) +{ + if (subServerID < 0 || subServerID >= srv->nsubservers) { + virReportError(VIR_ERR_INVALID_ARG, + _("Invalid subserver ID: %d"), + subServerID); + return NULL; + } + + return virObjectRef(srv->subservers[subServerID]); +} + +/* + * The subserver is locked after this function. + */ +virNetSubServerPtr +virNetServerGetSubServer(virNetServerPtr srv, + int subServerID) +{ + virNetSubServerPtr subsrv = NULL; + + virObjectLock(srv); + subsrv = virNetServerGetSubServerInternal(srv, subServerID); + virObjectUnlock(srv); + + return subsrv; +} + +int +virNetServerAddSubServerPostExec(virNetServerPtr srv, + virNetServerClientPrivNew clientPrivNew, + virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart, + virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, + virFreeCallback clientPrivFree, + void *clientPrivOpaque) +{ + bool keepaliveRequired; int n; - unsigned int min_workers; + int ret = -1; + int subServerID; + size_t i; + unsigned int keepaliveCount; + unsigned int keepaliveInterval; + unsigned int max_anonymous_clients; + unsigned int max_clients; unsigned int max_workers; + unsigned int min_workers; unsigned int priority_workers; - unsigned int max_clients; - unsigned int max_anonymous_clients; - unsigned int keepaliveInterval; - unsigned int keepaliveCount; - bool keepaliveRequired; - const char *mdnsGroupName = NULL; + virJSONValuePtr clients; + virJSONValuePtr object; + virJSONValuePtr services; + + virObjectLock(srv); + + if (!srv->subsrvObject) { + /* + * For back-compat we return -2 when there are no more saved + * subserver data so any new subservers can be added without + * restoring as well as without any error. + */ + return -2; + } + + if (virJSONValueIsArray(srv->subsrvObject)) { + object = virJSONValueArraySteal(srv->subsrvObject, 0); + if (virJSONValueArraySize(srv->subsrvObject) == 0) { + virJSONValueFree(srv->subsrvObject); + srv->subsrvObject = NULL; + } + } else { + object = srv->subsrvObject; + srv->subsrvObject = NULL; + } if (virJSONValueObjectGetNumberUint(object, "min_workers", &min_workers) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing min_workers data in JSON document")); - goto error; + goto cleanup; } if (virJSONValueObjectGetNumberUint(object, "max_workers", &max_workers) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing max_workers data in JSON document")); - goto error; + goto cleanup; } if (virJSONValueObjectGetNumberUint(object, "priority_workers", &priority_workers) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing priority_workers data in JSON document")); - goto error; + goto cleanup; } if (virJSONValueObjectGetNumberUint(object, "max_clients", &max_clients) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Missing max_clients data in JSON document")); - goto error; - } + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing max_clients data in JSON document")); + goto cleanup; + } if (virJSONValueObjectHasKey(object, "max_anonymous_clients")) { if (virJSONValueObjectGetNumberUint(object, "max_anonymous_clients", &max_anonymous_clients) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Malformed max_anonymous_clients data in JSON document")); - goto error; + goto cleanup; } } else { max_anonymous_clients = max_clients; } - if (virJSONValueObjectGetNumberUint(object, "keepaliveInterval", &keepaliveInterval) < 0) { + + if (virJSONValueObjectGetNumberUint(object, "keepaliveInterval", + &keepaliveInterval) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing keepaliveInterval data in JSON document")); - goto error; + goto cleanup; } if (virJSONValueObjectGetNumberUint(object, "keepaliveCount", &keepaliveCount) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing keepaliveCount data in JSON document")); - goto error; + goto cleanup; } if (virJSONValueObjectGetBoolean(object, "keepaliveRequired", &keepaliveRequired) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing keepaliveRequired data in JSON document")); - goto error; - } - - if (virJSONValueObjectHasKey(object, "mdnsGroupName") && - (!(mdnsGroupName = virJSONValueObjectGetString(object, "mdnsGroupName")))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Malformed mdnsGroupName data in JSON document")); - goto error; + goto cleanup; } - if (!(srv = virNetServerNew(min_workers, max_clients, - priority_workers, max_clients, - max_anonymous_clients, - keepaliveInterval, keepaliveCount, - keepaliveRequired, mdnsGroupName, - clientPrivNew, clientPrivPreExecRestart, - clientPrivFree, clientPrivOpaque))) - goto error; + if ((subServerID = virNetServerAddSubServer(srv, + min_workers, max_clients, + priority_workers, max_clients, + max_anonymous_clients, + keepaliveInterval, + keepaliveCount, + keepaliveRequired, + clientPrivNew, + clientPrivPreExecRestart, + clientPrivFree, + clientPrivOpaque)) < 0) + goto cleanup; if (!(services = virJSONValueObjectGet(object, "services"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing services data in JSON document")); - goto error; + goto cleanup; } - n = virJSONValueArraySize(services); + n = virJSONValueArraySize(services); if (n < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Malformed services data in JSON document")); - goto error; + goto cleanup; } for (i = 0; i < n; i++) { @@ -512,31 +347,31 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, if (!child) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing service data in JSON document")); - goto error; + goto cleanup; } if (!(service = virNetServerServiceNewPostExecRestart(child))) - goto error; + goto cleanup; /* XXX mdns entry names ? */ - if (virNetServerAddService(srv, service, NULL) < 0) { + if (virNetServerAddService(srv, subServerID, + service, NULL) < 0) { virObjectUnref(service); - goto error; + goto cleanup; } } - if (!(clients = virJSONValueObjectGet(object, "clients"))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing clients data in JSON document")); - goto error; + goto cleanup; } - n = virJSONValueArraySize(clients); + n = virJSONValueArraySize(clients); if (n < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Malformed clients data in JSON document")); - goto error; + goto cleanup; } for (i = 0; i < n; i++) { @@ -545,7 +380,7 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, if (!child) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing client data in JSON document")); - goto error; + goto cleanup; } if (!(client = virNetServerClientNewPostExecRestart(child, @@ -553,17 +388,58 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, clientPrivPreExecRestart, clientPrivFree, clientPrivOpaque))) - goto error; + goto cleanup; - if (virNetServerAddClient(srv, client) < 0) { + if (virNetSubServerAddClient(srv->subservers[subServerID], + client) < 0) { virObjectUnref(client); - goto error; + goto cleanup; } virObjectUnref(client); } - return srv; + ret = subServerID; + cleanup: + virJSONValueFree(object); + virObjectUnlock(srv); + return ret; +} + + +virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object) +{ + const char *mdnsGroupName = NULL; + virNetServerPtr srv = NULL; + + if (virJSONValueObjectHasKey(object, "mdnsGroupName") && + (!(mdnsGroupName = virJSONValueObjectGetString(object, "mdnsGroupName")))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed mdnsGroupName data in JSON document")); + goto error; + } + if (!(srv = virNetServerNew(mdnsGroupName))) + goto error; + + if (!virJSONValueObjectHasKey(object, "subservers")) { + /* + * Old format, we have to do this for back-compat. + */ + srv->subsrvObject = virJSONValueCopy(object); + } else { + virJSONValuePtr subservers = virJSONValueObjectGet(object, "subservers"); + + if (!subservers) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed subservers data in JSON document")); + goto error; + } + srv->subsrvObject = virJSONValueCopy(subservers); + } + if (!srv->subsrvObject) + goto error; + + return srv; error: virObjectUnref(srv); return NULL; @@ -572,9 +448,7 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv) { - virJSONValuePtr object; - virJSONValuePtr clients; - virJSONValuePtr services; + virJSONValuePtr object, srvArray = NULL; size_t i; virObjectLock(srv); @@ -582,51 +456,6 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv) if (!(object = virJSONValueNewObject())) goto error; - if (virJSONValueObjectAppendNumberUint(object, "min_workers", - virThreadPoolGetMinWorkers(srv->workers)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set min_workers data in JSON document")); - goto error; - } - if (virJSONValueObjectAppendNumberUint(object, "max_workers", - virThreadPoolGetMaxWorkers(srv->workers)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set max_workers data in JSON document")); - goto error; - } - if (virJSONValueObjectAppendNumberUint(object, "priority_workers", - virThreadPoolGetPriorityWorkers(srv->workers)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set priority_workers data in JSON document")); - goto error; - } - if (virJSONValueObjectAppendNumberUint(object, "max_clients", srv->nclients_max) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set max_clients data in JSON document")); - goto error; - } - if (virJSONValueObjectAppendNumberUint(object, "max_anonymous_clients", - srv->nclients_unauth_max) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set max_anonymous_clients data in JSON document")); - goto error; - } - if (virJSONValueObjectAppendNumberUint(object, "keepaliveInterval", srv->keepaliveInterval) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set keepaliveInterval data in JSON document")); - goto error; - } - if (virJSONValueObjectAppendNumberUint(object, "keepaliveCount", srv->keepaliveCount) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set keepaliveCount data in JSON document")); - goto error; - } - if (virJSONValueObjectAppendBoolean(object, "keepaliveRequired", srv->keepaliveRequired) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Cannot set keepaliveRequired data in JSON document")); - goto error; - } - if (srv->mdnsGroupName && virJSONValueObjectAppendString(object, "mdnsGroupName", srv->mdnsGroupName) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -634,36 +463,18 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv) goto error; } - services = virJSONValueNewArray(); - if (virJSONValueObjectAppend(object, "services", services) < 0) { - virJSONValueFree(services); + if (!(srvArray = virJSONValueNewArray())) goto error; - } - - for (i = 0; i < srv->nservices; i++) { - virJSONValuePtr child; - if (!(child = virNetServerServicePreExecRestart(srv->services[i]))) - goto error; - - if (virJSONValueArrayAppend(services, child) < 0) { - virJSONValueFree(child); - goto error; - } - } - clients = virJSONValueNewArray(); - if (virJSONValueObjectAppend(object, "clients", clients) < 0) { - virJSONValueFree(clients); - goto error; - } + for (i = 0; i < srv->nsubservers; i++) { + virJSONValuePtr subsrvJSON = NULL; + subsrvJSON = virNetSubServerPreExecRestart(srv->subservers[i]); - for (i = 0; i < srv->nclients; i++) { - virJSONValuePtr child; - if (!(child = virNetServerClientPreExecRestart(srv->clients[i]))) + if (!subsrvJSON) goto error; - if (virJSONValueArrayAppend(clients, child) < 0) { - virJSONValueFree(child); + if (virJSONValueArrayAppend(srvArray, subsrvJSON) < 0) { + virJSONValueFree(subsrvJSON); goto error; } } @@ -674,6 +485,7 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv) error: virJSONValueFree(object); + virJSONValueFree(srvArray); virObjectUnlock(srv); return NULL; } @@ -959,56 +771,68 @@ int virNetServerAddSignalHandler(virNetServerPtr srv, } - -int virNetServerAddService(virNetServerPtr srv, - virNetServerServicePtr svc, - const char *mdnsEntryName) +static inline int +virNetServerAddMDNSEntry(virNetServerPtr srv, + const char *mdnsEntryName, + int port) { + int ret = -1; + virObjectLock(srv); - if (VIR_EXPAND_N(srv->services, srv->nservices, 1) < 0) - goto error; + if (srv && mdnsEntryName && + !virNetServerMDNSAddEntry(srv->mdnsGroup, mdnsEntryName, port)) + goto cleanup; - if (mdnsEntryName) { - int port = virNetServerServiceGetPort(svc); + ret = 0; + cleanup: + virObjectUnlock(srv); + return ret; +} - if (!virNetServerMDNSAddEntry(srv->mdnsGroup, - mdnsEntryName, - port)) - goto error; - } +int virNetServerAddService(virNetServerPtr srv, + int subServerID, + virNetServerServicePtr svc, + const char *mdnsEntryName) +{ + int ret = -1; + virNetSubServerPtr subsrv = NULL; - srv->services[srv->nservices-1] = svc; - virObjectRef(svc); + subsrv = virNetServerGetSubServerInternal(srv, subServerID); + if (!subsrv) + goto cleanup; - virNetServerServiceSetDispatcher(svc, - virNetServerDispatchNewClient, - srv); + if (virNetSubServerAddService(subsrv, svc) < 0) + goto cleanup; - virObjectUnlock(srv); - return 0; + if (virNetServerAddMDNSEntry(srv, mdnsEntryName, + virNetServerServiceGetPort(svc)) < 0) + goto cleanup; - error: - virObjectUnlock(srv); - return -1; + ret = 0; + cleanup: + virObjectUnref(subsrv); + return ret; } int virNetServerAddProgram(virNetServerPtr srv, + int subServerID, virNetServerProgramPtr prog) { - virObjectLock(srv); - - if (VIR_EXPAND_N(srv->programs, srv->nprograms, 1) < 0) - goto error; + int ret = -1; + virNetSubServerPtr subsrv = NULL; - srv->programs[srv->nprograms-1] = virObjectRef(prog); + subsrv = virNetServerGetSubServer(srv, subServerID); + if (!subsrv) + goto cleanup; - virObjectUnlock(srv); - return 0; + if (virNetSubServerAddProgram(subsrv, prog) < 0) + goto cleanup; - error: - virObjectUnlock(srv); - return -1; + ret = 0; + cleanup: + virObjectUnref(subsrv); + return ret; } #if WITH_GNUTLS @@ -1036,55 +860,17 @@ static void virNetServerAutoShutdownTimer(int timerid ATTRIBUTE_UNUSED, virObjectUnlock(srv); } - -static void -virNetServerUpdateServicesLocked(virNetServerPtr srv, - bool enabled) -{ - size_t i; - - for (i = 0; i < srv->nservices; i++) - virNetServerServiceToggle(srv->services[i], enabled); -} - - void virNetServerUpdateServices(virNetServerPtr srv, bool enabled) { + size_t i; + virObjectLock(srv); - virNetServerUpdateServicesLocked(srv, enabled); + for (i = 0; i < srv->nsubservers; i++) + virNetSubServerUpdateServices(srv->subservers[i], enabled); virObjectUnlock(srv); } -/** - * virNetServerCheckLimits: - * @srv: server to check limits on - * - * Check if limits like max_clients or max_anonymous_clients - * are satisfied and if so, re-enable accepting new clients. - * The @srv must be locked when this function is called. - */ -static void -virNetServerCheckLimits(virNetServerPtr srv) -{ - /* Enable services if we can accept a new client. - * The new client can be accepted if both max_clients and - * max_anonymous_clients wouldn't get overcommitted by - * accepting it. */ - VIR_DEBUG("Considering re-enabling services: " - "nclients=%zu nclients_max=%zu " - "nclients_unauth=%zu nclients_unauth_max=%zu", - srv->nclients, srv->nclients_max, - srv->nclients_unauth, srv->nclients_unauth_max); - if (srv->nclients < srv->nclients_max && - (!srv->nclients_unauth_max || - srv->nclients_unauth < srv->nclients_unauth_max)) { - /* Now it makes sense to accept() a new client. */ - VIR_INFO("Re-enabling services"); - virNetServerUpdateServicesLocked(srv, true); - } -} - void virNetServerRun(virNetServerPtr srv) { int timerid = -1; @@ -1093,6 +879,12 @@ void virNetServerRun(virNetServerPtr srv) virObjectLock(srv); + if (srv->subsrvObject) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Not all subservers restored, cannot run server")); + goto cleanup; + } + if (srv->mdns && virNetServerMDNSStart(srv->mdns) < 0) goto cleanup; @@ -1120,17 +912,23 @@ void virNetServerRun(virNetServerPtr srv) */ if (srv->autoShutdownTimeout) { if (timerActive) { - if (srv->clients) { - VIR_DEBUG("Deactivating shutdown timer %d", timerid); - virEventUpdateTimeout(timerid, -1); - timerActive = false; + for (i = 0; i < srv->nsubservers; i++) { + if (virNetSubServerHasClients(srv->subservers[i])) { + VIR_DEBUG("Deactivating shutdown timer %d", timerid); + virEventUpdateTimeout(timerid, -1); + timerActive = false; + break; + } } } else { - if (!srv->clients) { - VIR_DEBUG("Activating shutdown timer %d", timerid); - virEventUpdateTimeout(timerid, - srv->autoShutdownTimeout * 1000); - timerActive = true; + for (i = 0; i < srv->nsubservers; i++) { + if (!virNetSubServerHasClients(srv->subservers[i])) { + VIR_DEBUG("Activating shutdown timer %d", timerid); + virEventUpdateTimeout(timerid, + srv->autoShutdownTimeout * 1000); + timerActive = true; + break; + } } } } @@ -1143,30 +941,8 @@ void virNetServerRun(virNetServerPtr srv) } virObjectLock(srv); - reprocess: - for (i = 0; i < srv->nclients; i++) { - /* Coverity 5.3.0 couldn't see that srv->clients is non-NULL - * if srv->nclients is non-zero. */ - sa_assert(srv->clients); - if (virNetServerClientWantClose(srv->clients[i])) - virNetServerClientClose(srv->clients[i]); - if (virNetServerClientIsClosed(srv->clients[i])) { - virNetServerClientPtr client = srv->clients[i]; - - VIR_DELETE_ELEMENT(srv->clients, i, srv->nclients); - - if (virNetServerClientNeedAuth(client)) - virNetServerTrackCompletedAuthLocked(srv); - - virNetServerCheckLimits(srv); - - virObjectUnlock(srv); - virObjectUnref(client); - virObjectLock(srv); - - goto reprocess; - } - } + for (i = 0; i < srv->nsubservers; i++) + virNetSubServerProcessClients(srv->subservers[i]); } cleanup: @@ -1191,11 +967,6 @@ void virNetServerDispose(void *obj) VIR_FORCE_CLOSE(srv->autoShutdownInhibitFd); - for (i = 0; i < srv->nservices; i++) - virNetServerServiceToggle(srv->services[i], false); - - virThreadPoolFree(srv->workers); - for (i = 0; i < srv->nsignals; i++) { sigaction(srv->signals[i]->signum, &srv->signals[i]->oldaction, NULL); VIR_FREE(srv->signals[i]); @@ -1206,22 +977,14 @@ void virNetServerDispose(void *obj) if (srv->sigwatch > 0) virEventRemoveHandle(srv->sigwatch); - for (i = 0; i < srv->nservices; i++) - virObjectUnref(srv->services[i]); - VIR_FREE(srv->services); - - for (i = 0; i < srv->nprograms; i++) - virObjectUnref(srv->programs[i]); - VIR_FREE(srv->programs); - - for (i = 0; i < srv->nclients; i++) { - virNetServerClientClose(srv->clients[i]); - virObjectUnref(srv->clients[i]); - } - VIR_FREE(srv->clients); + for (i = 0; i < srv->nsubservers; i++) + virObjectUnref(srv->subservers[i]); + VIR_FREE(srv->subservers); VIR_FREE(srv->mdnsGroupName); virNetServerMDNSFree(srv->mdns); + + virJSONValueFree(srv->subsrvObject); } void virNetServerClose(virNetServerPtr srv) @@ -1233,48 +996,8 @@ void virNetServerClose(virNetServerPtr srv) virObjectLock(srv); - for (i = 0; i < srv->nservices; i++) - virNetServerServiceClose(srv->services[i]); - - virObjectUnlock(srv); -} - -bool virNetServerKeepAliveRequired(virNetServerPtr srv) -{ - bool required; - virObjectLock(srv); - required = srv->keepaliveRequired; - virObjectUnlock(srv); - return required; -} - -static inline size_t -virNetServerTrackPendingAuthLocked(virNetServerPtr srv) -{ - return ++srv->nclients_unauth; -} - -static inline size_t -virNetServerTrackCompletedAuthLocked(virNetServerPtr srv) -{ - return --srv->nclients_unauth; -} - -size_t virNetServerTrackPendingAuth(virNetServerPtr srv) -{ - size_t ret; - virObjectLock(srv); - ret = virNetServerTrackPendingAuthLocked(srv); - virObjectUnlock(srv); - return ret; -} + for (i = 0; i < srv->nsubservers; i++) + virNetSubServerClose(srv->subservers[i]); -size_t virNetServerTrackCompletedAuth(virNetServerPtr srv) -{ - size_t ret; - virObjectLock(srv); - ret = virNetServerTrackCompletedAuthLocked(srv); - virNetServerCheckLimits(srv); virObjectUnlock(srv); - return ret; } diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index 8c5ae07..6b1630b 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -1,7 +1,7 @@ /* * virnetserver.h: generic network RPC server * - * Copyright (C) 2006-2011 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -29,32 +29,37 @@ # ifdef WITH_GNUTLS # include "virnettlscontext.h" # endif +# include "virobject.h" +# include "virjson.h" # include "virnetserverprogram.h" # include "virnetserverclient.h" # include "virnetserverservice.h" -# include "virobject.h" -# include "virjson.h" - -virNetServerPtr virNetServerNew(size_t min_workers, - size_t max_workers, - size_t priority_workers, - size_t max_clients, - size_t max_anonymous_clients, - int keepaliveInterval, - unsigned int keepaliveCount, - bool keepaliveRequired, - const char *mdnsGroupName, - virNetServerClientPrivNew clientPrivNew, - virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, - virFreeCallback clientPrivFree, - void *clientPrivOpaque); - -virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, - virNetServerClientPrivNew clientPrivNew, - virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart, - virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, - virFreeCallback clientPrivFree, - void *clientPrivOpaque); +# include "virnetsubserver.h" + +virNetServerPtr virNetServerNew(const char *mdnsGroupName); + +int virNetServerAddSubServer(virNetServerPtr srv, + size_t min_workers, + size_t max_workers, + size_t priority_workers, + size_t max_clients, + size_t max_anonymous_clients, + int keepaliveInterval, + unsigned int keepaliveCount, + bool keepaliveRequired, + virNetServerClientPrivNew clientPrivNew, + virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, + virFreeCallback clientPrivFree, + void *clientPrivOpaque); + +int virNetServerAddSubServerPostExec(virNetServerPtr srv, + virNetServerClientPrivNew clientPrivNew, + virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart, + virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, + virFreeCallback clientPrivFree, + void *clientPrivOpaque); + +virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object); virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv); @@ -76,10 +81,12 @@ int virNetServerAddSignalHandler(virNetServerPtr srv, void *opaque); int virNetServerAddService(virNetServerPtr srv, + int subServerID, virNetServerServicePtr svc, const char *mdnsEntryName); int virNetServerAddProgram(virNetServerPtr srv, + int subServerID, virNetServerProgramPtr prog); # if WITH_GNUTLS @@ -96,9 +103,7 @@ void virNetServerQuit(virNetServerPtr srv); void virNetServerClose(virNetServerPtr srv); -bool virNetServerKeepAliveRequired(virNetServerPtr srv); - -size_t virNetServerTrackPendingAuth(virNetServerPtr srv); -size_t virNetServerTrackCompletedAuth(virNetServerPtr srv); +virNetSubServerPtr virNetServerGetSubServer(virNetServerPtr srv, + int subServerID); #endif diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c index a4d9295..c043870 100644 --- a/src/rpc/virnetserverprogram.c +++ b/src/rpc/virnetserverprogram.c @@ -1,7 +1,7 @@ /* * virnetserverprogram.c: generic network RPC server program * - * Copyright (C) 2006-2012 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -253,7 +253,7 @@ int virNetServerProgramUnknownError(virNetServerClientPtr client, static int virNetServerProgramDispatchCall(virNetServerProgramPtr prog, - virNetServerPtr server, + virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg); @@ -273,7 +273,7 @@ virNetServerProgramDispatchCall(virNetServerProgramPtr prog, * Returns 0 if the message was dispatched, -1 upon fatal error */ int virNetServerProgramDispatch(virNetServerProgramPtr prog, - virNetServerPtr server, + virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg) { @@ -304,7 +304,7 @@ int virNetServerProgramDispatch(virNetServerProgramPtr prog, switch (msg->header.type) { case VIR_NET_CALL: case VIR_NET_CALL_WITH_FDS: - ret = virNetServerProgramDispatchCall(prog, server, client, msg); + ret = virNetServerProgramDispatchCall(prog, subserver, client, msg); break; case VIR_NET_STREAM: @@ -367,7 +367,7 @@ int virNetServerProgramDispatch(virNetServerProgramPtr prog, */ static int virNetServerProgramDispatchCall(virNetServerProgramPtr prog, - virNetServerPtr server, + virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg) { @@ -434,7 +434,7 @@ virNetServerProgramDispatchCall(virNetServerProgramPtr prog, * * 'args and 'ret' */ - rv = (dispatcher->func)(server, client, msg, &rerr, arg, ret); + rv = (dispatcher->func)(subserver, client, msg, &rerr, arg, ret); if (virIdentitySetCurrent(NULL) < 0) goto error; diff --git a/src/rpc/virnetserverprogram.h b/src/rpc/virnetserverprogram.h index c1ae17e..f292bc7 100644 --- a/src/rpc/virnetserverprogram.h +++ b/src/rpc/virnetserverprogram.h @@ -1,7 +1,7 @@ /* * virnetserverprogram.h: generic network RPC server program * - * Copyright (C) 2006-2011 Red Hat, Inc. + * Copyright (C) 2006-2012, 2014-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -31,6 +31,9 @@ typedef struct _virNetServer virNetServer; typedef virNetServer *virNetServerPtr; +typedef struct _virNetSubServer virNetSubServer; +typedef virNetSubServer *virNetSubServerPtr; + typedef struct _virNetServerService virNetServerService; typedef virNetServerService *virNetServerServicePtr; @@ -40,7 +43,7 @@ typedef virNetServerProgram *virNetServerProgramPtr; typedef struct _virNetServerProgramProc virNetServerProgramProc; typedef virNetServerProgramProc *virNetServerProgramProcPtr; -typedef int (*virNetServerProgramDispatchFunc)(virNetServerPtr server, +typedef int (*virNetServerProgramDispatchFunc)(virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg, virNetMessageErrorPtr rerr, @@ -72,7 +75,7 @@ int virNetServerProgramMatches(virNetServerProgramPtr prog, virNetMessagePtr msg); int virNetServerProgramDispatch(virNetServerProgramPtr prog, - virNetServerPtr server, + virNetSubServerPtr subserver, virNetServerClientPtr client, virNetMessagePtr msg); diff --git a/src/rpc/virnetsubserver.c b/src/rpc/virnetsubserver.c new file mode 100644 index 0000000..8d9defb --- /dev/null +++ b/src/rpc/virnetsubserver.c @@ -0,0 +1,662 @@ +/* + * virnetsubserver.c + * + * 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@redhat.com> + */ + + +#include <config.h> + +#include "virnetsubserver.h" + +#include "virlog.h" +#include "viralloc.h" +#include "virerror.h" +#include "virthread.h" +#include "virthreadpool.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +/* + * This file has been split from virnetserver.c and bothering people + * with the split and changing flters from "netserver" to + * "netsubserver" doesn't seem worthwhile, so we'll keep this as + * "netserver". + */ +VIR_LOG_INIT("rpc.netserver"); + + +typedef struct _virNetServerJob virNetServerJob; +typedef virNetServerJob *virNetServerJobPtr; + +struct _virNetServerJob { + virNetServerClientPtr client; + virNetMessagePtr msg; + virNetServerProgramPtr prog; +}; + +struct _virNetSubServer { + virObjectLockable object; + + virThreadPoolPtr workers; + + size_t nservices; + virNetServerServicePtr *services; + + size_t nprograms; + virNetServerProgramPtr *programs; + + size_t nclients; /* Current clients count */ + virNetServerClientPtr *clients; /* Clients */ + size_t nclients_max; /* Max allowed clients count */ + size_t nclients_unauth; /* Unauthenticated clients count */ + size_t nclients_unauth_max; /* Max allowed unauth clients count */ + + int keepaliveInterval; + unsigned int keepaliveCount; + bool keepaliveRequired; + + virNetServerClientPrivNew clientPrivNew; + virNetServerClientPrivPreExecRestart clientPrivPreExecRestart; + virFreeCallback clientPrivFree; + void *clientPrivOpaque; +}; + + +static virClassPtr virNetSubServerClass; + +static void +virNetSubServerDispose(void *obj) +{ + size_t i = 0; + virNetSubServerPtr subsrv = obj; + + if (!subsrv) + return; + + for (i = 0; i < subsrv->nservices; i++) + virNetServerServiceToggle(subsrv->services[i], false); + + virThreadPoolFree(subsrv->workers); + + for (i = 0; i < subsrv->nservices; i++) + virObjectUnref(subsrv->services[i]); + VIR_FREE(subsrv->services); + + for (i = 0; i < subsrv->nprograms; i++) + virObjectUnref(subsrv->programs[i]); + VIR_FREE(subsrv->programs); + + for (i = 0; i < subsrv->nclients; i++) { + virNetServerClientClose(subsrv->clients[i]); + virObjectUnref(subsrv->clients[i]); + } + VIR_FREE(subsrv->clients); +} + +static int +virNetSubServerOnceInit(void) +{ + if (!(virNetSubServerClass = virClassNew(virClassForObjectLockable(), + "virNetSubServer", + sizeof(virNetSubServer), + virNetSubServerDispose))) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virNetSubServer) + + +static inline size_t +virNetSubServerTrackPendingAuthLocked(virNetSubServerPtr subsrv) +{ + return ++subsrv->nclients_unauth; +} + +static inline size_t +virNetSubServerTrackCompletedAuthLocked(virNetSubServerPtr subsrv) +{ + return --subsrv->nclients_unauth; +} + +static int +virNetSubServerProcessMsg(virNetSubServerPtr subsrv, + virNetServerClientPtr client, + virNetServerProgramPtr prog, + virNetMessagePtr msg) +{ + int ret = -1; + if (!prog) { + /* Only send back an error for type == CALL. Other + * message types are not expecting replies, so we + * must just log it & drop them + */ + if (msg->header.type == VIR_NET_CALL || + msg->header.type == VIR_NET_CALL_WITH_FDS) { + if (virNetServerProgramUnknownError(client, + msg, + &msg->header) < 0) + goto cleanup; + } else { + VIR_INFO("Dropping client mesage, unknown program %d version %d type %d proc %d", + msg->header.prog, msg->header.vers, + msg->header.type, msg->header.proc); + /* Send a dummy reply to free up 'msg' & unblock client rx */ + virNetMessageClear(msg); + msg->header.type = VIR_NET_REPLY; + if (virNetServerClientSendMessage(client, msg) < 0) + goto cleanup; + } + goto done; + } + + if (virNetServerProgramDispatch(prog, subsrv, client, msg) < 0) + goto cleanup; + + done: + ret = 0; + + cleanup: + return ret; +} + +static void virNetSubServerHandleJob(void *jobOpaque, void *opaque) +{ + virNetSubServerPtr subsrv = opaque; + virNetServerJobPtr job = jobOpaque; + + VIR_DEBUG("subserver=%p client=%p message=%p prog=%p", + subsrv, job->client, job->msg, job->prog); + + if (virNetSubServerProcessMsg(subsrv, job->client, job->prog, job->msg) < 0) + goto error; + + virObjectUnref(job->prog); + virObjectUnref(job->client); + VIR_FREE(job); + return; + + error: + virObjectUnref(job->prog); + virNetMessageFree(job->msg); + virNetServerClientClose(job->client); + virObjectUnref(job->client); + VIR_FREE(job); +} + +static int +virNetSubServerDispatchNewClient(virNetServerServicePtr svc, + virNetSocketPtr clientsock, + void *opaque) +{ + virNetSubServerPtr subsrv = opaque; + virNetServerClientPtr client; + + if (!(client = virNetServerClientNew(clientsock, + virNetServerServiceGetAuth(svc), + virNetServerServiceIsReadonly(svc), + virNetServerServiceGetMaxRequests(svc), +#if WITH_GNUTLS + virNetServerServiceGetTLSContext(svc), +#endif + subsrv->clientPrivNew, + subsrv->clientPrivPreExecRestart, + subsrv->clientPrivFree, + subsrv->clientPrivOpaque))) + return -1; + + if (virNetSubServerAddClient(subsrv, client) < 0) { + virNetServerClientClose(client); + virObjectUnref(client); + return -1; + } + virObjectUnref(client); + return 0; +} + +static void +virNetSubServerUpdateServicesLocked(virNetSubServerPtr subsrv, + bool enabled) +{ + size_t i = 0; + + for (i = 0; i < subsrv->nservices; i++) + virNetServerServiceToggle(subsrv->services[i], enabled); +} + +void +virNetSubServerUpdateServices(virNetSubServerPtr subsrv, + bool enabled) +{ + virObjectLock(subsrv); + virNetSubServerUpdateServicesLocked(subsrv, enabled); + virObjectUnlock(subsrv); +} + +/** + * virNetSubServerCheckLimits: + * @srv: server to check limits on + * + * Check if limits like max_clients or max_anonymous_clients + * are satisfied and if so, re-enable accepting new clients. + * The @srv must be locked when this function is called. + */ +static void +virNetSubServerCheckLimits(virNetSubServerPtr subsrv) +{ + /* Enable services if we can accept a new client. + * The new client can be accepted if both max_clients and + * max_anonymous_clients wouldn't get overcommitted by + * accepting it. */ + VIR_DEBUG("Considering re-enabling services: " + "nclients=%zu nclients_max=%zu " + "nclients_unauth=%zu nclients_unauth_max=%zu", + subsrv->nclients, subsrv->nclients_max, + subsrv->nclients_unauth, subsrv->nclients_unauth_max); + if (subsrv->nclients < subsrv->nclients_max && + (!subsrv->nclients_unauth_max || + subsrv->nclients_unauth < subsrv->nclients_unauth_max)) { + /* Now it makes sense to accept() a new client. */ + VIR_INFO("Re-enabling services"); + virNetSubServerUpdateServicesLocked(subsrv, true); + } +} + +static int +virNetSubServerDispatchNewMessage(virNetServerClientPtr client, + virNetMessagePtr msg, + void *opaque) +{ + virNetSubServerPtr subsrv = opaque; + virNetServerProgramPtr prog = NULL; + unsigned int priority = 0; + size_t i; + int ret = -1; + + VIR_DEBUG("subserver=%p client=%p message=%p", + subsrv, client, msg); + + virObjectLock(subsrv); + for (i = 0; i < subsrv->nprograms; i++) { + if (virNetServerProgramMatches(subsrv->programs[i], msg)) { + prog = subsrv->programs[i]; + break; + } + } + + if (subsrv->workers) { + virNetServerJobPtr job; + + if (VIR_ALLOC(job) < 0) + goto cleanup; + + job->client = client; + job->msg = msg; + + if (prog) { + virObjectRef(prog); + job->prog = prog; + priority = virNetServerProgramGetPriority(prog, msg->header.proc); + } + + ret = virThreadPoolSendJob(subsrv->workers, priority, job); + + if (ret < 0) { + VIR_FREE(job); + virObjectUnref(prog); + } + } else { + ret = virNetSubServerProcessMsg(subsrv, client, prog, msg); + } + + cleanup: + virObjectUnlock(subsrv); + + return ret; +} + +virNetSubServerPtr +virNetSubServerNew(size_t min_workers, + size_t max_workers, + size_t priority_workers, + size_t max_clients, + size_t max_anonymous_clients, + int keepaliveInterval, + unsigned int keepaliveCount, + bool keepaliveRequired, + virNetServerClientPrivNew cpNew, + virNetServerClientPrivPreExecRestart cpPreExecRestart, + virFreeCallback cpFree, + void *cpOpaque) +{ + virNetSubServerPtr subsrv = NULL; + + if (virNetSubServerInitialize() < 0) + return NULL; + + if (!(subsrv = virObjectLockableNew(virNetSubServerClass))) + return NULL; + + subsrv->nclients_max = max_clients; + subsrv->nclients_unauth_max = max_anonymous_clients; + subsrv->clientPrivNew = cpNew; + subsrv->clientPrivPreExecRestart = cpPreExecRestart; + subsrv->clientPrivFree = cpFree; + subsrv->clientPrivOpaque = cpOpaque; + subsrv->keepaliveInterval = keepaliveInterval; + subsrv->keepaliveCount = keepaliveCount; + subsrv->keepaliveRequired = keepaliveRequired; + + if (max_workers && + !(subsrv->workers = virThreadPoolNew(min_workers, max_workers, + priority_workers, + virNetSubServerHandleJob, + subsrv))) + goto error; + + return subsrv; + error: + virObjectUnref(subsrv); + return NULL; +} + +int +virNetSubServerAddClient(virNetSubServerPtr subsrv, + virNetServerClientPtr client) +{ + virObjectLock(subsrv); + + if (subsrv->nclients >= subsrv->nclients_max) { + virReportError(VIR_ERR_RPC, + _("Too many active clients (%zu), dropping connection from %s"), + subsrv->nclients_max, virNetServerClientRemoteAddrString(client)); + goto error; + } + + if (virNetServerClientInit(client) < 0) + goto error; + + if (VIR_EXPAND_N(subsrv->clients, subsrv->nclients, 1) < 0) + goto error; + subsrv->clients[subsrv->nclients-1] = client; + virObjectRef(client); + + if (virNetServerClientNeedAuth(client)) + virNetSubServerTrackPendingAuthLocked(subsrv); + + if (subsrv->nclients_unauth_max && + subsrv->nclients_unauth == subsrv->nclients_unauth_max) { + /* Temporarily stop accepting new clients */ + VIR_INFO("Temporarily suspending services " + "due to max_anonymous_clients"); + virNetSubServerUpdateServicesLocked(subsrv, false); + } + + if (subsrv->nclients == subsrv->nclients_max) { + /* Temporarily stop accepting new clients */ + VIR_INFO("Temporarily suspending services due to max_clients"); + virNetSubServerUpdateServicesLocked(subsrv, false); + } + + virNetServerClientSetDispatcher(client, + virNetSubServerDispatchNewMessage, + subsrv); + + virNetServerClientInitKeepAlive(client, subsrv->keepaliveInterval, + subsrv->keepaliveCount); + + virObjectUnlock(subsrv); + return 0; + + error: + virObjectUnlock(subsrv); + return -1; +} + +virJSONValuePtr +virNetSubServerPreExecRestart(virNetSubServerPtr subsrv) +{ + size_t i; + virJSONValuePtr clients = NULL; + virJSONValuePtr object = NULL; + virJSONValuePtr ret = NULL; + virJSONValuePtr services = NULL; + + if (!(object = virJSONValueNewObject())) + goto error; + + if (virJSONValueObjectAppendNumberUint(object, "min_workers", + virThreadPoolGetMinWorkers(subsrv->workers)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set min_workers data in JSON document")); + goto error; + } + if (virJSONValueObjectAppendNumberUint(object, "max_workers", + virThreadPoolGetMaxWorkers(subsrv->workers)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set max_workers data in JSON document")); + goto error; + } + if (virJSONValueObjectAppendNumberUint(object, "priority_workers", + virThreadPoolGetPriorityWorkers(subsrv->workers)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set priority_workers data in JSON document")); + goto error; + } + if (virJSONValueObjectAppendNumberUint(object, "max_clients", subsrv->nclients_max) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set max_clients data in JSON document")); + goto error; + } + if (virJSONValueObjectAppendNumberUint(object, "max_anonymous_clients", + subsrv->nclients_unauth_max) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set max_anonymous_clients data in JSON document")); + goto error; + } + if (virJSONValueObjectAppendNumberUint(object, "keepaliveInterval", subsrv->keepaliveInterval) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set keepaliveInterval data in JSON document")); + goto error; + } + if (virJSONValueObjectAppendNumberUint(object, "keepaliveCount", subsrv->keepaliveCount) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set keepaliveCount data in JSON document")); + goto error; + } + if (virJSONValueObjectAppendBoolean(object, "keepaliveRequired", subsrv->keepaliveRequired) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot set keepaliveRequired data in JSON document")); + goto error; + } + + services = virJSONValueNewArray(); + if (virJSONValueObjectAppend(object, "services", services) < 0) { + virJSONValueFree(services); + goto error; + } + + for (i = 0; i < subsrv->nservices; i++) { + virJSONValuePtr child; + if (!(child = virNetServerServicePreExecRestart(subsrv->services[i]))) + goto error; + + if (virJSONValueArrayAppend(services, child) < 0) { + virJSONValueFree(child); + goto error; + } + } + + clients = virJSONValueNewArray(); + if (virJSONValueObjectAppend(object, "clients", clients) < 0) { + virJSONValueFree(clients); + goto error; + } + + for (i = 0; i < subsrv->nclients; i++) { + virJSONValuePtr child; + if (!(child = virNetServerClientPreExecRestart(subsrv->clients[i]))) + goto error; + + if (virJSONValueArrayAppend(clients, child) < 0) { + virJSONValueFree(child); + goto error; + } + } + + ret = object; + object = NULL; + error: + virJSONValueFree(object); + return ret; +} + +int +virNetSubServerAddService(virNetSubServerPtr subsrv, + virNetServerServicePtr svc) +{ + int ret = -1; + + virObjectLock(subsrv); + + if (VIR_APPEND_ELEMENT_COPY(subsrv->services, subsrv->nservices, svc) < 0) + goto cleanup; + + virNetServerServiceSetDispatcher(svc, + virNetSubServerDispatchNewClient, + subsrv); + + virObjectRef(svc); + + ret = 0; + cleanup: + virObjectUnlock(subsrv); + return ret; +} + +int +virNetSubServerAddProgram(virNetSubServerPtr subsrv, + virNetServerProgramPtr prog) +{ + int ret = -1; + + virObjectLock(subsrv); + + if (VIR_APPEND_ELEMENT_COPY(subsrv->programs, subsrv->nprograms, prog) < 0) + goto cleanup; + + virObjectRef(prog); + + ret = 0; + cleanup: + virObjectUnlock(subsrv); + return ret; +} + +void +virNetSubServerClose(virNetSubServerPtr subsrv) +{ + size_t i; + + virObjectLock(subsrv); + + for (i = 0; i < subsrv->nservices; i++) + virNetServerServiceClose(subsrv->services[i]); + + virObjectUnlock(subsrv); +} + +bool virNetSubServerKeepAliveRequired(virNetSubServerPtr subsrv) +{ + bool required; + virObjectLock(subsrv); + required = subsrv->keepaliveRequired; + virObjectUnlock(subsrv); + return required; +} + +size_t +virNetSubServerTrackPendingAuth(virNetSubServerPtr subsrv) +{ + size_t ret; + virObjectLock(subsrv); + ret = virNetSubServerTrackPendingAuthLocked(subsrv); + virObjectUnlock(subsrv); + return ret; +} + +size_t +virNetSubServerTrackCompletedAuth(virNetSubServerPtr subsrv) +{ + size_t ret; + virObjectLock(subsrv); + ret = virNetSubServerTrackCompletedAuthLocked(subsrv); + virNetSubServerCheckLimits(subsrv); + virObjectUnlock(subsrv); + return ret; +} + +bool +virNetSubServerHasClients(virNetSubServerPtr subsrv) +{ + bool ret; + + virObjectLock(subsrv); + ret = !!subsrv->nclients; + virObjectUnlock(subsrv); + + return ret; +} + +void +virNetSubServerProcessClients(virNetSubServerPtr subsrv) +{ + size_t i; + + virObjectLock(subsrv); + + reprocess: + for (i = 0; i < subsrv->nclients; i++) { + /* Coverity 5.3.0 couldn't see that subsrv->clients is non-NULL + * if subsrv->nclients is non-zero. */ + sa_assert(subsrv->clients); + if (virNetServerClientWantClose(subsrv->clients[i])) + virNetServerClientClose(subsrv->clients[i]); + if (virNetServerClientIsClosed(subsrv->clients[i])) { + virNetServerClientPtr client = subsrv->clients[i]; + + VIR_DELETE_ELEMENT(subsrv->clients, i, subsrv->nclients); + + if (virNetServerClientNeedAuth(client)) + virNetSubServerTrackCompletedAuthLocked(subsrv); + + virNetSubServerCheckLimits(subsrv); + + virObjectUnlock(subsrv); + virObjectUnref(client); + virObjectLock(subsrv); + + goto reprocess; + } + } + + virObjectUnlock(subsrv); +} diff --git a/src/rpc/virnetsubserver.h b/src/rpc/virnetsubserver.h new file mode 100644 index 0000000..cf7c213 --- /dev/null +++ b/src/rpc/virnetsubserver.h @@ -0,0 +1,76 @@ +/* + * virnetsubserver.h + * + * 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@redhat.com> + */ + +#ifndef __VIR_NET_SUBSERVER_H__ +# define __VIR_NET_SUBSERVER_H__ + + +# include <unistd.h> + +# include "virjson.h" +# include "virnetserverclient.h" +# include "virnetserverprogram.h" +# include "virnetserverservice.h" +# include "virobject.h" + + + +typedef struct _virNetSubServer virNetSubServer; +typedef virNetSubServer *virNetSubServerPtr; + + +virNetSubServerPtr +virNetSubServerNew(size_t min_workers, + size_t max_workers, + size_t priority_workers, + size_t max_clients, + size_t max_anonymous_clients, + int keepaliveInterval, + unsigned int keepaliveCount, + bool keepaliveRequired, + virNetServerClientPrivNew cpNew, + virNetServerClientPrivPreExecRestart cpPreExecRestart, + virFreeCallback cpFree, + void *cpOpaque); + +void virNetSubServerClose(virNetSubServerPtr subsrv); + +virJSONValuePtr virNetSubServerPreExecRestart(virNetSubServerPtr subsrv); + +int virNetSubServerAddService(virNetSubServerPtr subsrv, + virNetServerServicePtr svc); +int virNetSubServerAddProgram(virNetSubServerPtr subsrv, + virNetServerProgramPtr prog); +int virNetSubServerAddClient(virNetSubServerPtr subsrv, + virNetServerClientPtr client); + +bool virNetSubServerKeepAliveRequired(virNetSubServerPtr subsrv); + +size_t virNetSubServerTrackPendingAuth(virNetSubServerPtr subsrv); +size_t virNetSubServerTrackCompletedAuth(virNetSubServerPtr subsrv); + +bool virNetSubServerHasClients(virNetSubServerPtr subsrv); +void virNetSubServerProcessClients(virNetSubServerPtr subsrv); + +void virNetSubServerUpdateServices(virNetSubServerPtr subsrv, bool enabled); + +#endif /* __VIR_NET_SUBSERVER_H__ */ -- 2.3.5

On Thu, Apr 16, 2015 at 04:46:39PM +0200, Martin Kletzander wrote:
Each subserver has its own RPC programs, services, workers, keepalive, clients etc. Hence (possible) multiple subservers are properly separated.
The part in remote.c is just mechanical, the same applies to most of the code movement from virnetserver.c to virnetsubserver.c.
So, the problem we're facing here is that virNetServer is really filling two distinct roles in one class - it is the thing that manages the overall daemon process state, as well as managing the server connection/services. So the splitting up you're doing does rather make sense. I wonder if we could name it differently though. eg have virNetDaemon to handle the process level stuff, and virNetServer to handle the network level stuff. So what is in virnetserver.c moves to virnetdaemon.c and your new virnetsubserver.c becomes the new virnetserver.c
diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h index 8c5ae07..6b1630b 100644 --- a/src/rpc/virnetserver.h +++ b/src/rpc/virnetserver.h @@ -1,7 +1,7 @@ /* * virnetserver.h: generic network RPC server * - * Copyright (C) 2006-2011 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -29,32 +29,37 @@ # ifdef WITH_GNUTLS # include "virnettlscontext.h" # endif +# include "virobject.h" +# include "virjson.h" # include "virnetserverprogram.h" # include "virnetserverclient.h" # include "virnetserverservice.h" -# include "virobject.h" -# include "virjson.h" - -virNetServerPtr virNetServerNew(size_t min_workers, - size_t max_workers, - size_t priority_workers, - size_t max_clients, - size_t max_anonymous_clients, - int keepaliveInterval, - unsigned int keepaliveCount, - bool keepaliveRequired, - const char *mdnsGroupName, - virNetServerClientPrivNew clientPrivNew, - virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, - virFreeCallback clientPrivFree, - void *clientPrivOpaque); - -virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object, - virNetServerClientPrivNew clientPrivNew, - virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart, - virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, - virFreeCallback clientPrivFree, - void *clientPrivOpaque); +# include "virnetsubserver.h" + +virNetServerPtr virNetServerNew(const char *mdnsGroupName); + +int virNetServerAddSubServer(virNetServerPtr srv, + size_t min_workers, + size_t max_workers, + size_t priority_workers, + size_t max_clients, + size_t max_anonymous_clients, + int keepaliveInterval, + unsigned int keepaliveCount, + bool keepaliveRequired, + virNetServerClientPrivNew clientPrivNew, + virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, + virFreeCallback clientPrivFree, + void *clientPrivOpaque); + +int virNetServerAddSubServerPostExec(virNetServerPtr srv, + virNetServerClientPrivNew clientPrivNew, + virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart, + virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, + virFreeCallback clientPrivFree, + void *clientPrivOpaque); + +virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object);
virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv);
@@ -76,10 +81,12 @@ int virNetServerAddSignalHandler(virNetServerPtr srv, void *opaque);
int virNetServerAddService(virNetServerPtr srv, + int subServerID, virNetServerServicePtr svc, const char *mdnsEntryName);
int virNetServerAddProgram(virNetServerPtr srv, + int subServerID, virNetServerProgramPtr prog);
How about just moving these two methods to take the virNetSubServerPtr as their first arg, instead of needing to pass virNetServer + subServerID ? Not a big deal either way though. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Fri, Apr 17, 2015 at 11:22:32AM +0100, Daniel P. Berrange wrote:
On Thu, Apr 16, 2015 at 04:46:39PM +0200, Martin Kletzander wrote:
Each subserver has its own RPC programs, services, workers, keepalive, clients etc. Hence (possible) multiple subservers are properly separated.
The part in remote.c is just mechanical, the same applies to most of the code movement from virnetserver.c to virnetsubserver.c.
So, the problem we're facing here is that virNetServer is really filling two distinct roles in one class - it is the thing that manages the overall daemon process state, as well as managing the server connection/services.
So the splitting up you're doing does rather make sense. I wonder if we could name it differently though. eg have virNetDaemon to handle the process level stuff, and virNetServer to handle the network level stuff. So what is in virnetserver.c moves to virnetdaemon.c and your new virnetsubserver.c becomes the new virnetserver.c
Your naming makes more sense to me, I'll switch to that. [...]
@@ -76,10 +81,12 @@ int virNetServerAddSignalHandler(virNetServerPtr srv, void *opaque);
int virNetServerAddService(virNetServerPtr srv, + int subServerID, virNetServerServicePtr svc, const char *mdnsEntryName);
int virNetServerAddProgram(virNetServerPtr srv, + int subServerID, virNetServerProgramPtr prog);
How about just moving these two methods to take the virNetSubServerPtr as their first arg, instead of needing to pass virNetServer + subServerID ? Not a big deal either way though.
Because that was a really old and stupid idea :D Not dealing with the ID is better and more readable. I wanted to have better identifier than integer, but I don't know whether using string would be worth it.

Since this is just a new option for gendispatch, it looks more like a cleanup. The only differences handled by it are connect pointers, private pointers and API naming customs. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/rpc/gendispatch.pl | 128 ++++++++++++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 50 deletions(-) diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 199b38f..683bb92 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -49,6 +49,8 @@ my $procprefix = shift or die "missing procedure prefix argument"; my $protocol = shift or die "missing protocol argument"; my @autogen; +my $connect_ptr = $structprefix eq "admin" ? "virAdmConnectPtr" : "virConnectPtr"; +my $prefix = ($structprefix eq "admin") ? "adm" : "vir"; sub fixup_name { my $name = shift; @@ -78,9 +80,12 @@ sub fixup_name { # Convert name_of_call to NameOfCall. sub name_to_ProcName { my $name = shift; + my $forcefix = $structprefix eq "admin"; my @elems; - if ($name =~ /_/ || (lc $name) eq "open" || (lc $name) eq "close") { + + if ($forcefix || $name =~ /_/ || + (lc $name) eq "open" || (lc $name) eq "close") { @elems = split /_/, $name; @elems = map lc, @elems; @elems = map ucfirst, @elems; @@ -104,6 +109,19 @@ sub name_to_TypeName { return $typename; } +sub push_privconn { + my $args = shift; + + if (!@$args) { + if ($structprefix eq "admin") { + push(@$args, "priv->srv"); + } else { + push(@$args, "priv->conn"); + } + } +} + + # Read the input file (usually remote_protocol.x) and form an # opinion about the name, args and return type of each RPC. my ($name, $ProcName, $id, $flags, %calls, @calls, %opts); @@ -506,16 +524,11 @@ elsif ($mode eq "server") { " virObjectUnref(snapshot);\n" . " virObjectUnref(dom);"); } elsif ($args_member =~ m/^(?:remote_string|remote_uuid) (\S+)<\S+>;/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } - + push_privconn(\@args_list); push(@args_list, "args->$1.$1_val"); push(@args_list, "args->$1.$1_len"); } elsif ($args_member =~ m/^(?:opaque|remote_nonnull_string) (\S+)<\S+>;(.*)$/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); my $cast = ""; my $arg_name = $1; @@ -532,9 +545,7 @@ elsif ($mode eq "server") { push(@args_list, "${cast}args->$arg_name.${arg_name}_val"); push(@args_list, "args->$arg_name.${arg_name}_len"); } elsif ($args_member =~ m/^(?:unsigned )?int (\S+)<\S+>;/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); push(@args_list, "args->$1.$1_val"); push(@args_list, "args->$1.$1_len"); @@ -556,35 +567,25 @@ elsif ($mode eq "server") { # just make all other array types fail die "unhandled type for argument value: $args_member"; } elsif ($args_member =~ m/^remote_uuid (\S+);/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); push(@args_list, "(unsigned char *) args->$1"); } elsif ($args_member =~ m/^remote_string (\S+);/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); push(@vars_list, "char *$1"); push(@optionals_list, "$1"); push(@args_list, "$1"); } elsif ($args_member =~ m/^remote_nonnull_string (\S+);/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); push(@args_list, "args->$1"); } elsif ($args_member =~ m/^(unsigned )?int (\S+);/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); push(@args_list, "args->$2"); } elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) { - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); my $arg_name = $2; @@ -819,9 +820,7 @@ elsif ($mode eq "server") { die "multi-return-value without insert@<offset> annotation: $call->{ret}"; } - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); my $struct_name = $call->{ProcName}; $struct_name =~ s/Get//; @@ -871,7 +870,12 @@ elsif ($mode eq "server") { foreach my $var (@vars_list) { print " $var;\n"; } - print " struct daemonClientPrivate *priv =\n"; + + if ($structprefix eq "admin") { + print " struct daemonAdmClientPrivate *priv =\n"; + } else { + print " struct daemonClientPrivate *priv =\n"; + } print " virNetServerClientGetPrivateData(client);\n"; if ($call->{streamflag} ne "none") { @@ -880,7 +884,13 @@ elsif ($mode eq "server") { } print "\n"; - print " if (!priv->conn) {\n"; + + if ($structprefix eq "admin") { + print " if (!priv->srv) {\n"; + } else { + print " if (!priv->conn) {\n"; + } + print " virReportError(VIR_ERR_INTERNAL_ERROR, \"%s\", _(\"connection not open\"));\n"; print " goto cleanup;\n"; print " }\n"; @@ -919,18 +929,15 @@ elsif ($mode eq "server") { } if ($rettype eq "void") { - print " if (vir$call->{ProcName}("; + print " if ($prefix$call->{ProcName}("; print join(', ', @args_list); print ") < 0)\n"; print " goto cleanup;\n"; print "\n"; } elsif (!$multi_ret) { - my $prefix = ""; my $proc_name = $call->{ProcName}; - if (! @args_list) { - push(@args_list, "priv->conn"); - } + push_privconn(\@args_list); if ($structprefix eq "qemu" && $call->{ProcName} =~ /^(Connect)?Domain/) { @@ -949,7 +956,7 @@ elsif ($mode eq "server") { } if ($single_ret_by_ref) { - print " if (vir$prefix$proc_name("; + print " if ($prefix$proc_name("; print join(', ', @args_list); if (defined $single_ret_var) { @@ -958,7 +965,7 @@ elsif ($mode eq "server") { print ") < 0)\n"; } else { - print " if (($single_ret_var = vir$prefix$proc_name("; + print " if (($single_ret_var = $prefix$proc_name("; print join(', ', @args_list); print "))$single_ret_check)\n"; } @@ -1241,14 +1248,14 @@ elsif ($mode eq "client") { } if ($is_first_arg and $priv_src eq "conn") { - unshift(@args_list, "virConnectPtr conn"); + unshift(@args_list, "$connect_ptr conn"); } $is_first_arg = 0; } } - if (! @args_list) { + if (($structprefix ne "admin") && !@args_list) { push(@args_list, "virConnectPtr conn"); } @@ -1442,7 +1449,11 @@ elsif ($mode eq "client") { my $proc = $call->{ProcName}; my $extra = $structprefix; $extra =~ s/^(\w)/uc $1/e; - $proc =~ s/^(Domain)(.*)/$1 . $extra . $2/e; + if ($structprefix eq "admin") { + $proc = $extra . $proc; + } else { + $proc =~ s/^(Domain)(.*)/$1 . $extra . $2/e; + } print "remote$proc("; } @@ -1451,7 +1462,11 @@ elsif ($mode eq "client") { print ")\n"; print "{\n"; print " $single_ret_var;\n"; - print " struct private_data *priv = $priv_src->privateData;\n"; + if ($structprefix eq "admin") { + print " remoteAdminPrivPtr priv = $priv_src->privateData;\n"; + } else { + print " struct private_data *priv = $priv_src->privateData;\n"; + } foreach my $var (@vars_list) { print " $var;\n"; @@ -1466,7 +1481,11 @@ elsif ($mode eq "client") { } print "\n"; - print " remoteDriverLock(priv);\n"; + if ($structprefix eq "admin") { + print " remoteAdminLock(priv);\n"; + } else { + print " remoteDriverLock(priv);\n"; + } if ($call->{streamflag} ne "none") { print "\n"; @@ -1546,8 +1565,12 @@ elsif ($mode eq "client") { $callflags = "REMOTE_CALL_LXC"; } + if ($structprefix ne "admin") { + $priv_src = "$priv_src, priv"; + } + print "\n"; - print " if (call($priv_src, priv, $callflags, $call->{constname},\n"; + print " if (call($priv_src, $callflags, $call->{constname},\n"; print " (xdrproc_t)xdr_$argtype, (char *)$call_args,\n"; print " (xdrproc_t)xdr_$rettype, (char *)$call_ret) == -1) {\n"; @@ -1622,7 +1645,12 @@ elsif ($mode eq "client") { print join("\n", @free_list); - print " remoteDriverUnlock(priv);\n"; + if ($structprefix eq "admin") { + print " remoteAdminUnlock(priv);\n"; + } else { + print " remoteDriverUnlock(priv);\n"; + } + print " return rv;\n"; print "}\n"; } @@ -1682,7 +1710,7 @@ elsif ($mode eq "client") { next if $call->{acl}->[0] eq "none"; if ($mode eq "aclsym") { - my $apiname = "vir" . $call->{ProcName}; + my $apiname = $prefix . $call->{ProcName}; if ($structprefix eq "qemu") { $apiname =~ s/(vir(Connect)?Domain)/${1}Qemu/; } elsif ($structprefix eq "lxc") { @@ -1722,7 +1750,7 @@ elsif ($mode eq "client") { } } - my $apiname = "vir" . $call->{ProcName}; + my $apiname = $prefix . $call->{ProcName}; if ($structprefix eq "qemu") { $apiname =~ s/(vir(Connect)?Domain)/${1}Qemu/; } elsif ($structprefix eq "lxc") { @@ -1735,7 +1763,7 @@ elsif ($mode eq "client") { $object =~ s/^(\w)/uc $1/e; $object =~ s/_(\w)/uc $1/e; $object =~ s/Nwfilter/NWFilter/; - my $objecttype = "vir" . $object . "DefPtr"; + my $objecttype = $prefix . $object . "DefPtr"; $apiname .= $action . "ACL"; if ($arg eq "interface") { @@ -1743,7 +1771,7 @@ elsif ($mode eq "client") { } my @argdecls; - push @argdecls, "virConnectPtr conn"; + push @argdecls, "$connect_ptr conn"; if ($object ne "Connect") { if ($object eq "StorageVol") { push @argdecls, "virStoragePoolDefPtr pool"; @@ -1834,7 +1862,7 @@ elsif ($mode eq "client") { sub generate_aclapi { my $call = shift; - my $apiname = "vir" . $call->{ProcName}; + my $apiname = $prefix . $call->{ProcName}; if ($structprefix eq "qemu") { $apiname =~ s/(vir(Connect)?Domain)/${1}Qemu/; } elsif ($structprefix eq "lxc") { -- 2.3.5

For now there's only CONNECT_OPEN procedure. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- .gitignore | 1 + cfg.mk | 2 +- src/Makefile.am | 13 +++++++++- src/admin/admin_protocol.x | 60 ++++++++++++++++++++++++++++++++++++++++++++++ src/admin_protocol-structs | 8 +++++++ 5 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 src/admin/admin_protocol.x create mode 100644 src/admin_protocol-structs diff --git a/.gitignore b/.gitignore index 9d09709..56916cf 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,7 @@ /src/access/viraccessapichecklxc.h /src/access/viraccessapicheckqemu.c /src/access/viraccessapicheckqemu.h +/src/admin/admin_protocol.[ch] /src/esx/*.generated.* /src/hyperv/*.generated.* /src/libvirt*.def diff --git a/cfg.mk b/cfg.mk index 9ba2134..09803e4 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1,5 +1,5 @@ # Customize Makefile.maint. -*- makefile -*- -# Copyright (C) 2008-2014 Red Hat, Inc. +# Copyright (C) 2008-2015 Red Hat, Inc. # Copyright (C) 2003-2008 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify diff --git a/src/Makefile.am b/src/Makefile.am index d6245bd..b1044a7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -393,6 +393,16 @@ REMOTE_DRIVER_SOURCES = \ EXTRA_DIST += $(REMOTE_DRIVER_PROTOCOL) \ $(REMOTE_DRIVER_GENERATED) +ADMIN_PROTOCOL = $(srcdir)/admin/admin_protocol.x + +ADMIN_PROTOCOL_GENERATED = \ + admin/admin_protocol.c \ + admin/admin_protocol.h + +EXTRA_DIST += $(ADMIN_PROTOCOL) $(ADMIN_PROTOCOL_GENERATED) +BUILT_SOURCES += $(ADMIN_PROTOCOL_GENERATED) +MAINTAINERCLEANFILES += $(ADMIN_PROTOCOL_GENERATED) + # Ensure that we don't change the struct or member names or member ordering # in remote_protocol.x The embedded perl below needs a few comments, and # presumes you know what pdwtags output looks like: @@ -2070,7 +2080,8 @@ RPC_PROBE_FILES = $(srcdir)/rpc/virnetprotocol.x \ $(srcdir)/remote/lxc_protocol.x \ $(srcdir)/remote/qemu_protocol.x \ $(srcdir)/lxc/lxc_monitor_protocol.x \ - $(srcdir)/locking/lock_protocol.x + $(srcdir)/locking/lock_protocol.x \ + $(srcdir)/admin/admin_protocol.x libvirt_functions.stp: $(RPC_PROBE_FILES) $(srcdir)/rpc/gensystemtap.pl $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gensystemtap.pl $(RPC_PROBE_FILES) > $@ diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x new file mode 100644 index 0000000..3e1b28e --- /dev/null +++ b/src/admin/admin_protocol.x @@ -0,0 +1,60 @@ +/* -*- c -*- + * admin_protocol.x: private protocol for communicating between + * remote_internal driver and libvirtd. This protocol is + * internal and may change at any time. + * + * 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@redhat.com> + */ + +%#include "remote_protocol.h" + + +/*----- Protocol. -----*/ +struct admin_connect_open_args { + unsigned int flags; +}; + + +/* Define the program number, protocol version and procedure numbers here. */ +const ADMIN_PROGRAM = 0x06900690; +const ADMIN_PROTOCOL_VERSION = 1; + +enum admin_procedure { + /* Each function must be preceded by a comment providing one or + * more annotations: + * + * - @generate: none|client|server|both + * + * Whether to generate the dispatch stubs for the server + * and/or client code. + * + * - @readstream: paramnumber + * - @writestream: paramnumber + * + * The @readstream or @writestream annotations let daemon and src/remote + * create a stream. The direction is defined from the src/remote point + * of view. A readstream transfers data from daemon to src/remote. The + * <paramnumber> specifies at which offset the stream parameter is inserted + * in the function parameter list. + */ + /** + * @generate: none + */ + ADMIN_PROC_CONNECT_OPEN = 1 +}; diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs new file mode 100644 index 0000000..6b2460d --- /dev/null +++ b/src/admin_protocol-structs @@ -0,0 +1,8 @@ +/* -*- c -*- */ +struct admin_connect_open_args { + unsigned int flags; +}; + +enum admin_procedure { + ADMIN_PROC_CONNECT_OPEN = 1, +}; -- 2.3.5

Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- .gitignore | 1 + cfg.mk | 5 ++++- src/Makefile.am | 9 ++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 56916cf..0f8b3d6 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,7 @@ /src/access/viraccessapichecklxc.h /src/access/viraccessapicheckqemu.c /src/access/viraccessapicheckqemu.h +/src/admin/admin_client.h /src/admin/admin_protocol.[ch] /src/esx/*.generated.* /src/hyperv/*.generated.* diff --git a/cfg.mk b/cfg.mk index 09803e4..8f20f9b 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1070,13 +1070,16 @@ bracket-spacing-check: sc_po_check: \ $(srcdir)/daemon/remote_dispatch.h \ $(srcdir)/daemon/qemu_dispatch.h \ - $(srcdir)/src/remote/remote_client_bodies.h + $(srcdir)/src/remote/remote_client_bodies.h \ + $(srcdir)/src/admin/admin_client.h $(srcdir)/daemon/remote_dispatch.h: $(srcdir)/src/remote/remote_protocol.x $(MAKE) -C daemon remote_dispatch.h $(srcdir)/daemon/qemu_dispatch.h: $(srcdir)/src/remote/qemu_protocol.x $(MAKE) -C daemon qemu_dispatch.h $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protocol.x $(MAKE) -C src remote/remote_client_bodies.h +$(srcdir)/src/admin/admin_client.h: $(srcdir)/src/admin/admin_protocol.x + $(MAKE) -C src admin/admin_client.h # List all syntax-check exemptions: exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$ diff --git a/src/Makefile.am b/src/Makefile.am index b1044a7..6813554 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -397,7 +397,14 @@ ADMIN_PROTOCOL = $(srcdir)/admin/admin_protocol.x ADMIN_PROTOCOL_GENERATED = \ admin/admin_protocol.c \ - admin/admin_protocol.h + admin/admin_protocol.h \ + admin/admin_client.h + +admin/admin_client.h: $(srcdir)/rpc/gendispatch.pl \ + $(ADMIN_PROTOCOL) Makefile.am + $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gendispatch.pl --mode=client \ + admin ADMIN $(ADMIN_PROTOCOL) \ + > $(srcdir)/admin/admin_client.h EXTRA_DIST += $(ADMIN_PROTOCOL) $(ADMIN_PROTOCOL_GENERATED) BUILT_SOURCES += $(ADMIN_PROTOCOL_GENERATED) -- 2.3.5

Just the addition of VIR_FROM_ADMIN to the enum of error domains. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- include/libvirt/virterror.h | 3 ++- src/util/virerror.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 9c5b069..6325030 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -4,7 +4,7 @@ * Description: Provides the interfaces of the libvirt library to handle * errors raised while using the library. * - * Copyright (C) 2006, 2010-2012 Red Hat, Inc. + * Copyright (C) 2006-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 @@ -126,6 +126,7 @@ typedef enum { VIR_FROM_POLKIT = 60, /* Error from polkit code */ VIR_FROM_THREAD = 61, /* Error from thread utils */ + VIR_FROM_ADMIN = 62, /* Error from admin backend */ # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST diff --git a/src/util/virerror.c b/src/util/virerror.c index 8696e31..18c6c2a 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -134,6 +134,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, "Polkit", /* 60 */ "Thread jobs", + "Admin Interface", ) -- 2.3.5

Initial scratch of the admin library. It has its own virAdmConnectPtr that inherits from virAbstractConnectPtr and thus trivially supports error reporting. Configuration option --with-admin is added to control whether the admin library should be built or not (set to 'yes' by default). There's pkg-config file added and spec-file adjusted as well. Since the library should be "minimalistic" and not depend on any other library, the list of files is especially crafted for it. Most of them could've been put to it's own sub-libraries that would be LIBADD'd to libvirt_util, libvirt_net_rpc and libvirt_setuid_rpc_client to minimize the number of object files being built, but that's a refactoring that isn't the orginal aim of this commit. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- cfg.mk | 1 + configure.ac | 12 ++ include/libvirt/Makefile.am | 6 +- include/libvirt/libvirt-admin.h | 62 ++++++++ libvirt-admin.pc.in | 13 ++ libvirt.spec.in | 7 + src/Makefile.am | 109 ++++++++++++- src/datatypes.c | 30 ++++ src/datatypes.h | 37 +++++ src/internal.h | 1 + src/libvirt-admin.c | 337 ++++++++++++++++++++++++++++++++++++++++ src/libvirt_admin.syms | 18 +++ 12 files changed, 631 insertions(+), 2 deletions(-) create mode 100644 include/libvirt/libvirt-admin.h create mode 100644 libvirt-admin.pc.in create mode 100644 src/libvirt-admin.c create mode 100644 src/libvirt_admin.syms diff --git a/cfg.mk b/cfg.mk index 8f20f9b..b948b7a 100644 --- a/cfg.mk +++ b/cfg.mk @@ -304,6 +304,7 @@ sc_flags_usage: $(srcdir)/include/libvirt/virterror.h \ $(srcdir)/include/libvirt/libvirt-qemu.h \ $(srcdir)/include/libvirt/libvirt-lxc.h \ + $(srcdir)/include/libvirt/libvirt-admin.h \ | grep -c '\(long\|unsigned\) flags')" != 4 && \ { echo '$(ME): new API should use "unsigned int flags"' 1>&2; \ exit 1; } || : diff --git a/configure.ac b/configure.ac index aed0934..d13f825 100644 --- a/configure.ac +++ b/configure.ac @@ -583,6 +583,10 @@ AC_ARG_WITH([pm-utils], [AS_HELP_STRING([--with-pm-utils], [use pm-utils for power management @<:@default=yes@:>@])]) m4_divert_text([DEFAULTS], [with_pm_utils=check]) +AC_ARG_WITH([admin], + [AS_HELP_STRING([--with-admin], + [build admin library @<:@default=yes@:>@])]) +m4_divert_text([DEFAULTS], [with_admin=yes]) dnl dnl in case someone want to build static binaries @@ -821,6 +825,10 @@ if test "$with_libvirtd" = "yes" ; then fi AM_CONDITIONAL([WITH_LIBVIRTD], [test "$with_libvirtd" = "yes"]) +if test "$with_admin" = "yes" ; then + AC_DEFINE_UNQUOTED([WITH_ADMIN], 1, [whether admin library is built]) +fi +AM_CONDITIONAL([WITH_ADMIN], [test "$with_admin" = "yes"]) old_LIBS="$LIBS" old_CFLAGS="$CFLAGS" @@ -2358,6 +2366,7 @@ WIN32_EXTRA_CFLAGS= dnl libvirt.syms is generated in builddir, but libvirt_qemu.syms is in git; dnl hence the asymmetric naming of these two symbol files. LIBVIRT_SYMBOL_FILE=libvirt.syms +LIBVIRT_ADMIN_SYMBOL_FILE='$(srcdir)/libvirt_admin.syms' LIBVIRT_LXC_SYMBOL_FILE='$(srcdir)/libvirt_lxc.syms' LIBVIRT_QEMU_SYMBOL_FILE='$(srcdir)/libvirt_qemu.syms' MSCOM_LIBS= @@ -2388,6 +2397,7 @@ case "$host" in # Also set the symbol file to .def, so src/Makefile generates libvirt.def # from libvirt.syms and passes libvirt.def instead of libvirt.syms to the linker LIBVIRT_SYMBOL_FILE=libvirt.def + LIBVIRT_ADMIN_SYMBOL_FILE=libvirt_admin.def LIBVIRT_LXC_SYMBOL_FILE=libvirt_lxc.def LIBVIRT_QEMU_SYMBOL_FILE=libvirt_qemu.def # mingw's ld has the --version-script parameter, but it requires a .def file @@ -2403,6 +2413,7 @@ AC_SUBST([CYGWIN_EXTRA_LIBADD]) AC_SUBST([MINGW_EXTRA_LDFLAGS]) AC_SUBST([WIN32_EXTRA_CFLAGS]) AC_SUBST([LIBVIRT_SYMBOL_FILE]) +AC_SUBST([LIBVIRT_ADMIN_SYMBOL_FILE]) AC_SUBST([LIBVIRT_LXC_SYMBOL_FILE]) AC_SUBST([LIBVIRT_QEMU_SYMBOL_FILE]) AC_SUBST([VERSION_SCRIPT_FLAGS]) @@ -2980,6 +2991,7 @@ AC_MSG_NOTICE([ XML Catalog: $XML_CATALOG_FILE]) AC_MSG_NOTICE([ Init script: $with_init_script]) AC_MSG_NOTICE([Char device locks: $with_chrdev_lock_files]) AC_MSG_NOTICE([ Default Editor: $DEFAULT_EDITOR]) +AC_MSG_NOTICE([ Admin library: $with_admin]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([Developer Tools]) AC_MSG_NOTICE([]) diff --git a/include/libvirt/Makefile.am b/include/libvirt/Makefile.am index 8aee5d7..03c7ed7 100644 --- a/include/libvirt/Makefile.am +++ b/include/libvirt/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -## Copyright (C) 2005-2011, 2013 Red Hat, Inc. +## Copyright (C) 2005-2011, 2013, 2014 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 @@ -34,6 +34,10 @@ virinc_HEADERS = libvirt.h \ libvirt-qemu.h \ virterror.h +#if WITH_ADMIN +virinc_HEADERS += libvirt-admin.h +#endif WITH_ADMIN + install-exec-hook: $(mkinstalldirs) $(DESTDIR)$(virincdir) diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h new file mode 100644 index 0000000..7fe03cf --- /dev/null +++ b/include/libvirt/libvirt-admin.h @@ -0,0 +1,62 @@ +/* + * libvirt-admin.h: Admin interface for libvirt + * Summary: Interfaces for handling server-related tasks + * Description: Provides the interfaces of the libvirt library to operate + * with the server itself, not any hypervisors. + * + * 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@redhat.com> + */ + +#ifndef __VIR_ADMIN_H__ +# define __VIR_ADMIN_H__ + +# include "internal.h" + +# ifdef __cplusplus +extern "C" { +# endif + + +/** + * virAdmConnect: + * + * a virAdmConnect is a private structure representing a connection to + * libvirt daemon. + */ +typedef struct _virAdmConnect virAdmConnect; + +/** + * virAdmConnectPtr: + * + * a virAdmConnectPtr is pointer to a virAdmConnect private structure, + * this is the type used to reference a connection to the daemon + * in the API. + */ +typedef virAdmConnect *virAdmConnectPtr; + +virAdmConnectPtr virAdmConnectOpen(unsigned int flags); +int virAdmConnectClose(virAdmConnectPtr conn); + +int virAdmConnectRef(virAdmConnectPtr conn); + +# ifdef __cplusplus +} +# endif + +#endif /* __VIR_ADMIN_H__ */ diff --git a/libvirt-admin.pc.in b/libvirt-admin.pc.in new file mode 100644 index 0000000..76126ae --- /dev/null +++ b/libvirt-admin.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ + +libvirt_admin_api=@datadir@/libvirt/api/libvirt-admin-api.xml + +Name: libvirt-admin +Version: @VERSION@ +Description: libvirt admin library +Libs: -L${libdir} -lvirt-admin +Cflags: -I${includedir} diff --git a/libvirt.spec.in b/libvirt.spec.in index e08c9e7..153786c 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2178,6 +2178,12 @@ exit 0 %attr(0755, root, root) %{_libexecdir}/libvirt_sanlock_helper %endif +%if %{with_admin} +%files admin +%defattr(-, root, root) +%{_libdir}/%{name}/libvirt_admin.so +%endif + %files client -f %{name}.lang %defattr(-, root, root) %doc COPYING COPYING.LESSER @@ -2270,6 +2276,7 @@ exit 0 %{_includedir}/libvirt/libvirt-stream.h %{_includedir}/libvirt/libvirt-qemu.h %{_includedir}/libvirt/libvirt-lxc.h +%{_includedir}/libvirt/libvirt-admin.h %{_libdir}/pkgconfig/libvirt.pc %{_libdir}/pkgconfig/libvirt-qemu.pc %{_libdir}/pkgconfig/libvirt-lxc.pc diff --git a/src/Makefile.am b/src/Makefile.am index 6813554..4c56e72 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -502,6 +502,7 @@ PROTOCOL_STRUCTS = \ $(srcdir)/virkeepaliveprotocol-structs \ $(srcdir)/lxc_monitor_protocol-structs \ $(srcdir)/lock_protocol-structs \ + $(srcdir)/admin_protocol-structs \ $(NULL) if WITH_REMOTE @@ -523,6 +524,9 @@ $(srcdir)/lxc_monitor_protocol-struct: \ $(srcdir)/lock_protocol-struct: \ $(srcdir)/%-struct: locking/lockd_la-%.lo $(PDWTAGS) +$(srcdir)/admin_protocol-struct: \ + $(srcdir)/%-struct: admin/libvirt_admin_la-%.lo + $(PDWTAGS) else !WITH_REMOTE # The $(PROTOCOL_STRUCTS) files must live in git, because they cannot be @@ -535,6 +539,7 @@ check-drivername: $(AM_V_GEN)$(PERL) $(srcdir)/check-drivername.pl \ $(srcdir)/driver.h \ $(srcdir)/libvirt_public.syms \ + $(srcdir)/libvirt_admin.syms \ $(srcdir)/libvirt_qemu.syms \ $(srcdir)/libvirt_lxc.syms @@ -1091,6 +1096,7 @@ USED_SYM_FILES = $(srcdir)/libvirt_private.syms GENERATED_SYM_FILES = \ $(ACCESS_DRIVER_SYM_FILES) \ libvirt.syms libvirt.def libvirt_qemu.def libvirt_lxc.def \ + libvirt_admin.def \ $(NULL) if WITH_TEST @@ -1794,7 +1800,8 @@ EXTRA_DIST += \ $(VBOX_DRIVER_EXTRA_DIST) \ $(VMWARE_DRIVER_SOURCES) \ $(XENCONFIG_SOURCES) \ - $(ACCESS_DRIVER_POLKIT_POLICY) + $(ACCESS_DRIVER_POLKIT_POLICY) \ + $(libvirt_admin_la_SOURCES) check-local: check-augeas @@ -1977,6 +1984,7 @@ EXTRA_DIST += \ libvirt_public.syms \ libvirt_lxc.syms \ libvirt_qemu.syms \ + libvirt_admin.syms \ $(SYM_FILES) \ $(NULL) @@ -2020,6 +2028,105 @@ libvirt_lxc.def: $(srcdir)/libvirt_lxc.syms chmod a-w $@-tmp && \ mv $@-tmp libvirt_lxc.def +libvirt_admin.def: $(srcdir)/libvirt_admin.syms + $(AM_V_GEN)rm -f -- $@-tmp $@ ; \ + printf 'EXPORTS\n' > $@-tmp && \ + sed -e '/^$$/d; /#/d; /:/d; /}/d; /\*/d; /LIBVIRT_/d' \ + -e 's/[ ]*\(.*\)\;/ \1/g' $^ >> $@-tmp && \ + chmod a-w $@-tmp && \ + mv $@-tmp libvirt_admin.def + +if WITH_ADMIN +lib_LTLIBRARIES += libvirt-admin.la +libvirt_admin_la_SOURCES = \ + libvirt-admin.c \ + $(ADMIN_PROTOCOL_GENERATED) + +libvirt_admin_la_SOURCES += \ + datatypes.c \ + util/viralloc.c \ + util/viratomic.c \ + util/virauth.c \ + util/virauthconfig.c \ + util/virbitmap.c \ + util/virbuffer.c \ + util/vircommand.c \ + util/virerror.c \ + util/virevent.c \ + util/vireventpoll.c \ + util/virfile.c \ + util/virhash.c \ + util/virhashcode.c \ + util/virjson.c \ + util/virkeyfile.c \ + util/virlog.c \ + util/virobject.c \ + util/virpidfile.c \ + util/virprocess.c \ + util/virrandom.c \ + util/virseclabel.c \ + util/virsocketaddr.c \ + util/virstorageencryption.c \ + util/virstoragefile.c \ + util/virstring.c \ + util/virthread.c \ + util/virtime.c \ + util/virtypedparam.c \ + util/viruri.c \ + util/virutil.c \ + util/viruuid.c \ + util/virxml.c \ + remote/remote_protocol.c \ + rpc/virnetmessage.h \ + rpc/virnetmessage.c \ + rpc/virnetsocket.c \ + rpc/virnetsshsession.c \ + rpc/virkeepalive.c \ + rpc/virnetclient.c \ + rpc/virnetclientprogram.c \ + rpc/virnetclientstream.c \ + rpc/virnetprotocol.c \ + rpc/virnettlscontext.c \ + rpc/virnetsaslcontext.c + +libvirt_admin_la_LDFLAGS = \ + $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_ADMIN_SYMBOL_FILE) \ + -version-info $(LIBVIRT_VERSION_INFO) \ + $(AM_LDFLAGS) \ + $(CYGWIN_EXTRA_LDFLAGS) \ + $(MINGW_EXTRA_LDFLAGS) + +libvirt_admin_la_LIBADD = \ + $(CYGWIN_EXTRA_LIBADD) + +libvirt_admin_la_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(srcdir)/remote \ + -I$(srcdir)/rpc \ + -I$(srcdir)/admin + +libvirt_admin_la_CFLAGS += \ + $(CAPNG_CFLAGS) \ + $(YAJL_CFLAGS) \ + $(SSH2_CFLAGS) \ + $(SASL_CFLAGS) \ + $(GNUTLS_CFLAGS) + +libvirt_admin_la_LIBADD += \ + $(CAPNG_LIBS) \ + $(YAJL_LIBS) \ + $(DEVMAPPER_LIBS) \ + $(LIBXML_LIBS) \ + $(SSH2_LIBS) \ + $(SASL_LIBS) \ + $(GNUTLS_LIBS) + +if WITH_DTRACE_PROBES +libvirt_admin_la_LIBADD += libvirt_probes.lo +endif WITH_DTRACE_PROBES + +endif WITH_ADMIN + # Empty source list - it merely links a bunch of convenience libs together libvirt_la_SOURCES = libvirt_la_LDFLAGS = \ diff --git a/src/datatypes.c b/src/datatypes.c index b21113e..83cee7e 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -59,6 +59,10 @@ static void virStreamDispose(void *obj); static void virStorageVolDispose(void *obj); static void virStoragePoolDispose(void *obj); +virClassPtr virAdmConnectClass; + +static void virAdmConnectDispose(void *obj); + static int virDataTypesOnceInit(void) { @@ -88,6 +92,8 @@ virDataTypesOnceInit(void) DECLARE_CLASS(virStorageVol); DECLARE_CLASS(virStoragePool); + DECLARE_CLASS_CONNECT(virAdmConnect); + #undef DECLARE_CLASS_COMMON #undef DECLARE_CLASS_LOCKABLE #undef DECLARE_CLASS_CONNECT @@ -804,3 +810,27 @@ virDomainSnapshotDispose(void *obj) VIR_FREE(snapshot->name); virObjectUnref(snapshot->domain); } + + +virAdmConnectPtr +virAdmConnectNew(void) +{ + virAdmConnectPtr ret; + + if (virDataTypesInitialize() < 0) + return NULL; + + if (!(ret = virGetAbstractConnect(virAdmConnectClass))) + return NULL; + + return ret; +} + +static void +virAdmConnectDispose(void *obj) +{ + virAdmConnectPtr conn = obj; + + if (conn->privateDataFreeFunc) + conn->privateDataFreeFunc(conn->privateData); +} diff --git a/src/datatypes.h b/src/datatypes.h index 9f95811..b240e4c 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -42,6 +42,8 @@ extern virClassPtr virStreamClass; extern virClassPtr virStorageVolClass; extern virClassPtr virStoragePoolClass; +extern virClassPtr virAdmConnectClass; + # define virCheckConnectReturn(obj, retval) \ do { \ if (!virObjectIsClass(obj, virConnectClass)) { \ @@ -296,6 +298,26 @@ extern virClassPtr virStoragePoolClass; dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \ } while (0) +# define virCheckAdmConnectReturn(obj, retval) \ + do { \ + if (!virObjectIsClass(obj, virAdmConnectClass)) { \ + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INVALID_CONN, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + virDispatchError(NULL); \ + return retval; \ + } \ + } while (0) +# define virCheckAdmConnectGoto(obj, label) \ + do { \ + if (!virObjectIsClass(obj, virAdmConnectClass)) { \ + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INVALID_CONN, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + goto label; \ + } \ + } while (0) + /** * VIR_DOMAIN_DEBUG: * @dom: domain @@ -365,6 +387,19 @@ struct _virConnect { }; /** + * _virAdmConnect: + * + * Internal structure associated to an admin connection + */ +struct _virAdmConnect { + virAbstractConnect object; + + void *privateData; + virFreeCallback privateDataFreeFunc; +}; + + +/** * _virDomain: * * Internal structure associated to a domain @@ -545,4 +580,6 @@ virNWFilterPtr virGetNWFilter(virConnectPtr conn, virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain, const char *name); +virAdmConnectPtr virAdmConnectNew(void); + #endif /* __VIR_DATATYPES_H__ */ diff --git a/src/internal.h b/src/internal.h index 4d473af..1fbcfc2 100644 --- a/src/internal.h +++ b/src/internal.h @@ -58,6 +58,7 @@ # include "libvirt/libvirt.h" # include "libvirt/libvirt-lxc.h" # include "libvirt/libvirt-qemu.h" +# include "libvirt/libvirt-admin.h" # include "libvirt/virterror.h" # include "c-strcase.h" diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c new file mode 100644 index 0000000..e47089d --- /dev/null +++ b/src/libvirt-admin.c @@ -0,0 +1,337 @@ +/* + * libvirt-admin.c + * + * 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@redhat.com> + */ + +#include <config.h> + +#include <rpc/rpc.h> + +#include "internal.h" +#include "configmake.h" +#include "datatypes.h" +#include "viralloc.h" +#include "virlog.h" +#include "virstring.h" +#include "virutil.h" +#include "viruuid.h" +#include "virnetclient.h" + +#define VIR_FROM_THIS VIR_FROM_ADMIN +#define LIBVIRTD_ADMIN_UNIX_SOCKET LOCALSTATEDIR "/run/libvirt/libvirt-admin-sock" + +VIR_LOG_INIT("libvirt-admin"); + + +typedef struct _remoteAdminPriv remoteAdminPriv; +typedef remoteAdminPriv *remoteAdminPrivPtr; + +struct _remoteAdminPriv { + virMutex lock; + int counter; + int localUses; + virNetClientPtr client; + virNetClientProgramPtr program; +}; + +static void +remoteAdminLock(remoteAdminPrivPtr priv) +{ + virMutexLock(&priv->lock); +} + +static void +remoteAdminUnlock(remoteAdminPrivPtr priv) +{ + virMutexUnlock(&priv->lock); +} + +static void +remoteAdminPrivFree(void *opaque) +{ + remoteAdminPrivPtr priv = opaque; + + virObjectUnref(priv->program); + virObjectUnref(priv->client); + + virMutexDestroy(&priv->lock); + VIR_FREE(priv); +} + +static int +callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED, + remoteAdminPrivPtr priv, + int *fdin, + size_t fdinlen, + int **fdout, + size_t *fdoutlen, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret) +{ + int rv; + virNetClientProgramPtr prog; + int counter = priv->counter++; + virNetClientPtr client = priv->client; + priv->localUses++; + + /* We hav nothing else right now, but we can still add more + * programs in the future */ + prog = priv->program; + + /* Unlock, so that if we get any async events/stream data + * while processing the RPC, we don't deadlock when our + * callbacks for those are invoked + */ + remoteAdminUnlock(priv); + rv = virNetClientProgramCall(prog, + client, + counter, + proc_nr, + fdinlen, fdin, + fdoutlen, fdout, + args_filter, args, + ret_filter, ret); + remoteAdminLock(priv); + priv->localUses--; + + return rv; +} + +static int +call(virAdmConnectPtr conn, + unsigned int flags, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret) +{ + virCheckFlags(0, -1); + + return callFull(conn, conn->privateData, + NULL, 0, NULL, NULL, proc_nr, + args_filter, args, ret_filter, ret); +} + +#include "admin_protocol.h" +#include "admin_client.h" + +static bool virAdmGlobalError; +static virOnceControl virAdmGlobalOnce = VIR_ONCE_CONTROL_INITIALIZER; + +static remoteAdminPrivPtr +remoteAdminPrivNew(void) +{ + remoteAdminPrivPtr priv = NULL; + + /* initialize private data */ + if (VIR_ALLOC(priv) < 0) + goto error; + + if (virMutexInit(&priv->lock) < 0) { + VIR_FREE(priv); + goto error; + } + + priv->localUses = 1; + if (!(priv->client = virNetClientNewUNIX(LIBVIRTD_ADMIN_UNIX_SOCKET, + false, NULL))) + goto error; + + if (!(priv->program = virNetClientProgramNew(ADMIN_PROGRAM, + ADMIN_PROTOCOL_VERSION, + NULL, 0, NULL))) + goto error; + + if (virNetClientAddProgram(priv->client, priv->program) < 0) + goto error; + + return priv; + error: + remoteAdminPrivFree(priv); + return NULL; +} + +static void +virAdmGlobalInit(void) +{ + /* It would be nice if we could trace the use of this call, to + * help diagnose in log files if a user calls something other than + * virAdmConnectOpen first. But we can't rely on VIR_DEBUG working + * until after initialization is complete, and since this is + * one-shot, we never get here again. */ + if (virThreadInitialize() < 0 || + virErrorInitialize() < 0) + goto error; + + virLogSetFromEnv(); + + if (!bindtextdomain(PACKAGE, LOCALEDIR)) + goto error; + + return; + error: + virAdmGlobalError = true; +} + +/** + * virAdmInitialize: + * + * Initialize the library. + * + * Returns 0 in case of success, -1 in case of error + */ +static int +virAdmInitialize(void) +{ + if (virOnce(&virAdmGlobalOnce, virAdmGlobalInit) < 0) + return -1; + + if (virAdmGlobalError) + return -1; + + return 0; +} + +/** + * virAdmConnectOpen: + * @flags: unused, must be 0 + * + * Opens connection to admin interface of the daemon. + * + * Returns @virAdmConnectPtr object or NULL on error + */ +virAdmConnectPtr +virAdmConnectOpen(unsigned int flags) +{ + virAdmConnectPtr conn = NULL; + remoteAdminPrivPtr priv = NULL; + + if (virAdmInitialize() < 0) + goto error; + + VIR_DEBUG("flags=%x", flags); + virResetLastError(); + + if (!(conn = virAdmConnectNew())) + goto error; + + if (!(priv = remoteAdminPrivNew())) + goto error; + + remoteAdminLock(priv); + conn->privateData = priv; + conn->privateDataFreeFunc = remoteAdminPrivFree; + + { + admin_connect_open_args args = { flags }; + + VIR_DEBUG("Trying to open admin connection"); + if (call(conn, 0, ADMIN_PROC_CONNECT_OPEN, + (xdrproc_t) xdr_admin_connect_open_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto error; + } + + remoteAdminUnlock(priv); + + return conn; + error: + virDispatchError(NULL); + if (priv) + remoteAdminUnlock(priv); + virObjectUnref(conn); + return NULL; +} + +/** + * virAdmConnectClose: + * @conn: pointer to admin connection to close + * + * This function closes the connection to the Hypervisor. This should + * not be called if further interaction with the Hypervisor are needed + * especially if there is running domain which need further monitoring by + * the application. + * + * Connections are reference counted; the count is explicitly + * increased by the initial open (virConnectOpen, virConnectOpenAuth, + * and the like) as well as virConnectRef; it is also temporarily + * increased by other API that depend on the connection remaining + * alive. The open and every virConnectRef call should have a + * matching virConnectClose, and all other references will be released + * after the corresponding operation completes. + * + * Returns a positive number if at least 1 reference remains on + * success. The returned value should not be assumed to be the total + * reference count. A return of 0 implies no references remain and + * the connection is closed and memory has been freed. A return of -1 + * implies a failure. + * + * It is possible for the last virConnectClose to return a positive + * value if some other object still has a temporary reference to the + * connection, but the application should not try to further use a + * connection after the virConnectClose that matches the initial open. + */ +int +virAdmConnectClose(virAdmConnectPtr conn) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + if (!conn) + return 0; + + virCheckAdmConnectReturn(conn, -1); + + if (!virObjectUnref(conn)) + return 0; + return 1; +} + + +/** + * virAdmConnectRef: + * @conn: the connection to hold a reference on + * + * Increment the reference count on the connection. For each + * additional call to this method, there shall be a corresponding + * call to virConnectClose to release the reference count, once + * the caller no longer needs the reference to this object. + * + * This method is typically useful for applications where multiple + * threads are using a connection, and it is required that the + * connection remain open until all threads have finished using + * it. I.e., each new thread using a connection would increment + * the reference count. + * + * Returns 0 in case of success, -1 in case of failure + */ +int +virAdmConnectRef(virAdmConnectPtr conn) +{ + VIR_DEBUG("conn=%p refs=%d", conn, + conn ? conn->object.parent.parent.u.s.refs : 0); + + virResetLastError(); + virCheckAdmConnectReturn(conn, -1); + + virObjectRef(conn); + + return 0; +} diff --git a/src/libvirt_admin.syms b/src/libvirt_admin.syms new file mode 100644 index 0000000..292433f --- /dev/null +++ b/src/libvirt_admin.syms @@ -0,0 +1,18 @@ +# +# Officially exported symbols, for which header +# file definitions are installed in /usr/include/libvirt +# from libvirt-admin.h +# +# Versions here are *fixed* to match the libvirt version +# at which the symbol was introduced. This ensures that +# a new client app requiring symbol foo() can't accidentally +# run with old libvirt-admin.so not providing foo() - the global +# soname version info can't enforce this since we never +# change the soname +# +LIBVIRT_ADMIN_1.2.3 { + global: + virAdmInitialize; + virAdmConnectOpen; + virAdmConnectClose; +}; -- 2.3.5

On Thu, Apr 16, 2015 at 04:46:44PM +0200, Martin Kletzander wrote:
Initial scratch of the admin library. It has its own virAdmConnectPtr that inherits from virAbstractConnectPtr and thus trivially supports error reporting.
See my note earlier about error reporting on the connection being a bad idea due to lack of thread safety.
Configuration option --with-admin is added to control whether the admin library should be built or not (set to 'yes' by default).
Is there a compelling reason why we'd need/want to be able to disable building of the admin library ? As a comparison we unconditionally build libvirt-qemu.so & libvirt-lxc.so
diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h new file mode 100644 index 0000000..7fe03cf --- /dev/null +++ b/include/libvirt/libvirt-admin.h @@ -0,0 +1,62 @@ +/* + * libvirt-admin.h: Admin interface for libvirt + * Summary: Interfaces for handling server-related tasks + * Description: Provides the interfaces of the libvirt library to operate + * with the server itself, not any hypervisors. + * + * 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@redhat.com> + */ + +#ifndef __VIR_ADMIN_H__ +# define __VIR_ADMIN_H__ + +# include "internal.h" + +# ifdef __cplusplus +extern "C" { +# endif + + +/** + * virAdmConnect: + * + * a virAdmConnect is a private structure representing a connection to + * libvirt daemon. + */ +typedef struct _virAdmConnect virAdmConnect; + +/** + * virAdmConnectPtr: + * + * a virAdmConnectPtr is pointer to a virAdmConnect private structure, + * this is the type used to reference a connection to the daemon + * in the API. + */ +typedef virAdmConnect *virAdmConnectPtr; + +virAdmConnectPtr virAdmConnectOpen(unsigned int flags);
How does this figure out which libvirtd daemon to connect to ? Presumably you've hardcoded it based on the UID you're running as ? I think for future proofing we should probably define a URI syntax for this. eg admin:///system admin:///session And allow an optional parameter for the socket path, for people who have built their daemon with an unusual --prefix arg.
+libvirt_admin_la_SOURCES += \ + datatypes.c \ + util/viralloc.c \ + util/viratomic.c \ + util/virauth.c \ + util/virauthconfig.c \ + util/virbitmap.c \ + util/virbuffer.c \ + util/vircommand.c \ + util/virerror.c \ + util/virevent.c \ + util/vireventpoll.c \ + util/virfile.c \ + util/virhash.c \ + util/virhashcode.c \ + util/virjson.c \ + util/virkeyfile.c \ + util/virlog.c \ + util/virobject.c \ + util/virpidfile.c \ + util/virprocess.c \ + util/virrandom.c \ + util/virseclabel.c \ + util/virsocketaddr.c \ + util/virstorageencryption.c \ + util/virstoragefile.c \ + util/virstring.c \ + util/virthread.c \ + util/virtime.c \ + util/virtypedparam.c \ + util/viruri.c \ + util/virutil.c \ + util/viruuid.c \ + util/virxml.c \ + remote/remote_protocol.c \ + rpc/virnetmessage.h \ + rpc/virnetmessage.c \ + rpc/virnetsocket.c \ + rpc/virnetsshsession.c \ + rpc/virkeepalive.c \ + rpc/virnetclient.c \ + rpc/virnetclientprogram.c \ + rpc/virnetclientstream.c \ + rpc/virnetprotocol.c \ + rpc/virnettlscontext.c \ + rpc/virnetsaslcontext.c
+ +libvirt_admin_la_LDFLAGS = \ + $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_ADMIN_SYMBOL_FILE) \ + -version-info $(LIBVIRT_VERSION_INFO) \ + $(AM_LDFLAGS) \ + $(CYGWIN_EXTRA_LDFLAGS) \ + $(MINGW_EXTRA_LDFLAGS) + +libvirt_admin_la_LIBADD = \ + $(CYGWIN_EXTRA_LIBADD) + +libvirt_admin_la_CFLAGS = \ + $(AM_CFLAGS) \ + -I$(srcdir)/remote \ + -I$(srcdir)/rpc \ + -I$(srcdir)/admin + +libvirt_admin_la_CFLAGS += \ + $(CAPNG_CFLAGS) \ + $(YAJL_CFLAGS) \ + $(SSH2_CFLAGS) \ + $(SASL_CFLAGS) \ + $(GNUTLS_CFLAGS) + +libvirt_admin_la_LIBADD += \ + $(CAPNG_LIBS) \ + $(YAJL_LIBS) \ + $(DEVMAPPER_LIBS) \ + $(LIBXML_LIBS) \ + $(SSH2_LIBS) \ + $(SASL_LIBS) \ + $(GNUTLS_LIBS) + +if WITH_DTRACE_PROBES +libvirt_admin_la_LIBADD += libvirt_probes.lo +endif WITH_DTRACE_PROBES + +endif WITH_ADMIN + # Empty source list - it merely links a bunch of convenience libs together libvirt_la_SOURCES = libvirt_la_LDFLAGS = \ diff --git a/src/datatypes.c b/src/datatypes.c index b21113e..83cee7e 100644 --- a/src/datatypes.c +++ b/src/datatypes.c @@ -59,6 +59,10 @@ static void virStreamDispose(void *obj); static void virStorageVolDispose(void *obj); static void virStoragePoolDispose(void *obj);
+virClassPtr virAdmConnectClass; + +static void virAdmConnectDispose(void *obj); + static int virDataTypesOnceInit(void) { @@ -88,6 +92,8 @@ virDataTypesOnceInit(void) DECLARE_CLASS(virStorageVol); DECLARE_CLASS(virStoragePool);
+ DECLARE_CLASS_CONNECT(virAdmConnect); + #undef DECLARE_CLASS_COMMON #undef DECLARE_CLASS_LOCKABLE #undef DECLARE_CLASS_CONNECT @@ -804,3 +810,27 @@ virDomainSnapshotDispose(void *obj) VIR_FREE(snapshot->name); virObjectUnref(snapshot->domain); } + + +virAdmConnectPtr +virAdmConnectNew(void) +{ + virAdmConnectPtr ret; + + if (virDataTypesInitialize() < 0) + return NULL; + + if (!(ret = virGetAbstractConnect(virAdmConnectClass))) + return NULL; + + return ret; +} + +static void +virAdmConnectDispose(void *obj) +{ + virAdmConnectPtr conn = obj; + + if (conn->privateDataFreeFunc) + conn->privateDataFreeFunc(conn->privateData); +} diff --git a/src/datatypes.h b/src/datatypes.h index 9f95811..b240e4c 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -42,6 +42,8 @@ extern virClassPtr virStreamClass; extern virClassPtr virStorageVolClass; extern virClassPtr virStoragePoolClass;
+extern virClassPtr virAdmConnectClass; + # define virCheckConnectReturn(obj, retval) \ do { \ if (!virObjectIsClass(obj, virConnectClass)) { \ @@ -296,6 +298,26 @@ extern virClassPtr virStoragePoolClass; dom, NULLSTR(_domname), _uuidstr, __VA_ARGS__); \ } while (0)
+# define virCheckAdmConnectReturn(obj, retval) \ + do { \ + if (!virObjectIsClass(obj, virAdmConnectClass)) { \ + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INVALID_CONN, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + virDispatchError(NULL); \ + return retval; \ + } \ + } while (0) +# define virCheckAdmConnectGoto(obj, label) \ + do { \ + if (!virObjectIsClass(obj, virAdmConnectClass)) { \ + virReportErrorHelper(VIR_FROM_THIS, VIR_ERR_INVALID_CONN, \ + __FILE__, __FUNCTION__, __LINE__, \ + __FUNCTION__); \ + goto label; \ + } \ + } while (0) + /** * VIR_DOMAIN_DEBUG: * @dom: domain @@ -365,6 +387,19 @@ struct _virConnect { };
/** + * _virAdmConnect: + * + * Internal structure associated to an admin connection + */ +struct _virAdmConnect { + virAbstractConnect object; + + void *privateData; + virFreeCallback privateDataFreeFunc; +}; + + +/** * _virDomain: * * Internal structure associated to a domain @@ -545,4 +580,6 @@ virNWFilterPtr virGetNWFilter(virConnectPtr conn, virDomainSnapshotPtr virGetDomainSnapshot(virDomainPtr domain, const char *name);
+virAdmConnectPtr virAdmConnectNew(void); + #endif /* __VIR_DATATYPES_H__ */ diff --git a/src/internal.h b/src/internal.h index 4d473af..1fbcfc2 100644 --- a/src/internal.h +++ b/src/internal.h @@ -58,6 +58,7 @@ # include "libvirt/libvirt.h" # include "libvirt/libvirt-lxc.h" # include "libvirt/libvirt-qemu.h" +# include "libvirt/libvirt-admin.h" # include "libvirt/virterror.h"
# include "c-strcase.h" diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c new file mode 100644 index 0000000..e47089d --- /dev/null +++ b/src/libvirt-admin.c @@ -0,0 +1,337 @@ +/* + * libvirt-admin.c + * + * 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@redhat.com> + */ + +#include <config.h> + +#include <rpc/rpc.h> + +#include "internal.h" +#include "configmake.h" +#include "datatypes.h" +#include "viralloc.h" +#include "virlog.h" +#include "virstring.h" +#include "virutil.h" +#include "viruuid.h" +#include "virnetclient.h" + +#define VIR_FROM_THIS VIR_FROM_ADMIN +#define LIBVIRTD_ADMIN_UNIX_SOCKET LOCALSTATEDIR "/run/libvirt/libvirt-admin-sock" + +VIR_LOG_INIT("libvirt-admin"); + + +typedef struct _remoteAdminPriv remoteAdminPriv; +typedef remoteAdminPriv *remoteAdminPrivPtr; + +struct _remoteAdminPriv { + virMutex lock; + int counter; + int localUses; + virNetClientPtr client; + virNetClientProgramPtr program; +}; + +static void +remoteAdminLock(remoteAdminPrivPtr priv) +{ + virMutexLock(&priv->lock); +} + +static void +remoteAdminUnlock(remoteAdminPrivPtr priv) +{ + virMutexUnlock(&priv->lock); +} + +static void +remoteAdminPrivFree(void *opaque) +{ + remoteAdminPrivPtr priv = opaque; + + virObjectUnref(priv->program); + virObjectUnref(priv->client); + + virMutexDestroy(&priv->lock); + VIR_FREE(priv); +} + +static int +callFull(virAdmConnectPtr conn ATTRIBUTE_UNUSED, + remoteAdminPrivPtr priv, + int *fdin, + size_t fdinlen, + int **fdout, + size_t *fdoutlen, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret) +{ + int rv; + virNetClientProgramPtr prog; + int counter = priv->counter++; + virNetClientPtr client = priv->client; + priv->localUses++; + + /* We hav nothing else right now, but we can still add more + * programs in the future */ + prog = priv->program; + + /* Unlock, so that if we get any async events/stream data + * while processing the RPC, we don't deadlock when our + * callbacks for those are invoked + */ + remoteAdminUnlock(priv); + rv = virNetClientProgramCall(prog, + client, + counter, + proc_nr, + fdinlen, fdin, + fdoutlen, fdout, + args_filter, args, + ret_filter, ret); + remoteAdminLock(priv); + priv->localUses--; + + return rv; +} + +static int +call(virAdmConnectPtr conn, + unsigned int flags, + int proc_nr, + xdrproc_t args_filter, char *args, + xdrproc_t ret_filter, char *ret) +{ + virCheckFlags(0, -1); + + return callFull(conn, conn->privateData, + NULL, 0, NULL, NULL, proc_nr, + args_filter, args, ret_filter, ret); +} + +#include "admin_protocol.h" +#include "admin_client.h" + +static bool virAdmGlobalError; +static virOnceControl virAdmGlobalOnce = VIR_ONCE_CONTROL_INITIALIZER; + +static remoteAdminPrivPtr +remoteAdminPrivNew(void) +{ + remoteAdminPrivPtr priv = NULL; + + /* initialize private data */ + if (VIR_ALLOC(priv) < 0) + goto error; + + if (virMutexInit(&priv->lock) < 0) { + VIR_FREE(priv); + goto error; + } + + priv->localUses = 1; + if (!(priv->client = virNetClientNewUNIX(LIBVIRTD_ADMIN_UNIX_SOCKET, + false, NULL))) + goto error; + + if (!(priv->program = virNetClientProgramNew(ADMIN_PROGRAM, + ADMIN_PROTOCOL_VERSION, + NULL, 0, NULL))) + goto error; + + if (virNetClientAddProgram(priv->client, priv->program) < 0) + goto error; + + return priv; + error: + remoteAdminPrivFree(priv); + return NULL; +} + +static void +virAdmGlobalInit(void) +{ + /* It would be nice if we could trace the use of this call, to + * help diagnose in log files if a user calls something other than + * virAdmConnectOpen first. But we can't rely on VIR_DEBUG working + * until after initialization is complete, and since this is + * one-shot, we never get here again. */ + if (virThreadInitialize() < 0 || + virErrorInitialize() < 0) + goto error; + + virLogSetFromEnv(); + + if (!bindtextdomain(PACKAGE, LOCALEDIR)) + goto error; + + return; + error: + virAdmGlobalError = true; +} + +/** + * virAdmInitialize: + * + * Initialize the library. + * + * Returns 0 in case of success, -1 in case of error + */ +static int +virAdmInitialize(void) +{ + if (virOnce(&virAdmGlobalOnce, virAdmGlobalInit) < 0) + return -1; + + if (virAdmGlobalError) + return -1; + + return 0; +} + +/** + * virAdmConnectOpen: + * @flags: unused, must be 0 + * + * Opens connection to admin interface of the daemon. + * + * Returns @virAdmConnectPtr object or NULL on error + */ +virAdmConnectPtr +virAdmConnectOpen(unsigned int flags) +{ + virAdmConnectPtr conn = NULL; + remoteAdminPrivPtr priv = NULL; + + if (virAdmInitialize() < 0) + goto error; + + VIR_DEBUG("flags=%x", flags); + virResetLastError(); + + if (!(conn = virAdmConnectNew())) + goto error; + + if (!(priv = remoteAdminPrivNew())) + goto error; + + remoteAdminLock(priv); + conn->privateData = priv; + conn->privateDataFreeFunc = remoteAdminPrivFree; + + { + admin_connect_open_args args = { flags }; + + VIR_DEBUG("Trying to open admin connection"); + if (call(conn, 0, ADMIN_PROC_CONNECT_OPEN, + (xdrproc_t) xdr_admin_connect_open_args, (char *) &args, + (xdrproc_t) xdr_void, (char *) NULL) == -1) + goto error; + } + + remoteAdminUnlock(priv); + + return conn; + error: + virDispatchError(NULL); + if (priv) + remoteAdminUnlock(priv); + virObjectUnref(conn); + return NULL; +} + +/** + * virAdmConnectClose: + * @conn: pointer to admin connection to close + * + * This function closes the connection to the Hypervisor. This should + * not be called if further interaction with the Hypervisor are needed + * especially if there is running domain which need further monitoring by + * the application. + * + * Connections are reference counted; the count is explicitly + * increased by the initial open (virConnectOpen, virConnectOpenAuth, + * and the like) as well as virConnectRef; it is also temporarily + * increased by other API that depend on the connection remaining + * alive. The open and every virConnectRef call should have a + * matching virConnectClose, and all other references will be released + * after the corresponding operation completes. + * + * Returns a positive number if at least 1 reference remains on + * success. The returned value should not be assumed to be the total + * reference count. A return of 0 implies no references remain and + * the connection is closed and memory has been freed. A return of -1 + * implies a failure. + * + * It is possible for the last virConnectClose to return a positive + * value if some other object still has a temporary reference to the + * connection, but the application should not try to further use a + * connection after the virConnectClose that matches the initial open. + */ +int +virAdmConnectClose(virAdmConnectPtr conn) +{ + VIR_DEBUG("conn=%p", conn); + + virResetLastError(); + if (!conn) + return 0; + + virCheckAdmConnectReturn(conn, -1); + + if (!virObjectUnref(conn)) + return 0; + return 1; +} + + +/** + * virAdmConnectRef: + * @conn: the connection to hold a reference on + * + * Increment the reference count on the connection. For each + * additional call to this method, there shall be a corresponding + * call to virConnectClose to release the reference count, once + * the caller no longer needs the reference to this object. + * + * This method is typically useful for applications where multiple + * threads are using a connection, and it is required that the + * connection remain open until all threads have finished using + * it. I.e., each new thread using a connection would increment + * the reference count. + * + * Returns 0 in case of success, -1 in case of failure + */ +int +virAdmConnectRef(virAdmConnectPtr conn) +{ + VIR_DEBUG("conn=%p refs=%d", conn, + conn ? conn->object.parent.parent.u.s.refs : 0); + + virResetLastError(); + virCheckAdmConnectReturn(conn, -1); + + virObjectRef(conn); + + return 0; +} diff --git a/src/libvirt_admin.syms b/src/libvirt_admin.syms new file mode 100644 index 0000000..292433f --- /dev/null +++ b/src/libvirt_admin.syms @@ -0,0 +1,18 @@ +# +# Officially exported symbols, for which header +# file definitions are installed in /usr/include/libvirt +# from libvirt-admin.h +# +# Versions here are *fixed* to match the libvirt version +# at which the symbol was introduced. This ensures that +# a new client app requiring symbol foo() can't accidentally +# run with old libvirt-admin.so not providing foo() - the global +# soname version info can't enforce this since we never +# change the soname +# +LIBVIRT_ADMIN_1.2.3 {
Either you've been working on this a really long time, or this version was a typo. Either way, when we are ready to merge the admin library, that might be a nice reason to bump our version to 1.3.x, since we've been on 1.2.x a long time. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Fri, Apr 17, 2015 at 11:28:11AM +0100, Daniel P. Berrange wrote:
On Thu, Apr 16, 2015 at 04:46:44PM +0200, Martin Kletzander wrote:
Initial scratch of the admin library. It has its own virAdmConnectPtr that inherits from virAbstractConnectPtr and thus trivially supports error reporting.
See my note earlier about error reporting on the connection being a bad idea due to lack of thread safety.
Configuration option --with-admin is added to control whether the admin library should be built or not (set to 'yes' by default).
Is there a compelling reason why we'd need/want to be able to disable building of the admin library ? As a comparison we unconditionally build libvirt-qemu.so & libvirt-lxc.so
No reason, I just figured someone might want to disable that. [...]
+virAdmConnectPtr virAdmConnectOpen(unsigned int flags);
How does this figure out which libvirtd daemon to connect to ? Presumably you've hardcoded it based on the UID you're running as ?
It doesn't. I don't think anyone is going to use this to connect to the session daemon. I also don't see anyone having session daemon running without the possibility of restarting it.
I think for future proofing we should probably define a URI syntax for this.
eg
admin:///system admin:///session
And allow an optional parameter for the socket path, for people who have built their daemon with an unusual --prefix arg.
I think we can keep it without the possibility of connecting to the session daemon and if that is going to change, we can add virAdmConnectSession() function. In the meantime I'd rather focus on enabling this functionality then dealing with session daemon, all the unnecessary code it adds and the problems we already have with the session daemon. [...]
diff --git a/src/libvirt_admin.syms b/src/libvirt_admin.syms new file mode 100644 index 0000000..292433f --- /dev/null +++ b/src/libvirt_admin.syms @@ -0,0 +1,18 @@ +# +# Officially exported symbols, for which header +# file definitions are installed in /usr/include/libvirt +# from libvirt-admin.h +# +# Versions here are *fixed* to match the libvirt version +# at which the symbol was introduced. This ensures that +# a new client app requiring symbol foo() can't accidentally +# run with old libvirt-admin.so not providing foo() - the global +# soname version info can't enforce this since we never +# change the soname +# +LIBVIRT_ADMIN_1.2.3 {
Either you've been working on this a really long time, or this version was a typo.
That version is one year old and I've sent the original RFC 2 years ago. The progress can be seen thanks to that. I started a long time ago, then haven't had a time for that and every time I managed to get rid of higher priority tasks I had to rebase it and start off again and only for so much time until another higher priority tasks appeared.
Either way, when we are ready to merge the admin library, that might be a nice reason to bump our version to 1.3.x, since we've been on 1.2.x a long time.
That'd be great! Or 2.0? Just kidding.

On Fri, Apr 17, 2015 at 02:25:48PM +0200, Martin Kletzander wrote:
On Fri, Apr 17, 2015 at 11:28:11AM +0100, Daniel P. Berrange wrote:
On Thu, Apr 16, 2015 at 04:46:44PM +0200, Martin Kletzander wrote:
Initial scratch of the admin library. It has its own virAdmConnectPtr that inherits from virAbstractConnectPtr and thus trivially supports error reporting.
See my note earlier about error reporting on the connection being a bad idea due to lack of thread safety.
Configuration option --with-admin is added to control whether the admin library should be built or not (set to 'yes' by default).
Is there a compelling reason why we'd need/want to be able to disable building of the admin library ? As a comparison we unconditionally build libvirt-qemu.so & libvirt-lxc.so
No reason, I just figured someone might want to disable that.
[...]
+virAdmConnectPtr virAdmConnectOpen(unsigned int flags);
How does this figure out which libvirtd daemon to connect to ? Presumably you've hardcoded it based on the UID you're running as ?
It doesn't. I don't think anyone is going to use this to connect to the session daemon. I also don't see anyone having session daemon running without the possibility of restarting it.
I think for future proofing we should probably define a URI syntax for this.
eg
admin:///system admin:///session
And allow an optional parameter for the socket path, for people who have built their daemon with an unusual --prefix arg.
I think we can keep it without the possibility of connecting to the session daemon and if that is going to change, we can add virAdmConnectSession() function. In the meantime I'd rather focus on enabling this functionality then dealing with session daemon, all the unnecessary code it adds and the problems we already have with the session daemon.
I really think we need to have a URI here, as adding new connect functions doesn't really scale well. I don't think supporting the session instance should really add any complexity - all that changes is the socket path we need to use. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

No online docs are build from it since it doesn't really fit into our document structure and new page will need to be created for it, but this is at least a heads-up commit for easier parsing in order to build some documentation (or python bindings) later on. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- .gitignore | 1 + docs/Makefile.am | 23 +++++++++++++++++++---- docs/apibuild.py | 10 +++++++++- libvirt.spec.in | 1 + 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 0f8b3d6..d299063 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ /docs/apibuild.py.stamp /docs/devhelp/libvirt.devhelp /docs/hvsupport.html.in +/docs/libvirt-admin-*.xml /docs/libvirt-api.xml /docs/libvirt-lxc-*.xml /docs/libvirt-qemu-*.xml diff --git a/docs/Makefile.am b/docs/Makefile.am index a497256..12d1cd1 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -## Copyright (C) 2005-2014 Red Hat, Inc. +## Copyright (C) 2005-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 @@ -128,8 +128,16 @@ lxc_xml = \ libvirt-lxc-api.xml \ libvirt-lxc-refs.xml +admin_xml = \ + libvirt-admin-api.xml \ + libvirt-admin-refs.xml + apidir = $(pkgdatadir)/api -api_DATA = libvirt-api.xml libvirt-qemu-api.xml libvirt-lxc-api.xml +api_DATA = \ + libvirt-api.xml \ + libvirt-qemu-api.xml \ + libvirt-lxc-api.xml \ + libvirt-admin-api.xml fig = \ libvirt-net-logical.fig \ @@ -149,7 +157,7 @@ EXTRA_DIST= \ hacking1.xsl hacking2.xsl wrapstring.xsl \ $(dot_html) $(dot_html_in) $(gif) $(apihtml) $(apipng) \ $(devhelphtml) $(devhelppng) $(devhelpcss) $(devhelpxsl) \ - $(xml) $(qemu_xml) $(lxc_xml) $(fig) $(png) $(css) \ + $(xml) $(qemu_xml) $(lxc_xml) $(admin_xml) $(fig) $(png) $(css) \ $(patches) $(dot_php_in) $(dot_php_code_in) $(dot_php)\ $(internals_html_in) $(internals_html) \ sitemap.html.in aclperms.htmlinc \ @@ -174,6 +182,7 @@ all-am: web api: $(srcdir)/libvirt-api.xml $(srcdir)/libvirt-refs.xml qemu_api: $(srcdir)/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-refs.xml lxc_api: $(srcdir)/libvirt-lxc-api.xml $(srcdir)/libvirt-lxc-refs.xml +admin_api: $(srcdir)/libvirt-admin-api.xml $(srcdir)/libvirt-admin-refs.xml web: $(dot_html) $(internals_html) html/index.html devhelp/index.html \ $(dot_php) @@ -274,6 +283,7 @@ $(addprefix $(srcdir)/,$(devhelphtml)): $(srcdir)/libvirt-api.xml $(devhelpxsl) python_generated_files = \ $(srcdir)/html/libvirt-libvirt-lxc.html \ $(srcdir)/html/libvirt-libvirt-qemu.html \ + $(srcdir)/html/libvirt-libvirt-admin.html \ $(srcdir)/html/libvirt-virterror.html \ $(srcdir)/libvirt-api.xml \ $(srcdir)/libvirt-refs.xml \ @@ -281,6 +291,8 @@ python_generated_files = \ $(srcdir)/libvirt-lxc-refs.xml \ $(srcdir)/libvirt-qemu-api.xml \ $(srcdir)/libvirt-qemu-refs.xml \ + $(srcdir)/libvirt-admin-api.xml \ + $(srcdir)/libvirt-admin-refs.xml \ $(NULL) APIBUILD=$(srcdir)/apibuild.py @@ -304,10 +316,12 @@ $(APIBUILD_STAMP): $(srcdir)/apibuild.py \ $(srcdir)/../include/libvirt/libvirt-stream.h \ $(srcdir)/../include/libvirt/libvirt-lxc.h \ $(srcdir)/../include/libvirt/libvirt-qemu.h \ + $(srcdir)/../include/libvirt/libvirt-admin.h \ $(srcdir)/../include/libvirt/virterror.h \ $(srcdir)/../src/libvirt.c \ $(srcdir)/../src/libvirt-lxc.c \ $(srcdir)/../src/libvirt-qemu.c \ + $(srcdir)/../src/libvirt-admin.c \ $(srcdir)/../src/util/virerror.c \ $(srcdir)/../src/util/virevent.c \ $(srcdir)/../src/util/virtypedparam.c @@ -326,9 +340,10 @@ maintainer-clean-local: clean-local todo.html.in rm -rf $(srcdir)/libvirt-qemu-api.xml $(srcdir)/libvirt-qemu-refs.xml rm -rf $(srcdir)/libvirt-lxc-api.xml $(srcdir)/libvirt-lxc-refs.xml + rm -rf $(srcdir)/libvirt-admin-api.xml $(srcdir)/libvirt-admin-refs.xml rm -rf $(APIBUILD_STAMP) -rebuild: api qemu_api lxc_api all +rebuild: api qemu_api lxc_api admin_api all install-data-local: $(mkinstalldirs) $(DESTDIR)$(HTML_DIR) diff --git a/docs/apibuild.py b/docs/apibuild.py index 9fa9361..95e9f27 100755 --- a/docs/apibuild.py +++ b/docs/apibuild.py @@ -59,6 +59,11 @@ lxc_included_files = { "libvirt-lxc.c": "Implementations for the LXC specific APIs", } +admin_included_files = { + "libvirt-admin.h": "header with admin specific API definitions", + "libvirt-admin.c": "Implementations for the admin specific APIs", +} + ignored_words = { "ATTRIBUTE_UNUSED": (0, "macro keyword"), "ATTRIBUTE_SENTINEL": (0, "macro keyword"), @@ -2018,6 +2023,8 @@ class docBuilder: self.includes = includes + qemu_included_files.keys() elif name == "libvirt-lxc": self.includes = includes + lxc_included_files.keys() + elif name == "libvirt-admin": + self.includes = includes + admin_included_files.keys() self.modules = {} self.headers = {} self.idx = index() @@ -2551,7 +2558,7 @@ class docBuilder: def rebuild(name): - if name not in ["libvirt", "libvirt-qemu", "libvirt-lxc"]: + if name not in ["libvirt", "libvirt-qemu", "libvirt-lxc", "libvirt-admin"]: self.warning("rebuild() failed, unknown module %s") % name return None builder = None @@ -2595,6 +2602,7 @@ if __name__ == "__main__": rebuild("libvirt") rebuild("libvirt-qemu") rebuild("libvirt-lxc") + rebuild("libvirt-admin") if warnings > 0: sys.exit(2) else: diff --git a/libvirt.spec.in b/libvirt.spec.in index 153786c..7c13588 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2285,6 +2285,7 @@ exit 0 %{_datadir}/libvirt/api/libvirt-api.xml %{_datadir}/libvirt/api/libvirt-qemu-api.xml %{_datadir}/libvirt/api/libvirt-lxc-api.xml +%{_datadir}/libvirt/api/libvirt-admin-api.xml %doc docs/*.html docs/html docs/*.gif %doc docs/libvirt-api.xml -- 2.3.5

This is not going to be very widely used, but for some corner cases and easier (unsafe) debugging, it might be nice. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- daemon/libvirtd-config.c | 5 ++++- daemon/libvirtd-config.h | 1 + daemon/libvirtd.aug | 1 + daemon/libvirtd.conf | 8 ++++++++ daemon/test_libvirtd.aug.in | 1 + tests/confdata/libvirtd.conf | 6 ++++++ tests/confdata/libvirtd.out | 5 +++++ 7 files changed, 26 insertions(+), 1 deletion(-) diff --git a/daemon/libvirtd-config.c b/daemon/libvirtd-config.c index 3694455..bce2d70 100644 --- a/daemon/libvirtd-config.c +++ b/daemon/libvirtd-config.c @@ -264,7 +264,8 @@ daemonConfigNew(bool privileged ATTRIBUTE_UNUSED) if (VIR_STRDUP(data->unix_sock_rw_perms, data->auth_unix_rw == REMOTE_AUTH_POLKIT ? "0777" : "0700") < 0 || - VIR_STRDUP(data->unix_sock_ro_perms, "0777") < 0) + VIR_STRDUP(data->unix_sock_ro_perms, "0777") < 0 || + VIR_STRDUP(data->unix_sock_admin_perms, "0700") < 0) goto error; #if WITH_SASL @@ -337,6 +338,7 @@ daemonConfigFree(struct daemonConfig *data) } VIR_FREE(data->access_drivers); + VIR_FREE(data->unix_sock_admin_perms); VIR_FREE(data->unix_sock_ro_perms); VIR_FREE(data->unix_sock_rw_perms); VIR_FREE(data->unix_sock_group); @@ -404,6 +406,7 @@ daemonConfigLoadOptions(struct daemonConfig *data, goto error; GET_CONF_STR(conf, filename, unix_sock_group); + GET_CONF_STR(conf, filename, unix_sock_admin_perms); GET_CONF_STR(conf, filename, unix_sock_ro_perms); GET_CONF_STR(conf, filename, unix_sock_rw_perms); diff --git a/daemon/libvirtd-config.h b/daemon/libvirtd-config.h index c996995..b8d2bc0 100644 --- a/daemon/libvirtd-config.h +++ b/daemon/libvirtd-config.h @@ -35,6 +35,7 @@ struct daemonConfig { char *tls_port; char *tcp_port; + char *unix_sock_admin_perms; char *unix_sock_ro_perms; char *unix_sock_rw_perms; char *unix_sock_group; diff --git a/daemon/libvirtd.aug b/daemon/libvirtd.aug index 5a0807c..b20ceca 100644 --- a/daemon/libvirtd.aug +++ b/daemon/libvirtd.aug @@ -35,6 +35,7 @@ module Libvirtd = let sock_acl_entry = str_entry "unix_sock_group" | str_entry "unix_sock_ro_perms" | str_entry "unix_sock_rw_perms" + | str_entry "unix_sock_admin_perms" | str_entry "unix_sock_dir" let authentication_entry = str_entry "auth_unix_ro" diff --git a/daemon/libvirtd.conf b/daemon/libvirtd.conf index 069ef3a..6ef38fa 100644 --- a/daemon/libvirtd.conf +++ b/daemon/libvirtd.conf @@ -106,9 +106,17 @@ # control, then you may want to relax this too. #unix_sock_rw_perms = "0770" +# Set the UNIX socket permissions for the admin interface socket. +# +# Default allows only owner (root), do not change it unless you are +# sure to whom you are exposing the access to. +#unix_sock_admin_perms = "0700" + # Set the name of the directory in which sockets will be found/created. #unix_sock_dir = "/var/run/libvirt" + + ################################################################# # # Authentication. diff --git a/daemon/test_libvirtd.aug.in b/daemon/test_libvirtd.aug.in index 37ff33d..a87df5f 100644 --- a/daemon/test_libvirtd.aug.in +++ b/daemon/test_libvirtd.aug.in @@ -12,6 +12,7 @@ module Test_libvirtd = { "unix_sock_group" = "libvirt" } { "unix_sock_ro_perms" = "0777" } { "unix_sock_rw_perms" = "0770" } + { "unix_sock_admin_perms" = "0700" } { "unix_sock_dir" = "/var/run/libvirt" } { "auth_unix_ro" = "none" } { "auth_unix_rw" = "none" } diff --git a/tests/confdata/libvirtd.conf b/tests/confdata/libvirtd.conf index 2f2ba4b..5029c4c 100644 --- a/tests/confdata/libvirtd.conf +++ b/tests/confdata/libvirtd.conf @@ -89,6 +89,12 @@ unix_sock_ro_perms = "0777" # control then you may want to relax this to: unix_sock_rw_perms = "0770" +# Set the UNIX socket permissions for the admin interface socket. +# +# Default allows only owner (root), do not change it unless you are +# sure to whom you are exposing the access to +unix_sock_admin_perms = "0700" + ################################################################# diff --git a/tests/confdata/libvirtd.out b/tests/confdata/libvirtd.out index 171945d..4d7ed47 100644 --- a/tests/confdata/libvirtd.out +++ b/tests/confdata/libvirtd.out @@ -71,6 +71,11 @@ unix_sock_ro_perms = "0777" # If not using PolicyKit and setting group ownership for access # control then you may want to relax this to: unix_sock_rw_perms = "0770" +# Set the UNIX socket permissions for the admin interface socket. +# +# Default allows only owner (root), do not change it unless you are +# sure to whom you are exposing the access to +unix_sock_admin_perms = "0700" ################################################################# # # Authentication. -- 2.3.5

For this to pe properly separated from other protocols used by the server, there is second subserver added which allows access to the whole virNetServer to its clients. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- cfg.mk | 3 ++ daemon/Makefile.am | 33 +++++++++++++++++- daemon/admin_server.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++ daemon/admin_server.h | 36 +++++++++++++++++++ daemon/libvirtd.c | 91 ++++++++++++++++++++++++++++++++++++++++++----- daemon/libvirtd.h | 14 +++++++- po/POTFILES.in | 1 + 7 files changed, 264 insertions(+), 11 deletions(-) create mode 100644 daemon/admin_server.c create mode 100644 daemon/admin_server.h diff --git a/cfg.mk b/cfg.mk index b948b7a..7c1c597 100644 --- a/cfg.mk +++ b/cfg.mk @@ -1072,6 +1072,7 @@ sc_po_check: \ $(srcdir)/daemon/remote_dispatch.h \ $(srcdir)/daemon/qemu_dispatch.h \ $(srcdir)/src/remote/remote_client_bodies.h \ + $(srcdir)/daemon/admin_dispatch.h \ $(srcdir)/src/admin/admin_client.h $(srcdir)/daemon/remote_dispatch.h: $(srcdir)/src/remote/remote_protocol.x $(MAKE) -C daemon remote_dispatch.h @@ -1079,6 +1080,8 @@ $(srcdir)/daemon/qemu_dispatch.h: $(srcdir)/src/remote/qemu_protocol.x $(MAKE) -C daemon qemu_dispatch.h $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protocol.x $(MAKE) -C src remote/remote_client_bodies.h +$(srcdir)/daemon/admin_server.h: $(srcdir)/src/admin/admin_protocol.x + $(MAKE) -C daemon admin_dispatch.h $(srcdir)/src/admin/admin_client.h: $(srcdir)/src/admin/admin_protocol.x $(MAKE) -C src admin/admin_client.h diff --git a/daemon/Makefile.am b/daemon/Makefile.am index bceaeb2..b309ce9 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -## Copyright (C) 2005-2014 Red Hat, Inc. +## Copyright (C) 2005-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 @@ -25,6 +25,7 @@ INCLUDES = \ -I$(top_srcdir)/src/conf \ -I$(top_srcdir)/src/rpc \ -I$(top_srcdir)/src/remote \ + -I$(top_srcdir)/src/admin \ -I$(top_srcdir)/src/access \ $(GETTEXT_CPPFLAGS) @@ -49,6 +50,7 @@ EXTRA_DIST = \ remote_dispatch.h \ lxc_dispatch.h \ qemu_dispatch.h \ + admin_dispatch.h \ libvirtd.conf \ libvirtd.init.in \ libvirtd.upstart \ @@ -76,6 +78,9 @@ BUILT_SOURCES = REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x LXC_PROTOCOL = $(top_srcdir)/src/remote/lxc_protocol.x QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x +ADMIN_PROTOCOL = $(top_srcdir)/src/admin/admin_protocol.x + +BUILT_SOURCES += admin_dispatch.h remote_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ $(REMOTE_PROTOCOL) @@ -95,6 +100,12 @@ qemu_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ --mode=server qemu QEMU $(QEMU_PROTOCOL) \ > $(srcdir)/qemu_dispatch.h +admin_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \ + $(ADMIN_PROTOCOL) + $(AM_V_GEN)$(PERL) -w $(srcdir)/../src/rpc/gendispatch.pl \ + --mode=server admin ADMIN $(ADMIN_PROTOCOL) \ + > $(srcdir)/admin_dispatch.h + if WITH_LIBVIRTD # Build a convenience library, for reuse in tests/libvirtdconftest @@ -114,6 +125,25 @@ libvirtd_conf_la_LDFLAGS = \ $(NULL) libvirtd_conf_la_LIBADD = $(LIBXML_LIBS) +noinst_LTLIBRARIES += libvirtd_admin.la +libvirtd_admin_la_SOURCES = \ + admin_server.c \ + ../src/admin/admin_protocol.c + +libvirtd_admin_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(XDR_CFLAGS) \ + $(PIE_CFLAGS) \ + $(WARN_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(COVERAGE_CFLAGS) + +libvirtd_admin_la_LDFLAGS = \ + $(PIE_LDFLAGS) \ + $(RELRO_LDFLAGS) \ + $(COVERAGE_LDFLAGS) \ + $(NO_INDIRECT_LDFLAGS) + man8_MANS = libvirtd.8 sbin_PROGRAMS = libvirtd @@ -166,6 +196,7 @@ endif WITH_DTRACE_PROBES libvirtd_LDADD += \ libvirtd_conf.la \ + libvirtd_admin.la \ ../src/libvirt-lxc.la \ ../src/libvirt-qemu.la \ ../src/libvirt_driver_remote.la \ diff --git a/daemon/admin_server.c b/daemon/admin_server.c new file mode 100644 index 0000000..3f0939a --- /dev/null +++ b/daemon/admin_server.c @@ -0,0 +1,97 @@ +/* + * admin_server.c: + * + * 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@redhat.com> + */ + +#include <config.h> + +#include "internal.h" +#include "libvirtd.h" +#include "libvirt_internal.h" + +#include "admin_protocol.h" +#include "admin_server.h" +#include "datatypes.h" +#include "viralloc.h" +#include "virerror.h" +#include "virlog.h" +#include "virnetserver.h" +#include "virstring.h" +#include "virthreadjob.h" + +#define VIR_FROM_THIS VIR_FROM_ADMIN + +VIR_LOG_INIT("daemon.admin"); + + +void +remoteAdmClientFreeFunc(void *data) +{ + VIR_FREE(data); +} + +void * +remoteAdmClientInitHook(virNetServerClientPtr client ATTRIBUTE_UNUSED, + void *opaque) +{ + struct daemonAdmClientPrivate *priv; + + if (VIR_ALLOC(priv) < 0) + return NULL; + + if (virMutexInit(&priv->lock) < 0) { + VIR_FREE(priv); + virReportSystemError(errno, "%s", _("unable to init mutex")); + return NULL; + } + + priv->srv = opaque; + + return priv; +} + +/* Functions */ +static int +adminDispatchConnectOpen(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + struct admin_connect_open_args *args) +{ + unsigned int flags; + struct daemonAdmClientPrivate *priv = + virNetServerClientGetPrivateData(client); + int ret = -1; + + VIR_DEBUG("priv=%p srv=%p", priv, priv->srv); + virMutexLock(&priv->lock); + + flags = args->flags; + virCheckFlagsGoto(0, cleanup); + + ret = 0; + cleanup: + if (ret < 0) + virNetMessageSaveError(rerr); + virMutexUnlock(&priv->lock); + return ret; +} + +#include "admin_dispatch.h" diff --git a/daemon/admin_server.h b/daemon/admin_server.h new file mode 100644 index 0000000..26721a6 --- /dev/null +++ b/daemon/admin_server.h @@ -0,0 +1,36 @@ +/* + * admin_server.h + * + * Copyright (C) 2014 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@redhat.com> + */ + +#ifndef __LIBVIRTD_ADMIN_H__ +# define __LIBVIRTD_ADMIN_H__ + +# include "rpc/virnetserverprogram.h" +# include "rpc/virnetserverclient.h" + + +extern virNetServerProgramProc adminProcs[]; +extern size_t adminNProcs; + +void remoteAdmClientFreeFunc(void *data); +void *remoteAdmClientInitHook(virNetServerClientPtr client, void *opaque); + +#endif /* __ADMIN_REMOTE_H__ */ diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index e209e93..e041771 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -44,6 +44,7 @@ #include "libvirtd.h" #include "libvirtd-config.h" +#include "admin_server.h" #include "viruuid.h" #include "remote_driver.h" #include "viralloc.h" @@ -112,6 +113,7 @@ VIR_LOG_INIT("daemon.libvirtd"); virNetSASLContextPtr saslCtxt = NULL; #endif virNetServerProgramPtr remoteProgram = NULL; +virNetServerProgramPtr adminProgram = NULL; virNetServerProgramPtr qemuProgram = NULL; virNetServerProgramPtr lxcProgram = NULL; @@ -253,18 +255,24 @@ static int daemonUnixSocketPaths(struct daemonConfig *config, bool privileged, char **sockfile, - char **rosockfile) + char **rosockfile, + char **admsockfile) { if (config->unix_sock_dir) { if (virAsprintf(sockfile, "%s/libvirt-sock", config->unix_sock_dir) < 0) goto error; - if (privileged && - virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0) - goto error; + + if (privileged) { + if (virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0) + goto error; + if (virAsprintf(admsockfile, "%s/libvirt-admin-sock", config->unix_sock_dir) < 0) + goto error; + } } else { if (privileged) { if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock") < 0 || - VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0) + VIR_STRDUP(*rosockfile, LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro") < 0 || + VIR_STRDUP(*admsockfile, LOCALSTATEDIR "/run/libvirt/libvirt-admin-sock") < 0) goto error; } else { char *rundir = NULL; @@ -429,10 +437,12 @@ daemonSetupNetworking(virNetServerPtr srv, struct daemonConfig *config, const char *sock_path, const char *sock_path_ro, + const char *sock_path_adm, bool ipsock, bool privileged) { virNetServerServicePtr svc = NULL; + virNetServerServicePtr svcAdm = NULL; virNetServerServicePtr svcRO = NULL; virNetServerServicePtr svcTCP = NULL; #if WITH_GNUTLS @@ -441,6 +451,7 @@ daemonSetupNetworking(virNetServerPtr srv, gid_t unix_sock_gid = 0; int unix_sock_ro_mask = 0; int unix_sock_rw_mask = 0; + int unix_sock_adm_mask = 0; unsigned int cur_fd = STDERR_FILENO + 1; unsigned int nfds = virGetListenFDs(); @@ -460,6 +471,11 @@ daemonSetupNetworking(virNetServerPtr srv, goto error; } + if (virStrToLong_i(config->unix_sock_admin_perms, NULL, 8, &unix_sock_adm_mask) != 0) { + VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_admin_perms); + goto error; + } + if (virStrToLong_i(config->unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) { VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_rw_perms); goto error; @@ -502,6 +518,25 @@ daemonSetupNetworking(virNetServerPtr srv, virNetServerAddService(srv, 0, svcRO, NULL) < 0) goto error; + if (sock_path_adm) { + VIR_DEBUG("Registering unix socket %s", sock_path_adm); + if (!(svcAdm = virNetServerServiceNewUNIX(sock_path_adm, + unix_sock_adm_mask, + unix_sock_gid, + REMOTE_AUTH_NONE, +#if WITH_GNUTLS + NULL, +#endif + true, + config->max_queued_clients, + config->max_client_requests))) + goto error; + } + + if (svcAdm && + virNetServerAddService(srv, 1, svcAdm, NULL) < 0) + goto error; + if (ipsock) { if (config->listen_tcp) { VIR_DEBUG("Registering TCP socket %s:%s", @@ -599,6 +634,7 @@ daemonSetupNetworking(virNetServerPtr srv, virObjectUnref(svcTCP); virObjectUnref(svc); virObjectUnref(svcRO); + virObjectUnref(svcAdm); return -1; } @@ -1105,6 +1141,7 @@ int main(int argc, char **argv) { char *pid_file = NULL; char *sock_file = NULL; char *sock_file_ro = NULL; + char *sock_file_adm = NULL; int timeout = -1; /* -t: Shutdown timeout */ int verbose = 0; int godaemon = 0; @@ -1272,12 +1309,15 @@ int main(int argc, char **argv) { if (daemonUnixSocketPaths(config, privileged, &sock_file, - &sock_file_ro) < 0) { + &sock_file_ro, + &sock_file_adm) < 0) { VIR_ERROR(_("Can't determine socket paths")); exit(EXIT_FAILURE); } - VIR_DEBUG("Decided on socket paths '%s' and '%s'", - sock_file, NULLSTR(sock_file_ro)); + VIR_DEBUG("Decided on socket paths '%s', '%s' and '%s'", + sock_file, + NULLSTR(sock_file_ro), + NULLSTR(sock_file_adm)); if (godaemon) { char ebuf[1024]; @@ -1408,6 +1448,35 @@ int main(int argc, char **argv) { goto cleanup; } + if (virNetServerAddSubServer(srv, + config->min_workers, + config->max_workers, + config->prio_workers, + config->max_clients, + config->max_anonymous_clients, + config->keepalive_interval, + config->keepalive_count, + !!config->keepalive_required, + remoteAdmClientInitHook, + NULL, + remoteAdmClientFreeFunc, + srv) < 0) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + + if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM, + ADMIN_PROTOCOL_VERSION, + adminProcs, + adminNProcs))) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + if (virNetServerAddProgram(srv, 1, adminProgram) < 0) { + ret = VIR_DAEMON_ERR_INIT; + goto cleanup; + } + if (timeout != -1) { VIR_DEBUG("Registering shutdown timeout %d", timeout); virNetServerAutoShutdown(srv, @@ -1450,7 +1519,9 @@ int main(int argc, char **argv) { 0, "start", NULL, NULL); if (daemonSetupNetworking(srv, config, - sock_file, sock_file_ro, + sock_file, + sock_file_ro, + sock_file_adm, ipsock, privileged) < 0) { ret = VIR_DAEMON_ERR_NETWORK; goto cleanup; @@ -1503,6 +1574,7 @@ int main(int argc, char **argv) { virObjectUnref(remoteProgram); virObjectUnref(lxcProgram); virObjectUnref(qemuProgram); + virObjectUnref(adminProgram); virNetServerClose(srv); virObjectUnref(srv); virNetlinkShutdown(); @@ -1521,6 +1593,7 @@ int main(int argc, char **argv) { VIR_FREE(sock_file); VIR_FREE(sock_file_ro); + VIR_FREE(sock_file_adm); VIR_FREE(pid_file); VIR_FREE(remote_config_file); VIR_FREE(run_dir); diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index 02d4101..81f68cc 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -1,7 +1,7 @@ /* * libvirtd.h: daemon data structure definitions * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -30,9 +30,11 @@ # include <rpc/types.h> # include <rpc/xdr.h> # include "remote_protocol.h" +# include "admin_protocol.h" # include "lxc_protocol.h" # include "qemu_protocol.h" # include "virthread.h" + # if WITH_SASL # include "virnetsaslcontext.h" # endif @@ -42,6 +44,8 @@ typedef struct daemonClientStream daemonClientStream; typedef daemonClientStream *daemonClientStreamPtr; typedef struct daemonClientPrivate daemonClientPrivate; typedef daemonClientPrivate *daemonClientPrivatePtr; +typedef struct daemonAdmClientPrivate daemonAdmClientPrivate; +typedef daemonAdmClientPrivate *daemonAdmClientPrivatePtr; typedef struct daemonClientEventCallback daemonClientEventCallback; typedef daemonClientEventCallback *daemonClientEventCallbackPtr; @@ -71,6 +75,14 @@ struct daemonClientPrivate { bool keepalive_supported; }; +/* Separate private data for admin connection */ +struct daemonAdmClientPrivate { + /* Just a placeholder, not that there is anything to be locked */ + virMutex lock; + + virNetServerPtr srv; +}; + # if WITH_SASL extern virNetSASLContextPtr saslCtxt; # endif diff --git a/po/POTFILES.in b/po/POTFILES.in index af07e09..0378166 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,3 +1,4 @@ +daemon/admin_server.c daemon/libvirtd-config.c daemon/libvirtd.c daemon/qemu_dispatch.h -- 2.3.5

This function accesses the number of connected clients while properly locking the subserver it returns the data about. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/libvirt_remote.syms | 1 + src/rpc/virnetsubserver.c | 10 ++++++++++ src/rpc/virnetsubserver.h | 2 ++ 3 files changed, 13 insertions(+) diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms index f7cf226..8501b90 100644 --- a/src/libvirt_remote.syms +++ b/src/libvirt_remote.syms @@ -209,6 +209,7 @@ virNetSocketWrite; virNetSubServerAddProgram; virNetSubServerAddService; virNetSubServerClose; +virNetSubServerGetNClients; virNetSubServerHasClients; virNetSubServerKeepAliveRequired; virNetSubServerNew; diff --git a/src/rpc/virnetsubserver.c b/src/rpc/virnetsubserver.c index 8d9defb..a2c6568 100644 --- a/src/rpc/virnetsubserver.c +++ b/src/rpc/virnetsubserver.c @@ -660,3 +660,13 @@ virNetSubServerProcessClients(virNetSubServerPtr subsrv) virObjectUnlock(subsrv); } + +size_t +virNetSubServerGetNClients(virNetSubServerPtr subsrv) +{ + size_t ret = 0; + virObjectLock(subsrv); + ret = subsrv->nclients; + virObjectUnlock(subsrv); + return ret; +} diff --git a/src/rpc/virnetsubserver.h b/src/rpc/virnetsubserver.h index cf7c213..0b943f8 100644 --- a/src/rpc/virnetsubserver.h +++ b/src/rpc/virnetsubserver.h @@ -73,4 +73,6 @@ void virNetSubServerProcessClients(virNetSubServerPtr subsrv); void virNetSubServerUpdateServices(virNetSubServerPtr subsrv, bool enabled); +size_t virNetSubServerGetNClients(virNetSubServerPtr subsrv); + #endif /* __VIR_NET_SUBSERVER_H__ */ -- 2.3.5

Just one of the simplest functions that returns string "Clients: X" where X is the number of connected clients to daemon's first subserver (the original one), so it can be tested using virsh, ipython, etc. The subserver is gathered by incrementing its reference counter (similarly to getting qemu capabilities), so there is no deadlock with admin subserver in this API. Here you can see how functions should be named in the client (virAdm*) and server (adm*). There is also a parameter @flags that must be 0, which helps testing proper error propagation into the client. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- daemon/admin_server.c | 22 ++++++++++++++++++++++ include/libvirt/libvirt-admin.h | 1 + po/POTFILES.in | 1 + src/admin/admin_protocol.x | 15 ++++++++++++++- src/admin_protocol-structs | 9 +++++++++ src/libvirt-admin.c | 26 ++++++++++++++++++++++++++ src/libvirt_admin.syms | 1 + 7 files changed, 74 insertions(+), 1 deletion(-) diff --git a/daemon/admin_server.c b/daemon/admin_server.c index 3f0939a..bbbef4d 100644 --- a/daemon/admin_server.c +++ b/daemon/admin_server.c @@ -94,4 +94,26 @@ adminDispatchConnectOpen(virNetSubServerPtr subserver ATTRIBUTE_UNUSED, return ret; } +static char * +admHello(virNetServerPtr srv, + unsigned int flags) +{ + char *ret = NULL; + virNetSubServerPtr subsrv = NULL; + size_t nclients; + + virCheckFlags(0, NULL); + + if (!(subsrv = virNetServerGetSubServer(srv, 0))) + return NULL; + + nclients = virNetSubServerGetNClients(subsrv); + if (virAsprintf(&ret, "Clients: %zu", nclients) < 0) + goto cleanup; + + cleanup: + virObjectUnref(subsrv); + return ret; +} + #include "admin_dispatch.h" diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h index 7fe03cf..f1f59b5 100644 --- a/include/libvirt/libvirt-admin.h +++ b/include/libvirt/libvirt-admin.h @@ -54,6 +54,7 @@ virAdmConnectPtr virAdmConnectOpen(unsigned int flags); int virAdmConnectClose(virAdmConnectPtr conn); int virAdmConnectRef(virAdmConnectPtr conn); +char *virAdmHello(virAdmConnectPtr conn, unsigned int flags); # ifdef __cplusplus } diff --git a/po/POTFILES.in b/po/POTFILES.in index 0378166..ae8ba19 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,3 +1,4 @@ +daemon/admin_dispatch.h daemon/admin_server.c daemon/libvirtd-config.c daemon/libvirtd.c diff --git a/src/admin/admin_protocol.x b/src/admin/admin_protocol.x index 3e1b28e..f1addaf 100644 --- a/src/admin/admin_protocol.x +++ b/src/admin/admin_protocol.x @@ -30,6 +30,14 @@ struct admin_connect_open_args { unsigned int flags; }; +struct admin_hello_args { + unsigned int flags; +}; + +struct admin_hello_ret { + remote_string greeting; +}; + /* Define the program number, protocol version and procedure numbers here. */ const ADMIN_PROGRAM = 0x06900690; @@ -56,5 +64,10 @@ enum admin_procedure { /** * @generate: none */ - ADMIN_PROC_CONNECT_OPEN = 1 + ADMIN_PROC_CONNECT_OPEN = 1, + + /** + * @generate: both + */ + ADMIN_PROC_HELLO = 2 }; diff --git a/src/admin_protocol-structs b/src/admin_protocol-structs index 6b2460d..ed1dd04 100644 --- a/src/admin_protocol-structs +++ b/src/admin_protocol-structs @@ -3,6 +3,15 @@ struct admin_connect_open_args { unsigned int flags; }; +struct admin_hello_args { + unsigned int flags; +}; + +struct admin_hello_ret { + remote_string greeting; +}; + enum admin_procedure { ADMIN_PROC_CONNECT_OPEN = 1, + ADMIN_PROC_HELLO = 2, }; diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c index e47089d..c69753c 100644 --- a/src/libvirt-admin.c +++ b/src/libvirt-admin.c @@ -335,3 +335,29 @@ virAdmConnectRef(virAdmConnectPtr conn) return 0; } + + +/** + * virAdmHello: + * @conn: a connection object + * @flags: unused, 0 for now + * + * Testing function. + * + * Returns the number of connected clients as a string. Yes, as a + * string. Because it's just for testing. + */ +char * +virAdmHello(virAdmConnectPtr conn, + unsigned int flags) +{ + char *ret = NULL; + + virResetLastError(); + + ret = remoteAdminHello(conn, flags); + if (!ret) + virDispatchError(conn); + + return ret; +} diff --git a/src/libvirt_admin.syms b/src/libvirt_admin.syms index 292433f..d6d2bc3 100644 --- a/src/libvirt_admin.syms +++ b/src/libvirt_admin.syms @@ -15,4 +15,5 @@ LIBVIRT_ADMIN_1.2.3 { virAdmInitialize; virAdmConnectOpen; virAdmConnectClose; + virAdmHello; }; -- 2.3.5

You had only one job. That's what you can say about this example binary. In future, parts of virsh that are usable for this binary should be split into separate shell-utils and virt-admin should gain all the cool features of virsh without too much code addition. Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- .gitignore | 2 ++ Makefile.am | 4 +-- configure.ac | 7 ++++- libvirt.spec.in | 2 ++ tools/virt-admin/Makefile.am | 70 +++++++++++++++++++++++++++++++++++++++++ tools/virt-admin/virt-admin.c | 68 +++++++++++++++++++++++++++++++++++++++ tools/virt-admin/virt-admin.pod | 43 +++++++++++++++++++++++++ 7 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 tools/virt-admin/Makefile.am create mode 100644 tools/virt-admin/virt-admin.c create mode 100644 tools/virt-admin/virt-admin.pod diff --git a/.gitignore b/.gitignore index d299063..d6964f9 100644 --- a/.gitignore +++ b/.gitignore @@ -173,6 +173,8 @@ /tools/virsh-*-edit.c /tools/virt-*-validate /tools/virt-sanlock-cleanup +/tools/virt-admin/virt-admin.1 +/tools/virt-admin/virt-admin /tools/wireshark/src/plugin.c /tools/wireshark/src/libvirt /update.log diff --git a/Makefile.am b/Makefile.am index 4aafe94..cdae769 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -## Copyright (C) 2005-2013 Red Hat, Inc. +## Copyright (C) 2005-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 @@ -24,7 +24,7 @@ SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \ examples/dominfo examples/domsuspend examples/apparmor \ examples/xml/nwfilter examples/openauth examples/systemtap \ tools/wireshark examples/dommigrate \ - examples/lxcconvert examples/domtop + examples/lxcconvert examples/domtop tools/virt-admin ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index d13f825..aa0cc4b 100644 --- a/configure.ac +++ b/configure.ac @@ -1694,6 +1694,10 @@ dnl virsh libraries VIRSH_LIBS="$VIRSH_LIBS $READLINE_LIBS" AC_SUBST([VIRSH_LIBS]) +dnl virt-admin libraries +VIRT_ADMIN_LIBS="$VIRT_ADMIN_LIBS $READLINE_LIBS" +AC_SUBST([VIRT_ADMIN_LIBS]) + dnl check if the network driver should be compiled AC_ARG_WITH([network], @@ -2825,7 +2829,8 @@ AC_CONFIG_FILES([\ examples/xml/nwfilter/Makefile \ examples/lxcconvert/Makefile \ tools/wireshark/Makefile \ - tools/wireshark/src/Makefile]) + tools/wireshark/src/Makefile \ + tools/virt-admin/Makefile]) AC_OUTPUT AC_MSG_NOTICE([]) diff --git a/libvirt.spec.in b/libvirt.spec.in index 7c13588..7cfd358 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2181,6 +2181,8 @@ exit 0 %if %{with_admin} %files admin %defattr(-, root, root) +%{_mandir}/man1/virt-admin.1* +%{_bindir}/virt-admin %{_libdir}/%{name}/libvirt_admin.so %endif diff --git a/tools/virt-admin/Makefile.am b/tools/virt-admin/Makefile.am new file mode 100644 index 0000000..47c9646 --- /dev/null +++ b/tools/virt-admin/Makefile.am @@ -0,0 +1,70 @@ +## 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/>. + +AM_CPPFLAGS = \ + -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_builddir)/gnulib/lib -I$(top_srcdir)/gnulib/lib \ + -I$(top_builddir)/src -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/util \ + -I$(top_srcdir) \ + $(GETTEXT_CPPFLAGS) + +AM_LDFLAGS = \ + $(RELRO_LDFLAGS) \ + $(NO_INDIRECT_LDFLAGS) \ + $(NULL) + +POD2MAN = pod2man -c "Virtualization Support" -r "$(PACKAGE)-$(VERSION)" + +EXTRA_DIST = virt-admin.pod + +DISTCLEANFILES = + +bin_PROGRAMS = virt-admin + +dist_man1_MANS = virt-admin.1 + +virt_admin_SOURCES = virt-admin.c + +virt_admin_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(COVERAGE_LDFLAGS) \ + $(NULL) + +virt_admin_LDADD = \ + $(STATIC_BINARIES) \ + $(PIE_LDFLAGS) \ + ../../src/libvirt.la \ + ../../src/libvirt-admin.la \ + $(top_srcdir)/gnulib/lib/libgnu.la \ + $(VIRT_ADMIN_LIBS) \ + $(NULL) + +virt_admin_CFLAGS = \ + $(WARN_CFLAGS) \ + $(PIE_CFLAGS) \ + $(COVERAGE_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(READLINE_CFLAGS) \ + $(NULL) + +virt-admin.1: virt-admin.pod $(top_srcdir)/configure.ac + $(AM_V_GEN)$(POD2MAN) $< $(srcdir)/$@ \ + && if grep 'POD ERROR' $(srcdir)/$@ ; then \ + rm $(srcdir)/$@; exit 1; fi + +CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda +MAINTAINERCLEANFILES = $(dist_man1_MANS) diff --git a/tools/virt-admin/virt-admin.c b/tools/virt-admin/virt-admin.c new file mode 100644 index 0000000..2e67882 --- /dev/null +++ b/tools/virt-admin/virt-admin.c @@ -0,0 +1,68 @@ +/* + * virt-admin.c: a shell to exercise the libvirt admin API + * + * 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/>. + * + * Martin Kletzander <mkletzan@redhat.com> + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <locale.h> + +#include "configmake.h" +#include "internal.h" + +#include <viralloc.h> + +int +main(int argc ATTRIBUTE_UNUSED, + char **argv ATTRIBUTE_UNUSED) +{ + int ret = EXIT_FAILURE; + char *greeting = NULL; + virAdmConnectPtr conn = NULL; + + if (!setlocale(LC_ALL, "")) { + perror("setlocale"); + /* failure to setup locale is not fatal */ + } + if (!bindtextdomain(PACKAGE, LOCALEDIR)) { + perror("bindtextdomain"); + return EXIT_FAILURE; + } + if (!textdomain(PACKAGE)) { + perror("textdomain"); + return EXIT_FAILURE; + } + + if (!(conn = virAdmConnectOpen(0))) + goto cleanup; + + if (!(greeting = virAdmHello(conn, 0))) + goto cleanup; + + printf("%s\n", greeting); + + ret = EXIT_SUCCESS; + cleanup: + VIR_FREE(greeting); + virAdmConnectClose(conn); + return ret; +} diff --git a/tools/virt-admin/virt-admin.pod b/tools/virt-admin/virt-admin.pod new file mode 100644 index 0000000..b82013b --- /dev/null +++ b/tools/virt-admin/virt-admin.pod @@ -0,0 +1,43 @@ +=head1 NAME + +virt-admin - client for admin interface of libvirt + +=head1 SYNOPSIS + +B<virt-admin> + +=head1 DESCRIPTION + +Libre ip_sum do { lor(); } sit; I'm @. + +=head1 EXIT STATUS + +It should be 0, really. + +=head1 BUGS + +None! + +=head1 AUTHORS + + Please refer to the AUTHORS file distributed with libvirt. + + Martin Kletzander <mkletzan@redhat.com> + +=head1 COPYRIGHT + +Copyright (C) 2014-2015 Red Hat, Inc., and the authors listed in the +libvirt AUTHORS file. + +=head1 LICENSE + +virt-admin is distributed under the terms of the GNU GPL v2+. This is +free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE + +=head1 SEE ALSO + +L<virsh(1)>, L<http://www.libvirt.org/> + +=cut -- 2.3.5

On Thu, Apr 16, 2015 at 04:46:36PM +0200, Martin Kletzander wrote:
Faster version of virJSONValueFromString(virJSONValueToString()).
Signed-off-by: Martin Kletzander <mkletzan@redhat.com> --- src/libvirt_private.syms | 1 + src/util/virjson.c | 65 ++++++++++++++++++++++++++- src/util/virjson.h | 4 +- tests/jsontest.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 2 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Thu, Apr 16, 2015 at 04:46:10PM +0200, Martin Kletzander wrote:
*** BLURB ***
...
Just kidding :)
Sooo... After very very VERY long time, here's a draft of an admin interface that is supposed to open up new possibilities to be done on a live daemon. The aim here is to create some first inches of that API in order to open up the possibility of new API function creation to more people.
I already spent so much time explaining so much of that that I don't know what else to point at in here. Maybe the fact that last three patches are just an example on how this might work. Of course there won't be any functions like listClientIDs with the need of getting each client info by another API. There's going to be e.g. virAdmClientInfo and virAdmGetClients() will return the list of them, etc. Long story short, let's not repeat past mistakes ;)
With all that said, feel free to hate, love, comment or just try out compiling this series and let me know how many things I've missed and screwed up (hopefully zero).
Broadly speaking I think this all looks like pretty good approach to me. We should probably think about exactly which API we want to target for inclusion in the first release. Perhaps the ability to change the logging filters & outputs would be the most useful one, as its something people often want to have in the production deployments where restarting libvirtd is not an option. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Fri, Apr 17, 2015 at 11:30:54AM +0100, Daniel P. Berrange wrote:
On Thu, Apr 16, 2015 at 04:46:10PM +0200, Martin Kletzander wrote:
*** BLURB ***
...
Just kidding :)
Sooo... After very very VERY long time, here's a draft of an admin interface that is supposed to open up new possibilities to be done on a live daemon. The aim here is to create some first inches of that API in order to open up the possibility of new API function creation to more people.
I already spent so much time explaining so much of that that I don't know what else to point at in here. Maybe the fact that last three patches are just an example on how this might work. Of course there won't be any functions like listClientIDs with the need of getting each client info by another API. There's going to be e.g. virAdmClientInfo and virAdmGetClients() will return the list of them, etc. Long story short, let's not repeat past mistakes ;)
With all that said, feel free to hate, love, comment or just try out compiling this series and let me know how many things I've missed and screwed up (hopefully zero).
Broadly speaking I think this all looks like pretty good approach to me. We should probably think about exactly which API we want to target for inclusion in the first release.
Perhaps the ability to change the logging filters & outputs would be the most useful one, as its something people often want to have in the production deployments where restarting libvirtd is not an option.
Logging settings should be one of the first ones, together with client connection information. We can continue with working with those connections (disconnecting, etc.), similarly to services (e.g. disabling TLS socket listening) adding events for all that, etc. My opinion is that logging stuff and connection listing should be in the first batch and we'll go on from that. Thanks for your input.

On Fri, 2015-04-17 at 11:30 +0100, Daniel P. Berrange wrote:
On Thu, Apr 16, 2015 at 04:46:10PM +0200, Martin Kletzander wrote:
*** BLURB ***
...
Just kidding :)
Sooo... After very very VERY long time, here's a draft of an admin interface that is supposed to open up new possibilities to be done on a live daemon. The aim here is to create some first inches of that API in order to open up the possibility of new API function creation to more people.
I already spent so much time explaining so much of that that I don't know what else to point at in here. Maybe the fact that last three patches are just an example on how this might work. Of course there won't be any functions like listClientIDs with the need of getting each client info by another API. There's going to be e.g. virAdmClientInfo and virAdmGetClients() will return the list of them, etc. Long story short, let's not repeat past mistakes ;)
With all that said, feel free to hate, love, comment or just try out compiling this series and let me know how many things I've missed and screwed up (hopefully zero).
Broadly speaking I think this all looks like pretty good approach to me. We should probably think about exactly which API we want to target for inclusion in the first release.
Perhaps the ability to change the logging filters & outputs would be the most useful one, as its something people often want to have in the production deployments where restarting libvirtd is not an option.
How about reloading the server TLS certificates? virNetTLSContextNew() contains the comment: /* Generate Diffie Hellman parameters - for use with DHE * kx algorithms. These should be discarded and regenerated * once a day, once a week or once a month. Depending on the * security requirements. */ If I understand correctly, currently one must restart libvirtd to pickup new certificates? I wondered whether Martin's patch 4/15 -- multiple NetSubServers -- would allow introduction of a new cert on a new SubServer w/o restarting libvirtd? E.g., to allow long running migration, blockcopy or other jobs to complete on existing connections before destroying them. If that would be possible, I think would would also be useful for early inclusion for people considering ephemeral certificates. Regards, Lee
Regards, Daniel

On Fri, Apr 17, 2015 at 09:31:58AM -0400, Lee Schermerhorn wrote:
On Fri, 2015-04-17 at 11:30 +0100, Daniel P. Berrange wrote:
On Thu, Apr 16, 2015 at 04:46:10PM +0200, Martin Kletzander wrote:
*** BLURB ***
...
Just kidding :)
Sooo... After very very VERY long time, here's a draft of an admin interface that is supposed to open up new possibilities to be done on a live daemon. The aim here is to create some first inches of that API in order to open up the possibility of new API function creation to more people.
I already spent so much time explaining so much of that that I don't know what else to point at in here. Maybe the fact that last three patches are just an example on how this might work. Of course there won't be any functions like listClientIDs with the need of getting each client info by another API. There's going to be e.g. virAdmClientInfo and virAdmGetClients() will return the list of them, etc. Long story short, let's not repeat past mistakes ;)
With all that said, feel free to hate, love, comment or just try out compiling this series and let me know how many things I've missed and screwed up (hopefully zero).
Broadly speaking I think this all looks like pretty good approach to me. We should probably think about exactly which API we want to target for inclusion in the first release.
Perhaps the ability to change the logging filters & outputs would be the most useful one, as its something people often want to have in the production deployments where restarting libvirtd is not an option.
Logging settings is definitely in the top of the list. My idea is that then we'll design some APIs for the introspection of the virNerServer (i.e. what is virNetSubServer in this series) like services, clients, rpm programs, whatever comes to mind. It would be nice if libvirt-1.3 (2.0 :) ) would have at least logging settings and info about connected clients. I'd say that's enough for the first tryout release. One question came up when we discussed Admin API with Michal. Can we say something in the sense of "this is not stable yet and the API can change"? It would help us speed up some prototyping, but I don't think this is possible simply because we guarantee full backward compatibility.
How about reloading the server TLS certificates?
virNetTLSContextNew() contains the comment:
/* Generate Diffie Hellman parameters - for use with DHE * kx algorithms. These should be discarded and regenerated * once a day, once a week or once a month. Depending on the * security requirements. */
If I understand correctly, currently one must restart libvirtd to pickup new certificates? I wondered whether Martin's patch 4/15 -- multiple NetSubServers -- would allow introduction of a new cert on a new SubServer w/o restarting libvirtd? E.g., to allow long running migration, blockcopy or other jobs to complete on existing connections before destroying them.
I haven't checked the internals of this, but it sounds like a good idea. However, the introspection mentioned beforehand must be completed first, otherwise we cannot get to the TLS service. Therefore I'd see this arriving a bit later than in the first trial series. However, others should be encouraged to implement APIs for this ;)
If that would be possible, I think would would also be useful for early inclusion for people considering ephemeral certificates.
Regards, Lee
Regards, Daniel
participants (4)
-
Daniel P. Berrange
-
Lee Schermerhorn
-
Martin Kletzander
-
Michal Privoznik