Switch to using virNetServer APIs for monitor socket

In preparation for introducing a full RPC protocol for
libvirt_lxc, switch over to using the virNetServer APIs
for the monitor connection

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange
2012-07-03 15:25:30 +01:00
parent 9612e4b2e7
commit 9a4d0b5170
2 changed files with 55 additions and 217 deletions

View File

@@ -1523,6 +1523,8 @@ libvirt_lxc_SOURCES = \
libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(AM_LDFLAGS) libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(AM_LDFLAGS)
libvirt_lxc_LDADD = \ libvirt_lxc_LDADD = \
$(NUMACTL_LIBS) \ $(NUMACTL_LIBS) \
libvirt-net-rpc-server.la \
libvirt-net-rpc.la \
libvirt_driver_security.la \ libvirt_driver_security.la \
libvirt_conf.la \ libvirt_conf.la \
libvirt_util.la \ libvirt_util.la \

View File

@@ -68,6 +68,7 @@
#include "processinfo.h" #include "processinfo.h"
#include "nodeinfo.h" #include "nodeinfo.h"
#include "virrandom.h" #include "virrandom.h"
#include "rpc/virnetserver.h"
#define VIR_FROM_THIS VIR_FROM_LXC #define VIR_FROM_THIS VIR_FROM_LXC
@@ -124,10 +125,8 @@ struct _virLXCController {
virSecurityManagerPtr securityManager; virSecurityManagerPtr securityManager;
int monitorServerFd; /* Server socket */
int monitorServerWatch; virNetServerPtr server;
int monitorClientFd;
int monitorClientWatch;
virCgroupPtr cgroup; virCgroupPtr cgroup;
}; };
@@ -143,11 +142,6 @@ static virLXCControllerPtr virLXCControllerNew(const char *name)
if (VIR_ALLOC(ctrl) < 0) if (VIR_ALLOC(ctrl) < 0)
goto no_memory; goto no_memory;
ctrl->monitorServerFd = -1;
ctrl->monitorServerWatch = -1;
ctrl->monitorClientFd = -1;
ctrl->monitorClientWatch = -1;
if (!(ctrl->name = strdup(name))) if (!(ctrl->name = strdup(name)))
goto no_memory; goto no_memory;
@@ -254,12 +248,7 @@ static void virLXCControllerFree(virLXCControllerPtr ctrl)
virDomainDefFree(ctrl->def); virDomainDefFree(ctrl->def);
VIR_FREE(ctrl->name); VIR_FREE(ctrl->name);
if (ctrl->monitorServerWatch != -1) virNetServerFree(ctrl->server);
virEventRemoveHandle(ctrl->monitorServerWatch);
VIR_FORCE_CLOSE(ctrl->monitorServerFd);
if (ctrl->monitorClientWatch != -1)
virEventRemoveHandle(ctrl->monitorClientWatch);
VIR_FORCE_CLOSE(ctrl->monitorClientFd);
VIR_FREE(ctrl); VIR_FREE(ctrl);
} }
@@ -777,54 +766,58 @@ cleanup:
return rc; return rc;
} }
static char*lxcMonitorPath(virLXCControllerPtr ctrl)
static int virLXCControllerClientHook(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
void *opaque)
{ {
virLXCControllerPtr ctrl = opaque;
virNetServerClientSetPrivateData(client, ctrl, NULL);
return 0;
}
static int virLXCControllerSetupServer(virLXCControllerPtr ctrl)
{
virNetServerServicePtr svc = NULL;
char *sockpath; char *sockpath;
if (virAsprintf(&sockpath, "%s/%s.sock", if (virAsprintf(&sockpath, "%s/%s.sock",
LXC_STATE_DIR, ctrl->def->name) < 0) LXC_STATE_DIR, ctrl->name) < 0) {
virReportOOMError(); virReportOOMError();
return sockpath; return -1;
}
static int lxcMonitorServer(const char *sockpath)
{
int fd;
struct sockaddr_un addr;
if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
virReportSystemError(errno,
_("failed to create server socket '%s'"),
sockpath);
goto error;
} }
unlink(sockpath); if (!(ctrl->server = virNetServerNew(0, 0, 0, 1,
memset(&addr, 0, sizeof(addr)); -1, 0, false,
addr.sun_family = AF_UNIX; NULL,
if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) { virLXCControllerClientHook,
lxcError(VIR_ERR_INTERNAL_ERROR, ctrl)))
_("Socket path %s too long for destination"), sockpath);
goto error; goto error;
}
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { if (!(svc = virNetServerServiceNewUNIX(sockpath,
virReportSystemError(errno, 0700,
_("failed to bind server socket '%s'"), 0,
sockpath); 0,
false,
5,
NULL)))
goto error; goto error;
}
if (listen(fd, 30 /* backlog */ ) < 0) {
virReportSystemError(errno,
_("failed to listen server socket %s"),
sockpath);
goto error;
}
return fd; if (virNetServerAddService(ctrl->server, svc, NULL) < 0)
goto error;
virNetServerServiceFree(svc);
svc = NULL;
virNetServerUpdateServices(ctrl->server, true);
VIR_FREE(sockpath);
return 0;
error: error:
VIR_FORCE_CLOSE(fd); VIR_FREE(sockpath);
virNetServerFree(ctrl->server);
ctrl->server = NULL;
virNetServerServiceFree(svc);
return -1; return -1;
} }
@@ -847,120 +840,23 @@ static int lxcControllerClearCapabilities(void)
return 0; return 0;
} }
/* Return true if it is ok to ignore an accept-after-epoll syscall
that fails with the specified errno value. Else false. */
static bool
ignorable_accept_errno(int errnum)
{
return (errnum == EINVAL
|| errnum == ECONNABORTED
|| errnum == EAGAIN
|| errnum == EWOULDBLOCK);
}
static bool quit = false; static bool quit = false;
static virMutex lock; static virMutex lock;
static int sigpipe[2];
static void virLXCControllerSignalChildHandler(int signum ATTRIBUTE_UNUSED)
{
ignore_value(write(sigpipe[1], "1", 1));
}
static void virLXCControllerSignalChildIO(int watch ATTRIBUTE_UNUSED, static void virLXCControllerSignalChildIO(virNetServerPtr server ATTRIBUTE_UNUSED,
int fd ATTRIBUTE_UNUSED, siginfo_t *info ATTRIBUTE_UNUSED,
int events ATTRIBUTE_UNUSED,
void *opaque) void *opaque)
{ {
char buf[1]; virLXCControllerPtr ctrl = opaque;
int ret; int ret;
virLXCControllerPtr ctrl = opaque;
ignore_value(read(sigpipe[0], buf, 1));
ret = waitpid(-1, NULL, WNOHANG); ret = waitpid(-1, NULL, WNOHANG);
if (ret == ctrl->initpid) { if (ret == ctrl->initpid)
virMutexLock(&lock); virNetServerQuit(ctrl->server);
quit = true;
virMutexUnlock(&lock);
}
} }
static void virLXCControllerClientIO(int watch ATTRIBUTE_UNUSED, int fd, int events, void *opaque)
{
virLXCControllerPtr ctrl = opaque;
char buf[1024];
ssize_t ret;
if (events & (VIR_EVENT_HANDLE_HANGUP |
VIR_EVENT_HANDLE_ERROR)) {
virEventRemoveHandle(ctrl->monitorClientWatch);
ctrl->monitorClientWatch = -1;
return;
}
reread:
ret = read(fd, buf, sizeof(buf));
if (ret == -1 && errno == EINTR)
goto reread;
if (ret == -1 && errno == EAGAIN)
return;
if (ret == -1) {
lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to read from monitor client"));
virMutexLock(&lock);
quit = true;
virMutexUnlock(&lock);
return;
}
if (ret == 0) {
VIR_DEBUG("Client %d gone", fd);
VIR_FORCE_CLOSE(ctrl->monitorClientFd);
virEventRemoveHandle(ctrl->monitorClientWatch);
ctrl->monitorClientWatch = -1;
}
}
static void virLXCControllerServerAccept(int watch ATTRIBUTE_UNUSED, int fd, int events ATTRIBUTE_UNUSED, void *opaque)
{
virLXCControllerPtr ctrl = opaque;
int client;
if ((client = accept(fd, NULL, NULL)) < 0) {
/* First reflex may be simply to declare accept failure
to be a fatal error. However, accept may fail when
a client quits between the above poll and here.
That case is not fatal, but rather to be expected,
if not common, so ignore it. */
if (ignorable_accept_errno(errno))
return;
virReportSystemError(errno, "%s",
_("Unable to accept monitor client"));
virMutexLock(&lock);
quit = true;
virMutexUnlock(&lock);
return;
}
VIR_DEBUG("New client %d (old %d)\n", client, ctrl->monitorClientFd);
VIR_FORCE_CLOSE(ctrl->monitorClientFd);
virEventRemoveHandle(ctrl->monitorClientWatch);
ctrl->monitorClientFd = client;
if ((ctrl->monitorClientWatch = virEventAddHandle(ctrl->monitorClientFd,
VIR_EVENT_HANDLE_READABLE,
virLXCControllerClientIO,
ctrl,
NULL)) < 0) {
lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to watch client socket"));
virMutexLock(&lock);
quit = true;
virMutexUnlock(&lock);
return;
}
}
static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr console) static void virLXCControllerConsoleUpdateWatch(virLXCControllerConsolePtr console)
{ {
int hostEvents = 0; int hostEvents = 0;
@@ -1222,53 +1118,14 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl)
if (virMutexInit(&lock) < 0) if (virMutexInit(&lock) < 0)
goto cleanup2; goto cleanup2;
if (pipe2(sigpipe, O_CLOEXEC|O_NONBLOCK) < 0) { if (virNetServerAddSignalHandler(ctrl->server,
virReportSystemError(errno, "%s", SIGCHLD,
_("Cannot create signal pipe")); virLXCControllerSignalChildIO,
ctrl) < 0)
goto cleanup; goto cleanup;
}
if (virEventAddHandle(sigpipe[0],
VIR_EVENT_HANDLE_READABLE,
virLXCControllerSignalChildIO,
ctrl,
NULL) < 0) {
lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to watch signal pipe"));
goto cleanup;
}
if (signal(SIGCHLD, virLXCControllerSignalChildHandler) == SIG_ERR) {
virReportSystemError(errno, "%s",
_("Cannot install signal handler"));
goto cleanup;
}
VIR_DEBUG("serverFd=%d clientFd=%d",
ctrl->monitorServerFd, ctrl->monitorClientFd);
virResetLastError(); virResetLastError();
if ((ctrl->monitorServerWatch = virEventAddHandle(ctrl->monitorServerFd,
VIR_EVENT_HANDLE_READABLE,
virLXCControllerServerAccept,
ctrl,
NULL)) < 0) {
lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to watch monitor socket"));
goto cleanup;
}
if (ctrl->monitorClientFd != -1 &&
(ctrl->monitorClientWatch = virEventAddHandle(ctrl->monitorClientFd,
VIR_EVENT_HANDLE_READABLE,
virLXCControllerClientIO,
ctrl,
NULL)) < 0) {
lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Unable to watch client socket"));
goto cleanup;
}
for (i = 0 ; i < ctrl->nconsoles ; i++) { for (i = 0 ; i < ctrl->nconsoles ; i++) {
if ((ctrl->consoles[i].epollFd = epoll_create1(EPOLL_CLOEXEC)) < 0) { if ((ctrl->consoles[i].epollFd = epoll_create1(EPOLL_CLOEXEC)) < 0) {
virReportSystemError(errno, "%s", virReportSystemError(errno, "%s",
@@ -1322,7 +1179,6 @@ static int virLXCControllerMain(virLXCControllerPtr ctrl)
cleanup: cleanup:
virMutexDestroy(&lock); virMutexDestroy(&lock);
signal(SIGCHLD, SIG_DFL);
cleanup2: cleanup2:
for (i = 0 ; i < ctrl->nconsoles ; i++) for (i = 0 ; i < ctrl->nconsoles ; i++)
@@ -1669,12 +1525,6 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
if (virLXCControllerDaemonHandshake(ctrl) < 0) if (virLXCControllerDaemonHandshake(ctrl) < 0)
goto cleanup; goto cleanup;
if (virSetBlocking(ctrl->monitorServerFd, false) < 0 ||
virSetBlocking(ctrl->monitorClientFd, false) < 0) {
virReportSystemError(errno, "%s",
_("Unable to set file descriptor non-blocking"));
goto cleanup;
}
for (i = 0 ; i < ctrl->nconsoles ; i++) for (i = 0 ; i < ctrl->nconsoles ; i++)
if (virLXCControllerConsoleSetNonblocking(&(ctrl->consoles[i])) < 0) if (virLXCControllerConsoleSetNonblocking(&(ctrl->consoles[i])) < 0)
goto cleanup; goto cleanup;
@@ -1706,7 +1556,6 @@ int main(int argc, char *argv[])
char **veths = NULL; char **veths = NULL;
int handshakeFd = -1; int handshakeFd = -1;
int bg = 0; int bg = 0;
char *sockpath = NULL;
const struct option options[] = { const struct option options[] = {
{ "background", 0, NULL, 'b' }, { "background", 0, NULL, 'b' },
{ "name", 1, NULL, 'n' }, { "name", 1, NULL, 'n' },
@@ -1857,10 +1706,7 @@ int main(int argc, char *argv[])
if (virLXCControllerValidateConsoles(ctrl) < 0) if (virLXCControllerValidateConsoles(ctrl) < 0)
goto cleanup; goto cleanup;
if ((sockpath = lxcMonitorPath(ctrl)) == NULL) if (virLXCControllerSetupServer(ctrl) < 0)
goto cleanup;
if ((ctrl->monitorServerFd = lxcMonitorServer(sockpath)) < 0)
goto cleanup; goto cleanup;
if (bg) { if (bg) {
@@ -1895,21 +1741,11 @@ int main(int argc, char *argv[])
} }
} }
/* Accept initial client which is the libvirtd daemon */
if ((ctrl->monitorClientFd = accept(ctrl->monitorServerFd, NULL, 0)) < 0) {
virReportSystemError(errno, "%s",
_("Failed to accept a connection from driver"));
goto cleanup;
}
rc = virLXCControllerRun(ctrl); rc = virLXCControllerRun(ctrl);
cleanup: cleanup:
virPidFileDelete(LXC_STATE_DIR, name); virPidFileDelete(LXC_STATE_DIR, name);
virLXCControllerDeleteInterfaces(ctrl); virLXCControllerDeleteInterfaces(ctrl);
if (sockpath)
unlink(sockpath);
VIR_FREE(sockpath);
for (i = 0 ; i < nttyFDs ; i++) for (i = 0 ; i < nttyFDs ; i++)
VIR_FORCE_CLOSE(ttyFDs[i]); VIR_FORCE_CLOSE(ttyFDs[i]);
VIR_FREE(ttyFDs); VIR_FREE(ttyFDs);