Besides ID, libvirt should provide several parameters to help the user distinguish two clients from each other. One of them is the connection timestamp. This patch also adds a testcase for proper JSON formatting of the new attribute too (proper formatting of older clients that did not support this attribute yet is included in the existing tests) - in order to testGenerateJSON to work, a mock of time_t time(time_t *timer) needed to be created. Signed-off-by: Erik Skultety <eskultet@xxxxxxxxxx> --- src/rpc/virnetserverclient.c | 46 +++++++++++++- src/rpc/virnetserverclient.h | 1 + tests/Makefile.am | 7 +++ .../input-data-client-timestamp.json | 71 ++++++++++++++++++++++ .../output-data-client-timestamp.json | 71 ++++++++++++++++++++++ tests/virnetdaemonmock.c | 34 +++++++++++ tests/virnetdaemontest.c | 4 +- 7 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 tests/virnetdaemondata/input-data-client-timestamp.json create mode 100644 tests/virnetdaemondata/output-data-client-timestamp.json create mode 100644 tests/virnetdaemonmock.c diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 7233773..a1543b9 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -85,6 +85,13 @@ struct _virNetServerClient virIdentityPtr identity; + /* Connection timestamp, i.e. when a client connected to the daemon (UTC). + * For old clients restored by post-exec-restart, which did not have this + * attribute, value of 0 (epoch time) is used to indicate we have no + * information about their connection time. + */ + time_t conn_time; + /* Count of messages in the 'tx' queue, * and the server worker pool queue * ie RPC calls in progress. Does not count @@ -355,7 +362,8 @@ virNetServerClientNewInternal(unsigned long long id, virNetTLSContextPtr tls, #endif bool readonly, - size_t nrequests_max) + size_t nrequests_max, + time_t timestamp) { virNetServerClientPtr client; @@ -373,6 +381,7 @@ virNetServerClientNewInternal(unsigned long long id, client->tlsCtxt = virObjectRef(tls); #endif client->nrequests_max = nrequests_max; + client->conn_time = timestamp; client->sockTimer = virEventAddTimeout(-1, virNetServerClientSockTimerFunc, client, NULL); @@ -413,6 +422,7 @@ virNetServerClientPtr virNetServerClientNew(unsigned long long id, void *privOpaque) { virNetServerClientPtr client; + time_t now; VIR_DEBUG("sock=%p auth=%d tls=%p", sock, auth, #ifdef WITH_GNUTLS @@ -422,11 +432,17 @@ virNetServerClientPtr virNetServerClientNew(unsigned long long id, #endif ); + if ((now = time(NULL)) == (time_t) - 1) { + virReportSystemError(errno, "%s", _("failed to get current time")); + return NULL; + } + if (!(client = virNetServerClientNewInternal(id, sock, auth, #ifdef WITH_GNUTLS tls, #endif - readonly, nrequests_max))) + readonly, nrequests_max, + now))) return NULL; if (privNew) { @@ -456,6 +472,7 @@ virNetServerClientPtr virNetServerClientNewPostExecRestart(virJSONValuePtr objec bool readonly; unsigned int nrequests_max; unsigned long long id; + time_t timestamp; if (virJSONValueObjectGetNumberInt(object, "auth", &auth) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -492,6 +509,18 @@ virNetServerClientPtr virNetServerClientNewPostExecRestart(virJSONValuePtr objec } } + if (!virJSONValueObjectHasKey(object, "conn_time")) { + timestamp = 0; + } else { + if (virJSONValueObjectGetNumberLong(object, "conn_time", + (long long *) ×tamp) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed conn_time field in JSON " + "state document")); + return NULL; + } + } + if (!(sock = virNetSocketNewPostExecRestart(child))) { virObjectUnref(sock); return NULL; @@ -504,7 +533,8 @@ virNetServerClientPtr virNetServerClientNewPostExecRestart(virJSONValuePtr objec NULL, #endif readonly, - nrequests_max))) { + nrequests_max, + timestamp))) { virObjectUnref(sock); return NULL; } @@ -552,6 +582,11 @@ virJSONValuePtr virNetServerClientPreExecRestart(virNetServerClientPtr client) if (virJSONValueObjectAppendNumberUint(object, "nrequests_max", client->nrequests_max) < 0) goto error; + if (client->conn_time && + virJSONValueObjectAppendNumberLong(object, "conn_time", + client->conn_time) < 0) + goto error; + if (!(child = virNetSocketPreExecRestart(client->sock))) goto error; @@ -610,6 +645,11 @@ unsigned long long virNetServerClientGetID(virNetServerClientPtr client) return client->id; } +long long virNetServerClientGetTimestamp(virNetServerClientPtr client) +{ + return client->conn_time; +} + #ifdef WITH_GNUTLS bool virNetServerClientHasTLSSession(virNetServerClientPtr client) { diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h index 95edb06..e68ef76 100644 --- a/src/rpc/virnetserverclient.h +++ b/src/rpc/virnetserverclient.h @@ -82,6 +82,7 @@ int virNetServerClientGetAuth(virNetServerClientPtr client); void virNetServerClientSetAuth(virNetServerClientPtr client, int auth); bool virNetServerClientGetReadonly(virNetServerClientPtr client); unsigned long long virNetServerClientGetID(virNetServerClientPtr client); +long long virNetServerClientGetTimestamp(virNetServerClientPtr client); # ifdef WITH_GNUTLS bool virNetServerClientHasTLSSession(virNetServerClientPtr client); diff --git a/tests/Makefile.am b/tests/Makefile.am index db4f88b..4a8407e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -422,6 +422,7 @@ EXTRA_DIST += $(test_scripts) test_libraries = libshunload.la \ virportallocatormock.la \ + virnetdaemonmock.la \ virnetserverclientmock.la \ vircgroupmock.la \ virpcimock.la \ @@ -949,6 +950,12 @@ virnetdaemontest_SOURCES = \ virnetdaemontest_CFLAGS = $(XDR_CFLAGS) $(AM_CFLAGS) virnetdaemontest_LDADD = $(LDADDS) +virnetdaemonmock_la_SOURCES = \ + virnetdaemonmock.c +virnetdaemonmock_la_CFLAGS = $(AM_CFLAGS) +virnetdaemonmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) +virnetdaemonmock_la_LIBADD = $(MOCKLIBS_LIBS) + virnetserverclienttest_SOURCES = \ virnetserverclienttest.c \ testutils.h testutils.c diff --git a/tests/virnetdaemondata/input-data-client-timestamp.json b/tests/virnetdaemondata/input-data-client-timestamp.json new file mode 100644 index 0000000..386e6c5 --- /dev/null +++ b/tests/virnetdaemondata/input-data-client-timestamp.json @@ -0,0 +1,71 @@ +{ + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 10, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "mdnsGroupName": "libvirtTest", + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "conn_time": 1234567890, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "conn_time": 1234567890, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] + } + } +} diff --git a/tests/virnetdaemondata/output-data-client-timestamp.json b/tests/virnetdaemondata/output-data-client-timestamp.json new file mode 100644 index 0000000..386e6c5 --- /dev/null +++ b/tests/virnetdaemondata/output-data-client-timestamp.json @@ -0,0 +1,71 @@ +{ + "servers": { + "testServer0": { + "min_workers": 10, + "max_workers": 50, + "priority_workers": 5, + "max_clients": 100, + "max_anonymous_clients": 10, + "keepaliveInterval": 120, + "keepaliveCount": 5, + "next_client_id": 3, + "mdnsGroupName": "libvirtTest", + "services": [ + { + "auth": 0, + "readonly": true, + "nrequests_client_max": 2, + "socks": [ + { + "fd": 100, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + }, + { + "auth": 2, + "readonly": false, + "nrequests_client_max": 5, + "socks": [ + { + "fd": 101, + "errfd": -1, + "pid": 0, + "isClient": false + } + ] + } + ], + "clients": [ + { + "id": 1, + "auth": 1, + "readonly": true, + "nrequests_max": 15, + "conn_time": 1234567890, + "sock": { + "fd": 102, + "errfd": -1, + "pid": -1, + "isClient": true + } + }, + { + "id": 2, + "auth": 2, + "readonly": true, + "nrequests_max": 66, + "conn_time": 1234567890, + "sock": { + "fd": 103, + "errfd": -1, + "pid": -1, + "isClient": true + } + } + ] + } + } +} diff --git a/tests/virnetdaemonmock.c b/tests/virnetdaemonmock.c new file mode 100644 index 0000000..6d807a5 --- /dev/null +++ b/tests/virnetdaemonmock.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2016 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: Erik Skultety <eskultet@xxxxxxxxxx> + */ + +#include <config.h> + +#include "internal.h" +#include <time.h> + +#define VIR_FROM_THIS VIR_FROM_NONE + +time_t time(time_t *t) +{ + const time_t ret = 1234567890; + if (t) + *t = ret; + return ret; +} diff --git a/tests/virnetdaemontest.c b/tests/virnetdaemontest.c index b98c148..714f8d7 100644 --- a/tests/virnetdaemontest.c +++ b/tests/virnetdaemontest.c @@ -339,15 +339,17 @@ mymain(void) EXEC_RESTART_TEST("admin-server-names", 2); EXEC_RESTART_TEST("no-keepalive-required", 2); EXEC_RESTART_TEST("client-ids", 1); + EXEC_RESTART_TEST("client-timestamp", 1); EXEC_RESTART_TEST_FAIL("anon-clients", 2); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } +VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virnetdaemonmock.so") #else static int mymain(void) { return EXIT_AM_SKIP; } -#endif VIRT_TEST_MAIN(mymain); +#endif -- 2.4.11 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list