Move daemon-related parts of virNetServer to virNetDaemon

This allows to have more servers in one daemon which helps isolating
some resources.

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
This commit is contained in:
Martin Kletzander 2015-03-16 15:02:41 +01:00
parent 387cb8c6b2
commit fa14207368
15 changed files with 1086 additions and 604 deletions

View File

@ -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
@ -49,7 +49,7 @@
#include "viralloc.h"
#include "virconf.h"
#include "virnetlink.h"
#include "virnetserver.h"
#include "virnetdaemon.h"
#include "remote.h"
#include "virhook.h"
#include "viraudit.h"
@ -776,14 +776,14 @@ daemonSetupPrivs(void)
#endif
static void daemonShutdownHandler(virNetServerPtr srv,
static void daemonShutdownHandler(virNetDaemonPtr dmn,
siginfo_t *sig ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
virNetServerQuit(srv);
virNetDaemonQuit(dmn);
}
static void daemonReloadHandler(virNetServerPtr srv ATTRIBUTE_UNUSED,
static void daemonReloadHandler(virNetDaemonPtr dmn ATTRIBUTE_UNUSED,
siginfo_t *sig ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
@ -799,15 +799,15 @@ static void daemonReloadHandler(virNetServerPtr srv ATTRIBUTE_UNUSED,
VIR_WARN("Error while reloading drivers");
}
static int daemonSetupSignals(virNetServerPtr srv)
static int daemonSetupSignals(virNetDaemonPtr dmn)
{
if (virNetServerAddSignalHandler(srv, SIGINT, daemonShutdownHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGINT, daemonShutdownHandler, NULL) < 0)
return -1;
if (virNetServerAddSignalHandler(srv, SIGQUIT, daemonShutdownHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGQUIT, daemonShutdownHandler, NULL) < 0)
return -1;
if (virNetServerAddSignalHandler(srv, SIGTERM, daemonShutdownHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGTERM, daemonShutdownHandler, NULL) < 0)
return -1;
if (virNetServerAddSignalHandler(srv, SIGHUP, daemonReloadHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGHUP, daemonReloadHandler, NULL) < 0)
return -1;
return 0;
}
@ -815,12 +815,12 @@ static int daemonSetupSignals(virNetServerPtr srv)
static void daemonInhibitCallback(bool inhibit, void *opaque)
{
virNetServerPtr srv = opaque;
virNetDaemonPtr dmn = opaque;
if (inhibit)
virNetServerAddShutdownInhibition(srv);
virNetDaemonAddShutdownInhibition(dmn);
else
virNetServerRemoveShutdownInhibition(srv);
virNetDaemonRemoveShutdownInhibition(dmn);
}
@ -830,26 +830,26 @@ static DBusConnection *systemBus;
static void daemonStopWorker(void *opaque)
{
virNetServerPtr srv = opaque;
virNetDaemonPtr dmn = opaque;
VIR_DEBUG("Begin stop srv=%p", srv);
VIR_DEBUG("Begin stop dmn=%p", dmn);
ignore_value(virStateStop());
VIR_DEBUG("Completed stop srv=%p", srv);
VIR_DEBUG("Completed stop dmn=%p", dmn);
/* Exit libvirtd cleanly */
virNetServerQuit(srv);
virNetDaemonQuit(dmn);
}
/* We do this in a thread to not block the main loop */
static void daemonStop(virNetServerPtr srv)
static void daemonStop(virNetDaemonPtr dmn)
{
virThread thr;
virObjectRef(srv);
if (virThreadCreate(&thr, false, daemonStopWorker, srv) < 0)
virObjectUnref(srv);
virObjectRef(dmn);
if (virThreadCreate(&thr, false, daemonStopWorker, dmn) < 0)
virObjectUnref(dmn);
}
@ -858,14 +858,14 @@ handleSessionMessageFunc(DBusConnection *connection ATTRIBUTE_UNUSED,
DBusMessage *message,
void *opaque)
{
virNetServerPtr srv = opaque;
virNetDaemonPtr dmn = opaque;
VIR_DEBUG("srv=%p", srv);
VIR_DEBUG("dmn=%p", dmn);
if (dbus_message_is_signal(message,
DBUS_INTERFACE_LOCAL,
"Disconnected"))
daemonStop(srv);
daemonStop(dmn);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@ -876,14 +876,14 @@ handleSystemMessageFunc(DBusConnection *connection ATTRIBUTE_UNUSED,
DBusMessage *message,
void *opaque)
{
virNetServerPtr srv = opaque;
virNetDaemonPtr dmn = opaque;
VIR_DEBUG("srv=%p", srv);
VIR_DEBUG("dmn=%p", dmn);
if (dbus_message_is_signal(message,
"org.freedesktop.login1.Manager",
"PrepareForShutdown"))
daemonStop(srv);
daemonStop(dmn);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@ -892,22 +892,22 @@ handleSystemMessageFunc(DBusConnection *connection ATTRIBUTE_UNUSED,
static void daemonRunStateInit(void *opaque)
{
virNetServerPtr srv = opaque;
virNetDaemonPtr dmn = opaque;
virIdentityPtr sysident = virIdentityGetSystem();
virIdentitySetCurrent(sysident);
/* Since driver initialization can take time inhibit daemon shutdown until
we're done so clients get a chance to connect */
daemonInhibitCallback(true, srv);
daemonInhibitCallback(true, dmn);
/* Start the stateful HV drivers
* This is deliberately done after telling the parent process
* we're ready, since it can take a long time and this will
* seriously delay OS bootup process */
if (virStateInitialize(virNetServerIsPrivileged(srv),
if (virStateInitialize(virNetDaemonIsPrivileged(dmn),
daemonInhibitCallback,
srv) < 0) {
dmn) < 0) {
VIR_ERROR(_("Driver state initialization failed"));
/* Ensure the main event loop quits */
kill(getpid(), SIGTERM);
@ -918,17 +918,17 @@ static void daemonRunStateInit(void *opaque)
#ifdef HAVE_DBUS
/* Tie the non-priviledged libvirtd to the session/shutdown lifecycle */
if (!virNetServerIsPrivileged(srv)) {
if (!virNetDaemonIsPrivileged(dmn)) {
sessionBus = virDBusGetSessionBus();
if (sessionBus != NULL)
dbus_connection_add_filter(sessionBus,
handleSessionMessageFunc, srv, NULL);
handleSessionMessageFunc, dmn, NULL);
systemBus = virDBusGetSystemBus();
if (systemBus != NULL) {
dbus_connection_add_filter(systemBus,
handleSystemMessageFunc, srv, NULL);
handleSystemMessageFunc, dmn, NULL);
dbus_bus_add_match(systemBus,
"type='signal',sender='org.freedesktop.login1', interface='org.freedesktop.login1.Manager'",
NULL);
@ -936,20 +936,20 @@ static void daemonRunStateInit(void *opaque)
}
#endif
/* Only now accept clients from network */
virNetServerUpdateServices(srv, true);
virNetDaemonUpdateServices(dmn, true);
cleanup:
daemonInhibitCallback(false, srv);
virObjectUnref(srv);
daemonInhibitCallback(false, dmn);
virObjectUnref(dmn);
virObjectUnref(sysident);
virIdentitySetCurrent(NULL);
}
static int daemonStateInit(virNetServerPtr srv)
static int daemonStateInit(virNetDaemonPtr dmn)
{
virThread thr;
virObjectRef(srv);
if (virThreadCreate(&thr, false, daemonRunStateInit, srv) < 0) {
virObjectUnref(srv);
virObjectRef(dmn);
if (virThreadCreate(&thr, false, daemonRunStateInit, dmn) < 0) {
virObjectUnref(dmn);
return -1;
}
return 0;
@ -1100,6 +1100,7 @@ daemonUsage(const char *argv0, bool privileged)
}
int main(int argc, char **argv) {
virNetDaemonPtr dmn = NULL;
virNetServerPtr srv = NULL;
char *remote_config_file = NULL;
int statuswrite = -1;
@ -1354,6 +1355,12 @@ int main(int argc, char **argv) {
goto cleanup;
}
if (!(dmn = virNetDaemonNew()) ||
virNetDaemonAddServer(dmn, srv) < 0) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
/* Beyond this point, nothing should rely on using
* getuid/geteuid() == 0, for privilege level checks.
*/
@ -1408,11 +1415,10 @@ int main(int argc, char **argv) {
if (timeout != -1) {
VIR_DEBUG("Registering shutdown timeout %d", timeout);
virNetServerAutoShutdown(srv,
timeout);
virNetDaemonAutoShutdown(dmn, timeout);
}
if ((daemonSetupSignals(srv)) < 0) {
if ((daemonSetupSignals(dmn)) < 0) {
ret = VIR_DAEMON_ERR_SIGNAL;
goto cleanup;
}
@ -1467,7 +1473,7 @@ int main(int argc, char **argv) {
}
/* Initialize drivers & then start accepting new clients from network */
if (daemonStateInit(srv) < 0) {
if (daemonStateInit(dmn) < 0) {
ret = VIR_DAEMON_ERR_INIT;
goto cleanup;
}
@ -1489,7 +1495,7 @@ int main(int argc, char **argv) {
#endif
/* Run event loop. */
virNetServerRun(srv);
virNetDaemonRun(dmn);
ret = 0;
@ -1501,7 +1507,8 @@ int main(int argc, char **argv) {
virObjectUnref(remoteProgram);
virObjectUnref(lxcProgram);
virObjectUnref(qemuProgram);
virNetServerClose(srv);
virNetDaemonClose(dmn);
virObjectUnref(dmn);
virObjectUnref(srv);
virNetlinkShutdown();
if (statuswrite != -1) {

View File

@ -82,7 +82,9 @@
<ul>
<li>Daemon Startup
<p>The daemon initialization processing will declare itself
as a server via a virNetServerNew() call, then use
as a daemon via a virNetDaemonNew() call, then creates new server
using virNetServerNew() and adds that server to the main daemon
struct with virNetDaemonAddServer() call. It will then use
virDriverLoadModule() to find/load all known drivers,
set up an RPC server program using the <code>remoteProcs[]</code>
table via a virNetServerProgramNew() call. The table is the

View File

@ -532,6 +532,13 @@
calls in parallel, with dispatch across multiple worker threads.
</dd>
<dt><code>virNetDaemonPtr</code> (virnetdaemon.h)</dt>
<dd>The virNetDaemon APIs are used to manage a daemon process. A
deamon is a process that might expose one or more servers. It
handles most process-related details, network-related should
be part of the underlying server.
</dd>
<dt><code>virNetServerMDNSPtr</code> (virnetservermdns.h)</dt>
<dd>The virNetServerMDNS APIs are used to advertise a server
across the local network, enabling clients to automatically

View File

@ -132,6 +132,7 @@ src/rpc/virkeepalive.c
src/rpc/virnetclient.c
src/rpc/virnetclientprogram.c
src/rpc/virnetclientstream.c
src/rpc/virnetdaemon.c
src/rpc/virnetmessage.c
src/rpc/virnetsaslcontext.c
src/rpc/virnetsocket.c

View File

@ -2507,6 +2507,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/virnetdaemon.h rpc/virnetdaemon.c \
rpc/virnetserver.h rpc/virnetserver.c
libvirt_net_rpc_server_la_CFLAGS = \
$(AVAHI_CFLAGS) \

View File

@ -57,6 +57,24 @@ virNetClientStreamSendPacket;
virNetClientStreamSetError;
# rpc/virnetdaemon.h
virNetDaemonAddServer;
virNetDaemonAddServerPostExec;
virNetDaemonAddShutdownInhibition;
virNetDaemonAddSignalHandler;
virNetDaemonAutoShutdown;
virNetDaemonClose;
virNetDaemonGetServer;
virNetDaemonIsPrivileged;
virNetDaemonNew;
virNetDaemonNewPostExecRestart;
virNetDaemonPreExecRestart;
virNetDaemonQuit;
virNetDaemonRemoveShutdownInhibition;
virNetDaemonRun;
virNetDaemonUpdateServices;
# rpc/virnetmessage.h
virNetMessageClear;
virNetMessageDecodeHeader;
@ -80,18 +98,16 @@ xdr_virNetMessageError;
virNetServerAddClient;
virNetServerAddProgram;
virNetServerAddService;
virNetServerAddShutdownInhibition;
virNetServerAddSignalHandler;
virNetServerAutoShutdown;
virNetServerClose;
virNetServerIsPrivileged;
virNetServerHasClients;
virNetServerKeepAliveRequired;
virNetServerNew;
virNetServerNewPostExecRestart;
virNetServerPreExecRestart;
virNetServerQuit;
virNetServerRemoveShutdownInhibition;
virNetServerRun;
virNetServerProcessClients;
virNetServerStart;
virNetServerTrackCompletedAuth;
virNetServerTrackPendingAuth;
virNetServerUpdateServices;

View File

@ -1,7 +1,7 @@
/*
* lock_daemon.c: lock management daemon
*
* 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
@ -41,6 +41,7 @@
#include "virlog.h"
#include "viralloc.h"
#include "virconf.h"
#include "rpc/virnetdaemon.h"
#include "rpc/virnetserver.h"
#include "virrandom.h"
#include "virhash.h"
@ -60,6 +61,7 @@ VIR_LOG_INIT("locking.lock_daemon");
struct _virLockDaemon {
virMutex lock;
virNetDaemonPtr dmn;
virNetServerPtr srv;
virHashTablePtr lockspaces;
virLockSpacePtr defaultLockspace;
@ -118,6 +120,7 @@ virLockDaemonFree(virLockDaemonPtr lockd)
return;
virObjectUnref(lockd->srv);
virObjectUnref(lockd->dmn);
virHashFree(lockd->lockspaces);
virLockSpaceFree(lockd->defaultLockspace);
@ -155,6 +158,10 @@ virLockDaemonNew(virLockDaemonConfigPtr config, bool privileged)
(void*)(intptr_t)(privileged ? 0x1 : 0x0))))
goto error;
if (!(lockd->dmn = virNetDaemonNew()) ||
virNetDaemonAddServer(lockd->dmn, lockd->srv) < 0)
goto error;
if (!(lockd->lockspaces = virHashCreate(VIR_LOCK_DAEMON_NUM_LOCKSPACES,
virLockDaemonLockSpaceDataFree)))
goto error;
@ -230,13 +237,24 @@ virLockDaemonNewPostExecRestart(virJSONValuePtr object, bool privileged)
}
}
if (virJSONValueObjectHasKey(object, "daemon")) {
if (!(child = virJSONValueObjectGet(object, "daemon"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Malformed daemon data from JSON file"));
goto error;
}
} else {
if (!(child = virJSONValueObjectGet(object, "server"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Missing server data from JSON file"));
goto error;
}
}
if (!(lockd->srv = virNetServerNewPostExecRestart(child,
if (!(lockd->dmn = virNetDaemonNewPostExecRestart(child)))
goto error;
if (!(lockd->srv = virNetDaemonAddServerPostExec(lockd->dmn,
virLockDaemonClientNew,
virLockDaemonClientNewPostExecRestart,
virLockDaemonClientPreExecRestart,
@ -529,32 +547,32 @@ virLockDaemonVersion(const char *argv0)
}
static void
virLockDaemonShutdownHandler(virNetServerPtr srv,
virLockDaemonShutdownHandler(virNetDaemonPtr dmn,
siginfo_t *sig ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
virNetServerQuit(srv);
virNetDaemonQuit(dmn);
}
static void
virLockDaemonExecRestartHandler(virNetServerPtr srv,
virLockDaemonExecRestartHandler(virNetDaemonPtr dmn,
siginfo_t *sig ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
execRestart = true;
virNetServerQuit(srv);
virNetDaemonQuit(dmn);
}
static int
virLockDaemonSetupSignals(virNetServerPtr srv)
virLockDaemonSetupSignals(virNetDaemonPtr dmn)
{
if (virNetServerAddSignalHandler(srv, SIGINT, virLockDaemonShutdownHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGINT, virLockDaemonShutdownHandler, NULL) < 0)
return -1;
if (virNetServerAddSignalHandler(srv, SIGQUIT, virLockDaemonShutdownHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGQUIT, virLockDaemonShutdownHandler, NULL) < 0)
return -1;
if (virNetServerAddSignalHandler(srv, SIGTERM, virLockDaemonShutdownHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGTERM, virLockDaemonShutdownHandler, NULL) < 0)
return -1;
if (virNetServerAddSignalHandler(srv, SIGUSR1, virLockDaemonExecRestartHandler, NULL) < 0)
if (virNetDaemonAddSignalHandler(dmn, SIGUSR1, virLockDaemonExecRestartHandler, NULL) < 0)
return -1;
return 0;
}
@ -966,7 +984,7 @@ virLockDaemonPostExecRestart(const char *state_file,
static int
virLockDaemonPreExecRestart(const char *state_file,
virNetServerPtr srv,
virNetDaemonPtr dmn,
char **argv)
{
virJSONValuePtr child;
@ -982,10 +1000,10 @@ virLockDaemonPreExecRestart(const char *state_file,
if (!(object = virJSONValueNewObject()))
goto cleanup;
if (!(child = virNetServerPreExecRestart(srv)))
if (!(child = virNetDaemonPreExecRestart(dmn)))
goto cleanup;
if (virJSONValueObjectAppend(object, "server", child) < 0) {
if (virJSONValueObjectAppend(object, "daemon", child) < 0) {
virJSONValueFree(child);
goto cleanup;
}
@ -1350,11 +1368,11 @@ int main(int argc, char **argv) {
if (timeout != -1) {
VIR_DEBUG("Registering shutdown timeout %d", timeout);
virNetServerAutoShutdown(lockDaemon->srv,
virNetDaemonAutoShutdown(lockDaemon->dmn,
timeout);
}
if ((virLockDaemonSetupSignals(lockDaemon->srv)) < 0) {
if ((virLockDaemonSetupSignals(lockDaemon->dmn)) < 0) {
ret = VIR_LOCK_DAEMON_ERR_SIGNAL;
goto cleanup;
}
@ -1366,6 +1384,7 @@ int main(int argc, char **argv) {
ret = VIR_LOCK_DAEMON_ERR_INIT;
goto cleanup;
}
if (virNetServerAddProgram(lockDaemon->srv, lockProgram) < 0) {
ret = VIR_LOCK_DAEMON_ERR_INIT;
goto cleanup;
@ -1389,12 +1408,12 @@ int main(int argc, char **argv) {
/* Start accepting new clients from network */
virNetServerUpdateServices(lockDaemon->srv, true);
virNetServerRun(lockDaemon->srv);
virNetDaemonUpdateServices(lockDaemon->dmn, true);
virNetDaemonRun(lockDaemon->dmn);
if (execRestart &&
virLockDaemonPreExecRestart(state_file,
lockDaemon->srv,
lockDaemon->dmn,
argv) < 0)
ret = VIR_LOCK_DAEMON_ERR_REEXEC;
else

View File

@ -28,7 +28,7 @@
#include "viralloc.h"
#include "virerror.h"
#include "virlog.h"
#include "rpc/virnetserver.h"
#include "rpc/virnetdaemon.h"
#include "configmake.h"
#include "virstring.h"
#include "virutil.h"

View File

@ -1,7 +1,7 @@
/*
* lock_daemon_dispatch.c: lock management daemon dispatch
*
* Copyright (C) 2006-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
@ -22,7 +22,7 @@
#include <config.h>
#include "rpc/virnetserver.h"
#include "rpc/virnetdaemon.h"
#include "rpc/virnetserverclient.h"
#include "virlog.h"
#include "virstring.h"

View File

@ -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
@ -65,7 +65,7 @@
#include "virprocess.h"
#include "virnuma.h"
#include "virdbus.h"
#include "rpc/virnetserver.h"
#include "rpc/virnetdaemon.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@ -93,7 +93,7 @@ struct _virLXCControllerConsole {
size_t fromContLen;
char fromContBuf[1024];
virNetServerPtr server;
virNetDaemonPtr daemon;
};
typedef struct _virLXCController virLXCController;
@ -128,8 +128,7 @@ struct _virLXCController {
virSecurityManagerPtr securityManager;
/* Server socket */
virNetServerPtr server;
virNetDaemonPtr daemon;
bool firstClient;
virNetServerClientPtr client;
virNetServerProgramPtr prog;
@ -152,7 +151,7 @@ static void virLXCControllerQuitTimer(int timer ATTRIBUTE_UNUSED, void *opaque)
virLXCControllerPtr ctrl = opaque;
VIR_DEBUG("Triggering event loop quit");
virNetServerQuit(ctrl->server);
virNetDaemonQuit(ctrl->daemon);
}
@ -283,7 +282,7 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl)
if (ctrl->timerShutdown != -1)
virEventRemoveTimeout(ctrl->timerShutdown);
virObjectUnref(ctrl->server);
virObjectUnref(ctrl->daemon);
virLXCControllerFreeFuse(ctrl);
VIR_FREE(ctrl->nbdpids);
@ -301,7 +300,7 @@ static int virLXCControllerAddConsole(virLXCControllerPtr ctrl,
{
if (VIR_EXPAND_N(ctrl->consoles, ctrl->nconsoles, 1) < 0)
return -1;
ctrl->consoles[ctrl->nconsoles-1].server = ctrl->server;
ctrl->consoles[ctrl->nconsoles-1].daemon = ctrl->daemon;
ctrl->consoles[ctrl->nconsoles-1].hostFd = hostFd;
ctrl->consoles[ctrl->nconsoles-1].hostWatch = -1;
@ -902,6 +901,7 @@ static void *virLXCControllerClientPrivateNew(virNetServerClientPtr client,
static int virLXCControllerSetupServer(virLXCControllerPtr ctrl)
{
virNetServerPtr srv = NULL;
virNetServerServicePtr svc = NULL;
char *sockpath;
@ -909,7 +909,7 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl)
LXC_STATE_DIR, ctrl->name) < 0)
return -1;
if (!(ctrl->server = virNetServerNew(0, 0, 0, 1,
if (!(srv = virNetServerNew(0, 0, 0, 1,
0, -1, 0, false,
NULL,
virLXCControllerClientPrivateNew,
@ -936,7 +936,7 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl)
if (virSecurityManagerClearSocketLabel(ctrl->securityManager, ctrl->def) < 0)
goto error;
if (virNetServerAddService(ctrl->server, svc, NULL) < 0)
if (virNetServerAddService(srv, svc, NULL) < 0)
goto error;
virObjectUnref(svc);
svc = NULL;
@ -947,14 +947,19 @@ static int virLXCControllerSetupServer(virLXCControllerPtr ctrl)
virLXCMonitorNProcs)))
goto error;
virNetServerUpdateServices(ctrl->server, true);
if (!(ctrl->daemon = virNetDaemonNew()) ||
virNetDaemonAddServer(ctrl->daemon, srv) < 0)
goto error;
virNetDaemonUpdateServices(ctrl->daemon, true);
VIR_FREE(sockpath);
return 0;
error:
VIR_FREE(sockpath);
virObjectUnref(ctrl->server);
ctrl->server = NULL;
virObjectUnref(srv);
virObjectUnref(ctrl->daemon);
ctrl->daemon = NULL;
virObjectUnref(svc);
return -1;
}
@ -982,7 +987,7 @@ static bool wantReboot;
static virMutex lock = VIR_MUTEX_INITIALIZER;
static void virLXCControllerSignalChildIO(virNetServerPtr server,
static void virLXCControllerSignalChildIO(virNetDaemonPtr daemon,
siginfo_t *info ATTRIBUTE_UNUSED,
void *opaque)
{
@ -993,7 +998,7 @@ static void virLXCControllerSignalChildIO(virNetServerPtr server,
ret = waitpid(-1, &status, WNOHANG);
VIR_DEBUG("Got sig child %d vs %lld", ret, (unsigned long long)ctrl->initpid);
if (ret == ctrl->initpid) {
virNetServerQuit(server);
virNetDaemonQuit(daemon);
virMutexLock(&lock);
if (WIFSIGNALED(status) &&
WTERMSIG(status) == SIGHUP) {
@ -1052,7 +1057,7 @@ static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr consol
VIR_DEBUG(":fail");
virReportSystemError(errno, "%s",
_("Unable to add epoll fd"));
virNetServerQuit(console->server);
virNetDaemonQuit(console->daemon);
goto cleanup;
}
console->hostEpoll = events;
@ -1064,7 +1069,7 @@ static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr consol
virReportSystemError(errno, "%s",
_("Unable to remove epoll fd"));
VIR_DEBUG(":fail");
virNetServerQuit(console->server);
virNetDaemonQuit(console->daemon);
goto cleanup;
}
console->hostEpoll = 0;
@ -1090,7 +1095,7 @@ static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr consol
virReportSystemError(errno, "%s",
_("Unable to add epoll fd"));
VIR_DEBUG(":fail");
virNetServerQuit(console->server);
virNetDaemonQuit(console->daemon);
goto cleanup;
}
console->contEpoll = events;
@ -1102,7 +1107,7 @@ static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr consol
virReportSystemError(errno, "%s",
_("Unable to remove epoll fd"));
VIR_DEBUG(":fail");
virNetServerQuit(console->server);
virNetDaemonQuit(console->daemon);
goto cleanup;
}
console->contEpoll = 0;
@ -1131,7 +1136,7 @@ static void virLXCControllerConsoleEPoll(int watch, int fd, int events, void *op
continue;
virReportSystemError(errno, "%s",
_("Unable to wait on epoll"));
virNetServerQuit(console->server);
virNetDaemonQuit(console->daemon);
goto cleanup;
}
@ -1244,7 +1249,7 @@ static void virLXCControllerConsoleIO(int watch, int fd, int events, void *opaqu
virEventRemoveHandle(console->contWatch);
virEventRemoveHandle(console->hostWatch);
console->contWatch = console->hostWatch = -1;
virNetServerQuit(console->server);
virNetDaemonQuit(console->daemon);
virMutexUnlock(&lock);
}
@ -1264,7 +1269,7 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl)
int rc = -1;
size_t i;
if (virNetServerAddSignalHandler(ctrl->server,
if (virNetDaemonAddSignalHandler(ctrl->daemon,
SIGCHLD,
virLXCControllerSignalChildIO,
ctrl) < 0)
@ -1310,7 +1315,7 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl)
}
}
virNetServerRun(ctrl->server);
virNetDaemonRun(ctrl->daemon);
err = virGetLastError();
if (!err || err->code == VIR_ERR_OK)
@ -2284,7 +2289,7 @@ virLXCControllerEventSendExit(virLXCControllerPtr ctrl,
VIR_DEBUG("Waiting for client to complete dispatch");
ctrl->inShutdown = true;
virNetServerClientDelayedClose(ctrl->client);
virNetServerRun(ctrl->server);
virNetDaemonRun(ctrl->daemon);
}
VIR_DEBUG("Client has gone away");
return 0;

749
src/rpc/virnetdaemon.c Normal file
View File

@ -0,0 +1,749 @@
/*
* virnetdaemon.c
*
* 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 <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "virnetdaemon.h"
#include "virlog.h"
#include "viralloc.h"
#include "virerror.h"
#include "virthread.h"
#include "virthreadpool.h"
#include "virutil.h"
#include "virfile.h"
#include "virnetserver.h"
#include "virnetservermdns.h"
#include "virdbus.h"
#include "virstring.h"
#include "virsystemd.h"
#ifndef SA_SIGINFO
# define SA_SIGINFO 0
#endif
#define VIR_FROM_THIS VIR_FROM_RPC
VIR_LOG_INIT("rpc.netserver");
typedef struct _virNetDaemonSignal virNetDaemonSignal;
typedef virNetDaemonSignal *virNetDaemonSignalPtr;
struct _virNetDaemonSignal {
struct sigaction oldaction;
int signum;
virNetDaemonSignalFunc func;
void *opaque;
};
struct _virNetDaemon {
virObjectLockable parent;
bool privileged;
size_t nsignals;
virNetDaemonSignalPtr *signals;
int sigread;
int sigwrite;
int sigwatch;
size_t nservers;
virNetServerPtr *servers;
virJSONValuePtr srvObject;
bool quit;
unsigned int autoShutdownTimeout;
size_t autoShutdownInhibitions;
bool autoShutdownCallingInhibit;
int autoShutdownInhibitFd;
};
static virClassPtr virNetDaemonClass;
static void
virNetDaemonDispose(void *obj)
{
virNetDaemonPtr dmn = obj;
size_t i;
VIR_FORCE_CLOSE(dmn->autoShutdownInhibitFd);
for (i = 0; i < dmn->nsignals; i++) {
sigaction(dmn->signals[i]->signum, &dmn->signals[i]->oldaction, NULL);
VIR_FREE(dmn->signals[i]);
}
VIR_FREE(dmn->signals);
VIR_FORCE_CLOSE(dmn->sigread);
VIR_FORCE_CLOSE(dmn->sigwrite);
if (dmn->sigwatch > 0)
virEventRemoveHandle(dmn->sigwatch);
for (i = 0; i < dmn->nservers; i++)
virObjectUnref(dmn->servers[i]);
VIR_FREE(dmn->servers);
virJSONValueFree(dmn->srvObject);
}
static int
virNetDaemonOnceInit(void)
{
if (!(virNetDaemonClass = virClassNew(virClassForObjectLockable(),
"virNetDaemon",
sizeof(virNetDaemon),
virNetDaemonDispose)))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(virNetDaemon)
virNetDaemonPtr
virNetDaemonNew(void)
{
virNetDaemonPtr dmn;
struct sigaction sig_action;
if (virNetDaemonInitialize() < 0)
return NULL;
if (!(dmn = virObjectLockableNew(virNetDaemonClass)))
return NULL;
dmn->sigwrite = dmn->sigread = -1;
dmn->privileged = geteuid() == 0;
dmn->autoShutdownInhibitFd = -1;
if (virEventRegisterDefaultImpl() < 0)
goto error;
memset(&sig_action, 0, sizeof(sig_action));
sig_action.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sig_action, NULL);
return dmn;
error:
virObjectUnref(dmn);
return NULL;
}
int
virNetDaemonAddServer(virNetDaemonPtr dmn, virNetServerPtr srv)
{
int ret = -1;
virObjectLock(dmn);
if (VIR_APPEND_ELEMENT(dmn->servers, dmn->nservers, srv) < 0)
goto cleanup;
virObjectRef(srv);
ret = dmn->nservers - 1;
cleanup:
virObjectUnlock(dmn);
return ret;
}
/*
* Separate function merely for the purpose of unified error
* reporting.
*/
static virNetServerPtr
virNetDaemonGetServerInternal(virNetDaemonPtr dmn,
int subServerID)
{
if (subServerID < 0 || subServerID >= dmn->nservers) {
virReportError(VIR_ERR_INVALID_ARG,
_("Invalid server ID: %d"),
subServerID);
return NULL;
}
return virObjectRef(dmn->servers[subServerID]);
}
virNetServerPtr
virNetDaemonGetServer(virNetDaemonPtr dmn,
int subServerID)
{
virNetServerPtr srv = NULL;
virObjectLock(dmn);
srv = virNetDaemonGetServerInternal(dmn, subServerID);
virObjectUnlock(dmn);
return srv;
}
virNetServerPtr
virNetDaemonAddServerPostExec(virNetDaemonPtr dmn,
virNetServerClientPrivNew clientPrivNew,
virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart,
virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
virFreeCallback clientPrivFree,
void *clientPrivOpaque)
{
virJSONValuePtr object = NULL;
virNetServerPtr srv = NULL;
virObjectLock(dmn);
if (!dmn->srvObject) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot add more servers post-exec than "
"there were pre-exec"));
goto error;
}
if (virJSONValueIsArray(dmn->srvObject)) {
object = virJSONValueArraySteal(dmn->srvObject, 0);
if (virJSONValueArraySize(dmn->srvObject) == 0) {
virJSONValueFree(dmn->srvObject);
dmn->srvObject = NULL;
}
} else {
object = dmn->srvObject;
dmn->srvObject = NULL;
}
srv = virNetServerNewPostExecRestart(object,
clientPrivNew,
clientPrivNewPostExecRestart,
clientPrivPreExecRestart,
clientPrivFree,
clientPrivOpaque);
if (!srv || VIR_APPEND_ELEMENT_COPY(dmn->servers, dmn->nservers, srv) < 0)
goto error;
virJSONValueFree(object);
virObjectUnlock(dmn);
return srv;
error:
virObjectUnlock(dmn);
virObjectUnref(srv);
virJSONValueFree(object);
return NULL;
}
virNetDaemonPtr
virNetDaemonNewPostExecRestart(virJSONValuePtr object)
{
virNetDaemonPtr dmn = NULL;
virJSONValuePtr servers = virJSONValueObjectGet(object, "servers");
bool new_version = virJSONValueObjectHasKey(object, "servers");
if (!(dmn = virNetDaemonNew()))
goto error;
if (new_version && !servers) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Malformed servers data in JSON document"));
goto error;
}
if (!(dmn->srvObject = virJSONValueCopy(new_version ? servers : object)))
goto error;
return dmn;
error:
virObjectUnref(dmn);
return NULL;
}
virJSONValuePtr
virNetDaemonPreExecRestart(virNetDaemonPtr dmn)
{
virJSONValuePtr object, srvArray = NULL;
size_t i;
virObjectLock(dmn);
if (!(object = virJSONValueNewObject()))
goto error;
if (!(srvArray = virJSONValueNewArray()) ||
virJSONValueObjectAppend(object, "servers", srvArray) < 0)
goto error;
for (i = 0; i < dmn->nservers; i++) {
virJSONValuePtr srvJSON = NULL;
srvJSON = virNetServerPreExecRestart(dmn->servers[i]);
if (!srvJSON)
goto error;
if (virJSONValueArrayAppend(srvArray, srvJSON) < 0) {
virJSONValueFree(srvJSON);
goto error;
}
}
virObjectUnlock(dmn);
return object;
error:
virJSONValueFree(object);
virJSONValueFree(srvArray);
virObjectUnlock(dmn);
return NULL;
}
bool
virNetDaemonIsPrivileged(virNetDaemonPtr dmn)
{
bool priv;
virObjectLock(dmn);
priv = dmn->privileged;
virObjectUnlock(dmn);
return priv;
}
void
virNetDaemonAutoShutdown(virNetDaemonPtr dmn,
unsigned int timeout)
{
virObjectLock(dmn);
dmn->autoShutdownTimeout = timeout;
virObjectUnlock(dmn);
}
#if defined(HAVE_DBUS) && defined(DBUS_TYPE_UNIX_FD)
static void
virNetDaemonGotInhibitReply(DBusPendingCall *pending,
void *opaque)
{
virNetDaemonPtr dmn = opaque;
DBusMessage *reply;
int fd;
virObjectLock(dmn);
dmn->autoShutdownCallingInhibit = false;
VIR_DEBUG("dmn=%p", dmn);
reply = dbus_pending_call_steal_reply(pending);
if (reply == NULL)
goto cleanup;
if (dbus_message_get_args(reply, NULL,
DBUS_TYPE_UNIX_FD, &fd,
DBUS_TYPE_INVALID)) {
if (dmn->autoShutdownInhibitions) {
dmn->autoShutdownInhibitFd = fd;
} else {
/* We stopped the last VM since we made the inhibit call */
VIR_FORCE_CLOSE(fd);
}
}
dbus_message_unref(reply);
cleanup:
virObjectUnlock(dmn);
}
/* As per: http://www.freedesktop.org/wiki/Software/systemd/inhibit */
static void
virNetDaemonCallInhibit(virNetDaemonPtr dmn,
const char *what,
const char *who,
const char *why,
const char *mode)
{
DBusMessage *message;
DBusPendingCall *pendingReply;
DBusConnection *systemBus;
VIR_DEBUG("dmn=%p what=%s who=%s why=%s mode=%s",
dmn, NULLSTR(what), NULLSTR(who), NULLSTR(why), NULLSTR(mode));
if (!(systemBus = virDBusGetSystemBus()))
return;
/* Only one outstanding call at a time */
if (dmn->autoShutdownCallingInhibit)
return;
message = dbus_message_new_method_call("org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"Inhibit");
if (message == NULL)
return;
dbus_message_append_args(message,
DBUS_TYPE_STRING, &what,
DBUS_TYPE_STRING, &who,
DBUS_TYPE_STRING, &why,
DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID);
pendingReply = NULL;
if (dbus_connection_send_with_reply(systemBus, message,
&pendingReply,
25*1000)) {
dbus_pending_call_set_notify(pendingReply,
virNetDaemonGotInhibitReply,
dmn, NULL);
dmn->autoShutdownCallingInhibit = true;
}
dbus_message_unref(message);
}
#endif
void
virNetDaemonAddShutdownInhibition(virNetDaemonPtr dmn)
{
virObjectLock(dmn);
dmn->autoShutdownInhibitions++;
VIR_DEBUG("dmn=%p inhibitions=%zu", dmn, dmn->autoShutdownInhibitions);
#if defined(HAVE_DBUS) && defined(DBUS_TYPE_UNIX_FD)
if (dmn->autoShutdownInhibitions == 1)
virNetDaemonCallInhibit(dmn,
"shutdown",
_("Libvirt"),
_("Virtual machines need to be saved"),
"delay");
#endif
virObjectUnlock(dmn);
}
void
virNetDaemonRemoveShutdownInhibition(virNetDaemonPtr dmn)
{
virObjectLock(dmn);
dmn->autoShutdownInhibitions--;
VIR_DEBUG("dmn=%p inhibitions=%zu", dmn, dmn->autoShutdownInhibitions);
if (dmn->autoShutdownInhibitions == 0)
VIR_FORCE_CLOSE(dmn->autoShutdownInhibitFd);
virObjectUnlock(dmn);
}
static sig_atomic_t sigErrors;
static int sigLastErrno;
static int sigWrite = -1;
static void
virNetDaemonSignalHandler(int sig, siginfo_t * siginfo,
void* context ATTRIBUTE_UNUSED)
{
int origerrno;
int r;
siginfo_t tmp;
if (SA_SIGINFO)
tmp = *siginfo;
else
memset(&tmp, 0, sizeof(tmp));
/* set the sig num in the struct */
tmp.si_signo = sig;
origerrno = errno;
r = safewrite(sigWrite, &tmp, sizeof(tmp));
if (r == -1) {
sigErrors++;
sigLastErrno = errno;
}
errno = origerrno;
}
static void
virNetDaemonSignalEvent(int watch,
int fd ATTRIBUTE_UNUSED,
int events ATTRIBUTE_UNUSED,
void *opaque)
{
virNetDaemonPtr dmn = opaque;
siginfo_t siginfo;
size_t i;
virObjectLock(dmn);
if (saferead(dmn->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
virReportSystemError(errno, "%s",
_("Failed to read from signal pipe"));
virEventRemoveHandle(watch);
dmn->sigwatch = -1;
goto cleanup;
}
for (i = 0; i < dmn->nsignals; i++) {
if (siginfo.si_signo == dmn->signals[i]->signum) {
virNetDaemonSignalFunc func = dmn->signals[i]->func;
void *funcopaque = dmn->signals[i]->opaque;
virObjectUnlock(dmn);
func(dmn, &siginfo, funcopaque);
return;
}
}
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unexpected signal received: %d"), siginfo.si_signo);
cleanup:
virObjectUnlock(dmn);
}
static int
virNetDaemonSignalSetup(virNetDaemonPtr dmn)
{
int fds[2] = { -1, -1 };
if (dmn->sigwrite != -1)
return 0;
if (pipe2(fds, O_CLOEXEC|O_NONBLOCK) < 0) {
virReportSystemError(errno, "%s",
_("Unable to create signal pipe"));
return -1;
}
if ((dmn->sigwatch = virEventAddHandle(fds[0],
VIR_EVENT_HANDLE_READABLE,
virNetDaemonSignalEvent,
dmn, NULL)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to add signal handle watch"));
goto error;
}
dmn->sigread = fds[0];
dmn->sigwrite = fds[1];
sigWrite = fds[1];
return 0;
error:
VIR_FORCE_CLOSE(fds[0]);
VIR_FORCE_CLOSE(fds[1]);
return -1;
}
int
virNetDaemonAddSignalHandler(virNetDaemonPtr dmn,
int signum,
virNetDaemonSignalFunc func,
void *opaque)
{
virNetDaemonSignalPtr sigdata = NULL;
struct sigaction sig_action;
virObjectLock(dmn);
if (virNetDaemonSignalSetup(dmn) < 0)
goto error;
if (VIR_EXPAND_N(dmn->signals, dmn->nsignals, 1) < 0)
goto error;
if (VIR_ALLOC(sigdata) < 0)
goto error;
sigdata->signum = signum;
sigdata->func = func;
sigdata->opaque = opaque;
memset(&sig_action, 0, sizeof(sig_action));
sig_action.sa_sigaction = virNetDaemonSignalHandler;
sig_action.sa_flags = SA_SIGINFO;
sigemptyset(&sig_action.sa_mask);
sigaction(signum, &sig_action, &sigdata->oldaction);
dmn->signals[dmn->nsignals-1] = sigdata;
virObjectUnlock(dmn);
return 0;
error:
VIR_FREE(sigdata);
virObjectUnlock(dmn);
return -1;
}
static void
virNetDaemonAutoShutdownTimer(int timerid ATTRIBUTE_UNUSED,
void *opaque)
{
virNetDaemonPtr dmn = opaque;
virObjectLock(dmn);
if (!dmn->autoShutdownInhibitions) {
VIR_DEBUG("Automatic shutdown triggered");
dmn->quit = true;
}
virObjectUnlock(dmn);
}
void
virNetDaemonUpdateServices(virNetDaemonPtr dmn,
bool enabled)
{
size_t i;
virObjectLock(dmn);
for (i = 0; i < dmn->nservers; i++)
virNetServerUpdateServices(dmn->servers[i], enabled);
virObjectUnlock(dmn);
}
void
virNetDaemonRun(virNetDaemonPtr dmn)
{
int timerid = -1;
bool timerActive = false;
size_t i;
virObjectLock(dmn);
if (dmn->srvObject) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Not all servers restored, cannot run server"));
goto cleanup;
}
for (i = 0; i < dmn->nservers; i++) {
if (virNetServerStart(dmn->servers[i]) < 0)
goto cleanup;
}
dmn->quit = false;
if (dmn->autoShutdownTimeout &&
(timerid = virEventAddTimeout(-1,
virNetDaemonAutoShutdownTimer,
dmn, NULL)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to register shutdown timeout"));
goto cleanup;
}
/* We are accepting connections now. Notify systemd
* so it can start dependent services. */
virSystemdNotifyStartup();
VIR_DEBUG("dmn=%p quit=%d", dmn, dmn->quit);
while (!dmn->quit) {
/* A shutdown timeout is specified, so check
* if any drivers have active state, if not
* shutdown after timeout seconds
*/
if (dmn->autoShutdownTimeout) {
if (timerActive) {
for (i = 0; i < dmn->nservers; i++) {
if (virNetServerHasClients(dmn->servers[i])) {
VIR_DEBUG("Deactivating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid, -1);
timerActive = false;
break;
}
}
} else {
for (i = 0; i < dmn->nservers; i++) {
if (!virNetServerHasClients(dmn->servers[i])) {
VIR_DEBUG("Activating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid,
dmn->autoShutdownTimeout * 1000);
timerActive = true;
break;
}
}
}
}
virObjectUnlock(dmn);
if (virEventRunDefaultImpl() < 0) {
virObjectLock(dmn);
VIR_DEBUG("Loop iteration error, exiting");
break;
}
virObjectLock(dmn);
for (i = 0; i < dmn->nservers; i++)
virNetServerProcessClients(dmn->servers[i]);
}
cleanup:
virObjectUnlock(dmn);
}
void
virNetDaemonQuit(virNetDaemonPtr dmn)
{
virObjectLock(dmn);
VIR_DEBUG("Quit requested %p", dmn);
dmn->quit = true;
virObjectUnlock(dmn);
}
void
virNetDaemonClose(virNetDaemonPtr dmn)
{
size_t i;
if (!dmn)
return;
virObjectLock(dmn);
for (i = 0; i < dmn->nservers; i++)
virNetServerClose(dmn->servers[i]);
virObjectUnlock(dmn);
}

82
src/rpc/virnetdaemon.h Normal file
View File

@ -0,0 +1,82 @@
/*
* virnetdaemon.h
*
* 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_NET_DAEMON_H__
# define __VIR_NET_DAEMON_H__
# include <signal.h>
# ifdef WITH_GNUTLS
# include "virnettlscontext.h"
# endif
# include "virobject.h"
# include "virjson.h"
# include "virnetserverprogram.h"
# include "virnetserverclient.h"
# include "virnetserverservice.h"
# include "virnetserver.h"
virNetDaemonPtr virNetDaemonNew(void);
int virNetDaemonAddServer(virNetDaemonPtr dmn, virNetServerPtr);
virNetServerPtr virNetDaemonAddServerPostExec(virNetDaemonPtr dmn,
virNetServerClientPrivNew clientPrivNew,
virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart,
virNetServerClientPrivPreExecRestart clientPrivPreExecRestart,
virFreeCallback clientPrivFree,
void *clientPrivOpaque);
virNetDaemonPtr virNetDaemonNewPostExecRestart(virJSONValuePtr object);
virJSONValuePtr virNetDaemonPreExecRestart(virNetDaemonPtr dmn);
typedef int (*virNetDaemonAutoShutdownFunc)(virNetDaemonPtr dmn, void *opaque);
bool virNetDaemonIsPrivileged(virNetDaemonPtr dmn);
void virNetDaemonAutoShutdown(virNetDaemonPtr dmn,
unsigned int timeout);
void virNetDaemonAddShutdownInhibition(virNetDaemonPtr dmn);
void virNetDaemonRemoveShutdownInhibition(virNetDaemonPtr dmn);
typedef void (*virNetDaemonSignalFunc)(virNetDaemonPtr dmn, siginfo_t *info, void *opaque);
int virNetDaemonAddSignalHandler(virNetDaemonPtr dmn,
int signum,
virNetDaemonSignalFunc func,
void *opaque);
void virNetDaemonUpdateServices(virNetDaemonPtr dmn,
bool enabled);
void virNetDaemonRun(virNetDaemonPtr dmn);
void virNetDaemonQuit(virNetDaemonPtr dmn);
void virNetDaemonClose(virNetDaemonPtr dmn);
virNetServerPtr virNetDaemonGetServer(virNetDaemonPtr dmn,
int subServerID);
#endif /* __VIR_NET_DAEMON_H__ */

View File

@ -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
@ -23,40 +23,19 @@
#include <config.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "virnetserver.h"
#include "virlog.h"
#include "viralloc.h"
#include "virerror.h"
#include "virthread.h"
#include "virthreadpool.h"
#include "virutil.h"
#include "virfile.h"
#include "virnetservermdns.h"
#include "virdbus.h"
#include "virstring.h"
#include "virsystemd.h"
#ifndef SA_SIGINFO
# define SA_SIGINFO 0
#endif
#define VIR_FROM_THIS VIR_FROM_RPC
VIR_LOG_INIT("rpc.netserver");
typedef struct _virNetServerSignal virNetServerSignal;
typedef virNetServerSignal *virNetServerSignalPtr;
struct _virNetServerSignal {
struct sigaction oldaction;
int signum;
virNetServerSignalFunc func;
void *opaque;
};
typedef struct _virNetServerJob virNetServerJob;
typedef virNetServerJob *virNetServerJobPtr;
@ -72,14 +51,6 @@ struct _virNetServer {
virThreadPoolPtr workers;
bool privileged;
size_t nsignals;
virNetServerSignalPtr *signals;
int sigread;
int sigwrite;
int sigwatch;
char *mdnsGroupName;
virNetServerMDNSPtr mdns;
virNetServerMDNSGroupPtr mdnsGroup;
@ -100,17 +71,10 @@ struct _virNetServer {
unsigned int keepaliveCount;
bool keepaliveRequired;
bool quit;
#ifdef WITH_GNUTLS
virNetTLSContextPtr tls;
#endif
unsigned int autoShutdownTimeout;
size_t autoShutdownInhibitions;
bool autoShutdownCallingInhibit;
int autoShutdownInhibitFd;
virNetServerClientPrivNew clientPrivNew;
virNetServerClientPrivPreExecRestart clientPrivPreExecRestart;
virFreeCallback clientPrivFree;
@ -356,7 +320,6 @@ virNetServerPtr virNetServerNew(size_t min_workers,
void *clientPrivOpaque)
{
virNetServerPtr srv;
struct sigaction sig_action;
if (virNetServerInitialize() < 0)
return NULL;
@ -376,13 +339,10 @@ virNetServerPtr virNetServerNew(size_t min_workers,
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;
if (VIR_STRDUP(srv->mdnsGroupName, mdnsGroupName) < 0)
goto error;
@ -394,15 +354,7 @@ virNetServerPtr virNetServerNew(size_t min_workers,
goto error;
}
if (virEventRegisterDefaultImpl() < 0)
goto error;
memset(&sig_action, 0, sizeof(sig_action));
sig_action.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sig_action, NULL);
return srv;
error:
virObjectUnref(srv);
return NULL;
@ -679,286 +631,6 @@ virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv)
}
bool virNetServerIsPrivileged(virNetServerPtr srv)
{
bool priv;
virObjectLock(srv);
priv = srv->privileged;
virObjectUnlock(srv);
return priv;
}
void virNetServerAutoShutdown(virNetServerPtr srv,
unsigned int timeout)
{
virObjectLock(srv);
srv->autoShutdownTimeout = timeout;
virObjectUnlock(srv);
}
#if defined(HAVE_DBUS) && defined(DBUS_TYPE_UNIX_FD)
static void virNetServerGotInhibitReply(DBusPendingCall *pending,
void *opaque)
{
virNetServerPtr srv = opaque;
DBusMessage *reply;
int fd;
virObjectLock(srv);
srv->autoShutdownCallingInhibit = false;
VIR_DEBUG("srv=%p", srv);
reply = dbus_pending_call_steal_reply(pending);
if (reply == NULL)
goto cleanup;
if (dbus_message_get_args(reply, NULL,
DBUS_TYPE_UNIX_FD, &fd,
DBUS_TYPE_INVALID)) {
if (srv->autoShutdownInhibitions) {
srv->autoShutdownInhibitFd = fd;
} else {
/* We stopped the last VM since we made the inhibit call */
VIR_FORCE_CLOSE(fd);
}
}
dbus_message_unref(reply);
cleanup:
virObjectUnlock(srv);
}
/* As per: http://www.freedesktop.org/wiki/Software/systemd/inhibit */
static void virNetServerCallInhibit(virNetServerPtr srv,
const char *what,
const char *who,
const char *why,
const char *mode)
{
DBusMessage *message;
DBusPendingCall *pendingReply;
DBusConnection *systemBus;
VIR_DEBUG("srv=%p what=%s who=%s why=%s mode=%s",
srv, NULLSTR(what), NULLSTR(who), NULLSTR(why), NULLSTR(mode));
if (!(systemBus = virDBusGetSystemBus()))
return;
/* Only one outstanding call at a time */
if (srv->autoShutdownCallingInhibit)
return;
message = dbus_message_new_method_call("org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"Inhibit");
if (message == NULL)
return;
dbus_message_append_args(message,
DBUS_TYPE_STRING, &what,
DBUS_TYPE_STRING, &who,
DBUS_TYPE_STRING, &why,
DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID);
pendingReply = NULL;
if (dbus_connection_send_with_reply(systemBus, message,
&pendingReply,
25*1000)) {
dbus_pending_call_set_notify(pendingReply,
virNetServerGotInhibitReply,
srv, NULL);
srv->autoShutdownCallingInhibit = true;
}
dbus_message_unref(message);
}
#endif
void virNetServerAddShutdownInhibition(virNetServerPtr srv)
{
virObjectLock(srv);
srv->autoShutdownInhibitions++;
VIR_DEBUG("srv=%p inhibitions=%zu", srv, srv->autoShutdownInhibitions);
#if defined(HAVE_DBUS) && defined(DBUS_TYPE_UNIX_FD)
if (srv->autoShutdownInhibitions == 1)
virNetServerCallInhibit(srv,
"shutdown",
_("Libvirt"),
_("Virtual machines need to be saved"),
"delay");
#endif
virObjectUnlock(srv);
}
void virNetServerRemoveShutdownInhibition(virNetServerPtr srv)
{
virObjectLock(srv);
srv->autoShutdownInhibitions--;
VIR_DEBUG("srv=%p inhibitions=%zu", srv, srv->autoShutdownInhibitions);
if (srv->autoShutdownInhibitions == 0)
VIR_FORCE_CLOSE(srv->autoShutdownInhibitFd);
virObjectUnlock(srv);
}
static sig_atomic_t sigErrors;
static int sigLastErrno;
static int sigWrite = -1;
static void
virNetServerSignalHandler(int sig, siginfo_t * siginfo,
void* context ATTRIBUTE_UNUSED)
{
int origerrno;
int r;
siginfo_t tmp;
if (SA_SIGINFO)
tmp = *siginfo;
else
memset(&tmp, 0, sizeof(tmp));
/* set the sig num in the struct */
tmp.si_signo = sig;
origerrno = errno;
r = safewrite(sigWrite, &tmp, sizeof(tmp));
if (r == -1) {
sigErrors++;
sigLastErrno = errno;
}
errno = origerrno;
}
static void
virNetServerSignalEvent(int watch,
int fd ATTRIBUTE_UNUSED,
int events ATTRIBUTE_UNUSED,
void *opaque)
{
virNetServerPtr srv = opaque;
siginfo_t siginfo;
size_t i;
virObjectLock(srv);
if (saferead(srv->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
virReportSystemError(errno, "%s",
_("Failed to read from signal pipe"));
virEventRemoveHandle(watch);
srv->sigwatch = -1;
goto cleanup;
}
for (i = 0; i < srv->nsignals; i++) {
if (siginfo.si_signo == srv->signals[i]->signum) {
virNetServerSignalFunc func = srv->signals[i]->func;
void *funcopaque = srv->signals[i]->opaque;
virObjectUnlock(srv);
func(srv, &siginfo, funcopaque);
return;
}
}
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unexpected signal received: %d"), siginfo.si_signo);
cleanup:
virObjectUnlock(srv);
}
static int virNetServerSignalSetup(virNetServerPtr srv)
{
int fds[2] = { -1, -1 };
if (srv->sigwrite != -1)
return 0;
if (pipe2(fds, O_CLOEXEC|O_NONBLOCK) < 0) {
virReportSystemError(errno, "%s",
_("Unable to create signal pipe"));
return -1;
}
if ((srv->sigwatch = virEventAddHandle(fds[0],
VIR_EVENT_HANDLE_READABLE,
virNetServerSignalEvent,
srv, NULL)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to add signal handle watch"));
goto error;
}
srv->sigread = fds[0];
srv->sigwrite = fds[1];
sigWrite = fds[1];
return 0;
error:
VIR_FORCE_CLOSE(fds[0]);
VIR_FORCE_CLOSE(fds[1]);
return -1;
}
int virNetServerAddSignalHandler(virNetServerPtr srv,
int signum,
virNetServerSignalFunc func,
void *opaque)
{
virNetServerSignalPtr sigdata = NULL;
struct sigaction sig_action;
virObjectLock(srv);
if (virNetServerSignalSetup(srv) < 0)
goto error;
if (VIR_EXPAND_N(srv->signals, srv->nsignals, 1) < 0)
goto error;
if (VIR_ALLOC(sigdata) < 0)
goto error;
sigdata->signum = signum;
sigdata->func = func;
sigdata->opaque = opaque;
memset(&sig_action, 0, sizeof(sig_action));
sig_action.sa_sigaction = virNetServerSignalHandler;
sig_action.sa_flags = SA_SIGINFO;
sigemptyset(&sig_action.sa_mask);
sigaction(signum, &sig_action, &sigdata->oldaction);
srv->signals[srv->nsignals-1] = sigdata;
virObjectUnlock(srv);
return 0;
error:
VIR_FREE(sigdata);
virObjectUnlock(srv);
return -1;
}
int virNetServerAddService(virNetServerPtr srv,
virNetServerServicePtr svc,
@ -1023,22 +695,6 @@ int virNetServerSetTLSContext(virNetServerPtr srv,
#endif
static void virNetServerAutoShutdownTimer(int timerid ATTRIBUTE_UNUSED,
void *opaque)
{
virNetServerPtr srv = opaque;
virObjectLock(srv);
if (!srv->autoShutdownInhibitions) {
VIR_DEBUG("Automatic shutdown triggered");
srv->quit = true;
}
virObjectUnlock(srv);
}
static void
virNetServerUpdateServicesLocked(virNetServerPtr srv,
bool enabled)
@ -1087,127 +743,16 @@ virNetServerCheckLimits(virNetServerPtr srv)
}
}
void virNetServerRun(virNetServerPtr srv)
{
int timerid = -1;
bool timerActive = false;
size_t i;
virObjectLock(srv);
if (srv->mdns &&
virNetServerMDNSStart(srv->mdns) < 0)
goto cleanup;
srv->quit = false;
if (srv->autoShutdownTimeout &&
(timerid = virEventAddTimeout(-1,
virNetServerAutoShutdownTimer,
srv, NULL)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to register shutdown timeout"));
goto cleanup;
}
/* We are accepting connections now. Notify systemd
* so it can start dependent services. */
virSystemdNotifyStartup();
VIR_DEBUG("srv=%p quit=%d", srv, srv->quit);
while (!srv->quit) {
/* A shutdown timeout is specified, so check
* if any drivers have active state, if not
* shutdown after timeout seconds
*/
if (srv->autoShutdownTimeout) {
if (timerActive) {
if (srv->clients) {
VIR_DEBUG("Deactivating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid, -1);
timerActive = false;
}
} else {
if (!srv->clients) {
VIR_DEBUG("Activating shutdown timer %d", timerid);
virEventUpdateTimeout(timerid,
srv->autoShutdownTimeout * 1000);
timerActive = true;
}
}
}
virObjectUnlock(srv);
if (virEventRunDefaultImpl() < 0) {
virObjectLock(srv);
VIR_DEBUG("Loop iteration error, exiting");
break;
}
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;
}
}
}
cleanup:
virObjectUnlock(srv);
}
void virNetServerQuit(virNetServerPtr srv)
{
virObjectLock(srv);
VIR_DEBUG("Quit requested %p", srv);
srv->quit = true;
virObjectUnlock(srv);
}
void virNetServerDispose(void *obj)
{
virNetServerPtr srv = obj;
size_t i;
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]);
}
VIR_FREE(srv->signals);
VIR_FORCE_CLOSE(srv->sigread);
VIR_FORCE_CLOSE(srv->sigwrite);
if (srv->sigwatch > 0)
virEventRemoveHandle(srv->sigwatch);
for (i = 0; i < srv->nservices; i++)
virObjectUnref(srv->services[i]);
VIR_FREE(srv->services);
@ -1280,3 +825,62 @@ size_t virNetServerTrackCompletedAuth(virNetServerPtr srv)
virObjectUnlock(srv);
return ret;
}
bool
virNetServerHasClients(virNetServerPtr srv)
{
bool ret;
virObjectLock(srv);
ret = !!srv->nclients;
virObjectUnlock(srv);
return ret;
}
void
virNetServerProcessClients(virNetServerPtr srv)
{
size_t i;
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;
}
}
virObjectUnlock(srv);
}
int
virNetServerStart(virNetServerPtr srv)
{
/*
* Do whatever needs to be done before starting.
*/
if (!srv->mdns)
return 0;
return virNetServerMDNSStart(srv->mdns);
}

View File

@ -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
@ -24,8 +24,6 @@
#ifndef __VIR_NET_SERVER_H__
# define __VIR_NET_SERVER_H__
# include <signal.h>
# ifdef WITH_GNUTLS
# include "virnettlscontext.h"
# endif
@ -35,6 +33,9 @@
# include "virobject.h"
# include "virjson.h"
typedef struct _virNetServer virNetServer;
typedef virNetServer *virNetServerPtr;
virNetServerPtr virNetServerNew(size_t min_workers,
size_t max_workers,
size_t priority_workers,
@ -56,25 +57,10 @@ virNetServerPtr virNetServerNewPostExecRestart(virJSONValuePtr object,
virFreeCallback clientPrivFree,
void *clientPrivOpaque);
void virNetServerClose(virNetServerPtr srv);
virJSONValuePtr virNetServerPreExecRestart(virNetServerPtr srv);
typedef int (*virNetServerAutoShutdownFunc)(virNetServerPtr srv, void *opaque);
bool virNetServerIsPrivileged(virNetServerPtr srv);
void virNetServerAutoShutdown(virNetServerPtr srv,
unsigned int timeout);
void virNetServerAddShutdownInhibition(virNetServerPtr srv);
void virNetServerRemoveShutdownInhibition(virNetServerPtr srv);
typedef void (*virNetServerSignalFunc)(virNetServerPtr srv, siginfo_t *info, void *opaque);
int virNetServerAddSignalHandler(virNetServerPtr srv,
int signum,
virNetServerSignalFunc func,
void *opaque);
int virNetServerAddService(virNetServerPtr srv,
virNetServerServicePtr svc,
const char *mdnsEntryName);
@ -90,18 +76,18 @@ int virNetServerSetTLSContext(virNetServerPtr srv,
virNetTLSContextPtr tls);
# endif
void virNetServerUpdateServices(virNetServerPtr srv,
bool enabled);
void virNetServerRun(virNetServerPtr srv);
void virNetServerQuit(virNetServerPtr srv);
void virNetServerClose(virNetServerPtr srv);
bool virNetServerKeepAliveRequired(virNetServerPtr srv);
size_t virNetServerTrackPendingAuth(virNetServerPtr srv);
size_t virNetServerTrackCompletedAuth(virNetServerPtr srv);
#endif
int virNetServerAddClient(virNetServerPtr srv,
virNetServerClientPtr client);
bool virNetServerHasClients(virNetServerPtr srv);
void virNetServerProcessClients(virNetServerPtr srv);
void virNetServerUpdateServices(virNetServerPtr srv, bool enabled);
int virNetServerStart(virNetServerPtr srv);
#endif /* __VIR_NET_SERVER_H__ */

View File

@ -28,6 +28,9 @@
# include "virnetserverclient.h"
# include "virobject.h"
typedef struct _virNetDaemon virNetDaemon;
typedef virNetDaemon *virNetDaemonPtr;
typedef struct _virNetServer virNetServer;
typedef virNetServer *virNetServerPtr;