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
virNetTLSContextPtr tls,
#endif
bool readonly,
- size_t nrequests_max)
+ size_t nrequests_max,
+ time_t timestamp)
{
virNetServerClientPtr client;
client->tlsCtxt = virObjectRef(tls);
#endif
client->nrequests_max = nrequests_max;
+ client->conn_time = timestamp;
client->sockTimer = virEventAddTimeout(-1, virNetServerClientSockTimerFunc,
client, NULL);
void *privOpaque)
{
virNetServerClientPtr client;
+ time_t now;
VIR_DEBUG("sock=%p auth=%d tls=%p", sock, auth,
#ifdef WITH_GNUTLS
#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) {
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",
}
}
+ 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;
NULL,
#endif
readonly,
- nrequests_max))) {
+ nrequests_max,
+ timestamp))) {
virObjectUnref(sock);
return NULL;
}
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;
return client->id;
}
+long long virNetServerClientGetTimestamp(virNetServerClientPtr client)
+{
+ return client->conn_time;
+}
+
#ifdef WITH_GNUTLS
bool virNetServerClientHasTLSSession(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);
test_libraries = libshunload.la \
virportallocatormock.la \
+ virnetdaemonmock.la \
virnetserverclientmock.la \
vircgroupmock.la \
virpcimock.la \
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
--- /dev/null
+{
+ "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,
+ "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
+ }
+ }
+ ]
+ }
+ }
+}
--- /dev/null
+{
+ "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,
+ "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
+ }
+ }
+ ]
+ }
+ }
+}
--- /dev/null
+/*
+ * 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@redhat.com>
+ */
+
+#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;
+}
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