/config.sub
/configure
/configure.lineno
-/daemon/*_dispatch_*.h
+/daemon/*_dispatch.h
/docs/hvsupport.html.in
/gnulib/
/libtool
fi
-AC_MSG_CHECKING([where to write libvirtd PID file])
-AC_ARG_WITH([remote-pid-file], [AC_HELP_STRING([--with-remote-pid-file=@<:@pidfile|none@:>@], [PID file for libvirtd])])
-if test "x$with_remote_pid_file" = "x" ; then
- REMOTE_PID_FILE="$localstatedir/run/libvirtd.pid"
-elif test "x$with_remote_pid_file" = "xnone" ; then
- REMOTE_PID_FILE=""
-else
- REMOTE_PID_FILE="$with_remote_pid_file"
-fi
-AC_SUBST([REMOTE_PID_FILE])
-AC_MSG_RESULT($REMOTE_PID_FILE)
dnl
dnl init script flavor
CLEANFILES =
DAEMON_GENERATED = \
- $(srcdir)/remote_dispatch_prototypes.h \
- $(srcdir)/remote_dispatch_table.h \
- $(srcdir)/remote_dispatch_args.h \
- $(srcdir)/remote_dispatch_ret.h \
- $(srcdir)/remote_dispatch_bodies.h \
- $(srcdir)/qemu_dispatch_prototypes.h \
- $(srcdir)/qemu_dispatch_table.h \
- $(srcdir)/qemu_dispatch_args.h \
- $(srcdir)/qemu_dispatch_ret.h \
- $(srcdir)/qemu_dispatch_bodies.h
+ $(srcdir)/remote_dispatch.h \
+ $(srcdir)/qemu_dispatch.h
DAEMON_SOURCES = \
libvirtd.c libvirtd.h \
remote.c remote.h \
- dispatch.c dispatch.h \
stream.c stream.h \
../src/remote/remote_protocol.c \
../src/remote/qemu_protocol.c \
$(DAEMON_GENERATED)
-AVAHI_SOURCES = \
- mdns.c mdns.h
-
DISTCLEANFILES =
EXTRA_DIST = \
- remote_dispatch_bodies.h \
- qemu_dispatch_bodies.h \
+ remote_dispatch.h \
+ qemu_dispatch.h \
libvirtd.conf \
libvirtd.init.in \
libvirtd.upstart \
libvirtd.pod.in \
libvirtd.8.in \
libvirtd.stp \
- $(AVAHI_SOURCES) \
$(DAEMON_SOURCES)
BUILT_SOURCES =
REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x
QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x
-$(srcdir)/remote_dispatch_prototypes.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(REMOTE_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -p remote \
- $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_table.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(REMOTE_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -t remote \
- $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_args.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(REMOTE_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -a remote \
- $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_ret.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(REMOTE_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -r remote \
- $(REMOTE_PROTOCOL) > $@
-
-$(srcdir)/remote_dispatch_bodies.h: $(srcdir)/../src/rpc/gendispatch.pl \
+$(srcdir)/remote_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \
$(REMOTE_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c -b remote \
$(REMOTE_PROTOCOL) > $@
-$(srcdir)/qemu_dispatch_prototypes.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(QEMU_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -p qemu \
- $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_table.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(QEMU_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -t qemu \
- $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_args.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(QEMU_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -a qemu \
- $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_ret.h: $(srcdir)/../src/rpc/gendispatch.pl \
- $(QEMU_PROTOCOL)
- $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -r qemu \
- $(QEMU_PROTOCOL) > $@
-
-$(srcdir)/qemu_dispatch_bodies.h: $(srcdir)/../src/rpc/gendispatch.pl \
+$(srcdir)/qemu_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl \
$(QEMU_PROTOCOL)
$(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -b qemu \
$(QEMU_PROTOCOL) > $@
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/util \
-I$(top_srcdir)/src/conf \
+ -I$(top_srcdir)/src/rpc \
-I$(top_srcdir)/src/remote \
$(LIBXML_CFLAGS) $(GNUTLS_CFLAGS) $(SASL_CFLAGS) \
$(XDR_CFLAGS) $(POLKIT_CFLAGS) \
$(SASL_LIBS) \
$(POLKIT_LIBS)
-libvirtd_LDADD += ../src/libvirt-qemu.la
+libvirtd_LDADD += \
+ ../src/libvirt-net-rpc-server.la \
+ ../src/libvirt-net-rpc.la \
+ ../src/libvirt-qemu.la
if ! WITH_DRIVER_MODULES
if WITH_QEMU
endif
endif
-if HAVE_AVAHI
-libvirtd_SOURCES += $(AVAHI_SOURCES)
-libvirtd_CFLAGS += $(AVAHI_CFLAGS)
-libvirtd_LDADD += $(AVAHI_LIBS)
-endif
-
if WITH_DTRACE
libvirtd_LDADD += probes.o
nodist_libvirtd_SOURCES = probes.h
+++ /dev/null
-/*
- * dispatch.h: RPC message dispatching infrastructure
- *
- * Copyright (C) 2007, 2008, 2009 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Richard W.M. Jones <rjones@redhat.com>
- * Author: Daniel P. Berrange <berrange@redhat.com>
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "dispatch.h"
-#include "remote.h"
-
-#include "memory.h"
-
-/* Convert a libvirt virError object into wire format */
-static void
-remoteDispatchCopyError (remote_error *rerr,
- virErrorPtr verr)
-{
- rerr->code = verr->code;
- rerr->domain = verr->domain;
- rerr->message = verr->message ? malloc(sizeof(char*)) : NULL;
- if (rerr->message) *rerr->message = strdup(verr->message);
- rerr->level = verr->level;
- rerr->str1 = verr->str1 ? malloc(sizeof(char*)) : NULL;
- if (rerr->str1) *rerr->str1 = strdup(verr->str1);
- rerr->str2 = verr->str2 ? malloc(sizeof(char*)) : NULL;
- if (rerr->str2) *rerr->str2 = strdup(verr->str2);
- rerr->str3 = verr->str3 ? malloc(sizeof(char*)) : NULL;
- if (rerr->str3) *rerr->str3 = strdup(verr->str3);
- rerr->int1 = verr->int1;
- rerr->int2 = verr->int2;
-}
-
-
-/* A set of helpers for sending back errors to client
- in various ways .... */
-
-static void
-remoteDispatchStringError (remote_error *rerr,
- int code, const char *msg)
-{
- virError verr;
-
- memset(&verr, 0, sizeof verr);
-
- /* Construct the dummy libvirt virError. */
- verr.code = code;
- verr.domain = VIR_FROM_REMOTE;
- verr.message = (char *)msg;
- verr.level = VIR_ERR_ERROR;
- verr.str1 = (char *)msg;
-
- remoteDispatchCopyError(rerr, &verr);
-}
-
-
-void remoteDispatchAuthError (remote_error *rerr)
-{
- remoteDispatchStringError (rerr, VIR_ERR_AUTH_FAILED, "authentication failed");
-}
-
-
-void remoteDispatchFormatError (remote_error *rerr,
- const char *fmt, ...)
-{
- va_list args;
- char msgbuf[1024];
- char *msg = msgbuf;
-
- va_start (args, fmt);
- vsnprintf (msgbuf, sizeof msgbuf, fmt, args);
- va_end (args);
-
- remoteDispatchStringError (rerr, VIR_ERR_RPC, msg);
-}
-
-
-void remoteDispatchGenericError (remote_error *rerr)
-{
- remoteDispatchStringError(rerr,
- VIR_ERR_INTERNAL_ERROR,
- "library function returned error but did not set virterror");
-}
-
-
-void remoteDispatchError(remote_error *rerr)
-{
- virErrorPtr verr = virGetLastError();
-
- if (verr)
- remoteDispatchCopyError(rerr, verr);
- else
- remoteDispatchGenericError(rerr);
-}
-
-static int
-remoteSerializeError(struct qemud_client *client,
- remote_error *rerr,
- int program,
- int version,
- int procedure,
- int type,
- int serial)
-{
- XDR xdr;
- unsigned int len;
- struct qemud_client_message *msg = NULL;
-
- VIR_DEBUG("prog=%d ver=%d proc=%d type=%d serial=%d, msg=%s",
- program, version, procedure, type, serial,
- rerr->message ? *rerr->message : "(none)");
-
- if (VIR_ALLOC(msg) < 0)
- goto fatal_error;
-
- /* Return header. */
- msg->hdr.prog = program;
- msg->hdr.vers = version;
- msg->hdr.proc = procedure;
- msg->hdr.type = type;
- msg->hdr.serial = serial;
- msg->hdr.status = REMOTE_ERROR;
-
- msg->bufferLength = sizeof(msg->buffer);
-
- /* Serialise the return header. */
- xdrmem_create (&xdr,
- msg->buffer,
- msg->bufferLength,
- XDR_ENCODE);
-
- len = 0; /* We'll come back and write this later. */
- if (!xdr_u_int (&xdr, &len))
- goto xdr_error;
-
- if (!xdr_remote_message_header (&xdr, &msg->hdr))
- goto xdr_error;
-
- /* Error was not set, so synthesize a generic error message. */
- if (rerr->code == 0)
- remoteDispatchGenericError(rerr);
-
- if (!xdr_remote_error (&xdr, rerr))
- goto xdr_error;
-
- /* Write the length word. */
- len = xdr_getpos (&xdr);
- if (xdr_setpos (&xdr, 0) == 0)
- goto xdr_error;
-
- if (!xdr_u_int (&xdr, &len))
- goto xdr_error;
-
- xdr_destroy (&xdr);
-
- msg->bufferLength = len;
- msg->bufferOffset = 0;
-
- /* Put reply on end of tx queue to send out */
- qemudClientMessageQueuePush(&client->tx, msg);
- qemudUpdateClientEvent(client);
- xdr_free((xdrproc_t)xdr_remote_error, (char *)rerr);
-
- return 0;
-
-xdr_error:
- VIR_WARN("Failed to serialize remote error '%s' as XDR",
- rerr->message ? *rerr->message : "<unknown>");
- xdr_destroy(&xdr);
- VIR_FREE(msg);
-fatal_error:
- xdr_free((xdrproc_t)xdr_remote_error, (char *)rerr);
- return -1;
-}
-
-
-/*
- * @client: the client to send the error to
- * @rerr: the error object to send
- * @req: the message this error is in reply to
- *
- * Send an error message to the client
- *
- * Returns 0 if the error was sent, -1 upon fatal error
- */
-int
-remoteSerializeReplyError(struct qemud_client *client,
- remote_error *rerr,
- remote_message_header *req) {
- /*
- * For data streams, errors are sent back as data streams
- * For method calls, errors are sent back as method replies
- */
- return remoteSerializeError(client,
- rerr,
- req->prog,
- req->vers,
- req->proc,
- req->type == REMOTE_STREAM ? REMOTE_STREAM : REMOTE_REPLY,
- req->serial);
-}
-
-int
-remoteSerializeStreamError(struct qemud_client *client,
- remote_error *rerr,
- int proc,
- int serial)
-{
- return remoteSerializeError(client,
- rerr,
- REMOTE_PROGRAM,
- REMOTE_PROTOCOL_VERSION,
- proc,
- REMOTE_STREAM,
- serial);
-}
-
-/*
- * @msg: the complete incoming message, whose header to decode
- *
- * Decodes the header part of the client message, but does not
- * validate the decoded fields in the header. It expects
- * bufferLength to refer to length of the data packet. Upon
- * return bufferOffset will refer to the amount of the packet
- * consumed by decoding of the header.
- *
- * returns 0 if successfully decoded, -1 upon fatal error
- */
-int
-remoteDecodeClientMessageHeader (struct qemud_client_message *msg)
-{
- XDR xdr;
- int ret = -1;
-
- msg->bufferOffset = REMOTE_MESSAGE_HEADER_XDR_LEN;
-
- /* Parse the header. */
- xdrmem_create (&xdr,
- msg->buffer + msg->bufferOffset,
- msg->bufferLength - msg->bufferOffset,
- XDR_DECODE);
-
- if (!xdr_remote_message_header (&xdr, &msg->hdr))
- goto cleanup;
-
- msg->bufferOffset += xdr_getpos(&xdr);
-
- ret = 0;
-
-cleanup:
- xdr_destroy(&xdr);
- return ret;
-}
-
-
-/*
- * @msg: the outgoing message, whose header to encode
- *
- * Encodes the header part of the client message, setting the
- * message offset ready to encode the payload. Leaves space
- * for the length field later. Upon return bufferLength will
- * refer to the total available space for message, while
- * bufferOffset will refer to current space used by header
- *
- * returns 0 if successfully encoded, -1 upon fatal error
- */
-int
-remoteEncodeClientMessageHeader (struct qemud_client_message *msg)
-{
- XDR xdr;
- int ret = -1;
- unsigned int len = 0;
-
- msg->bufferLength = sizeof(msg->buffer);
- msg->bufferOffset = 0;
-
- /* Format the header. */
- xdrmem_create (&xdr,
- msg->buffer,
- msg->bufferLength,
- XDR_ENCODE);
-
- /* The real value is filled in shortly */
- if (!xdr_u_int (&xdr, &len)) {
- goto cleanup;
- }
-
- if (!xdr_remote_message_header (&xdr, &msg->hdr))
- goto cleanup;
-
- len = xdr_getpos(&xdr);
- xdr_setpos(&xdr, 0);
-
- /* Fill in current length - may be re-written later
- * if a payload is added
- */
- if (!xdr_u_int (&xdr, &len)) {
- goto cleanup;
- }
-
- msg->bufferOffset += len;
-
- ret = 0;
-
-cleanup:
- xdr_destroy(&xdr);
- return ret;
-}
-
-
-static int
-remoteDispatchClientCall (struct qemud_server *server,
- struct qemud_client *client,
- struct qemud_client_message *msg,
- bool qemu_protocol);
-
-
-/*
- * @server: the unlocked server object
- * @client: the locked client object
- * @msg: the complete incoming message packet, with header already decoded
- *
- * This function gets called from qemud when it pulls a incoming
- * remote protocol message off the dispatch queue for processing.
- *
- * The @msg parameter must have had its header decoded already by
- * calling remoteDecodeClientMessageHeader
- *
- * Returns 0 if the message was dispatched, -1 upon fatal error
- */
-int
-remoteDispatchClientRequest(struct qemud_server *server,
- struct qemud_client *client,
- struct qemud_client_message *msg)
-{
- int ret;
- remote_error rerr;
- bool qemu_call;
-
- VIR_DEBUG("prog=%d ver=%d type=%d status=%d serial=%d proc=%d",
- msg->hdr.prog, msg->hdr.vers, msg->hdr.type,
- msg->hdr.status, msg->hdr.serial, msg->hdr.proc);
-
- memset(&rerr, 0, sizeof rerr);
-
- /* Check version, etc. */
- if (msg->hdr.prog == REMOTE_PROGRAM)
- qemu_call = false;
- else if (msg->hdr.prog == QEMU_PROGRAM)
- qemu_call = true;
- else {
- remoteDispatchFormatError (&rerr,
- _("program mismatch (actual %x, expected %x or %x)"),
- msg->hdr.prog, REMOTE_PROGRAM, QEMU_PROGRAM);
- goto error;
- }
-
- if (!qemu_call && msg->hdr.vers != REMOTE_PROTOCOL_VERSION) {
- remoteDispatchFormatError (&rerr,
- _("version mismatch (actual %x, expected %x)"),
- msg->hdr.vers, REMOTE_PROTOCOL_VERSION);
- goto error;
- }
- else if (qemu_call && msg->hdr.vers != QEMU_PROTOCOL_VERSION) {
- remoteDispatchFormatError (&rerr,
- _("version mismatch (actual %x, expected %x)"),
- msg->hdr.vers, QEMU_PROTOCOL_VERSION);
- goto error;
- }
-
- switch (msg->hdr.type) {
- case REMOTE_CALL:
- return remoteDispatchClientCall(server, client, msg, qemu_call);
-
- case REMOTE_STREAM:
- /* Since stream data is non-acked, async, we may continue to received
- * stream packets after we closed down a stream. Just drop & ignore
- * these.
- */
- VIR_INFO("Ignoring unexpected stream data serial=%d proc=%d status=%d",
- msg->hdr.serial, msg->hdr.proc, msg->hdr.status);
- qemudClientMessageRelease(client, msg);
- break;
-
- default:
- remoteDispatchFormatError (&rerr, _("type (%d) != REMOTE_CALL"),
- (int) msg->hdr.type);
- goto error;
- }
-
- return 0;
-
-error:
- ret = remoteSerializeReplyError(client, &rerr, &msg->hdr);
-
- if (ret >= 0)
- VIR_FREE(msg);
-
- return ret;
-}
-
-
-/*
- * @server: the unlocked server object
- * @client: the locked client object
- * @msg: the complete incoming method call, with header already decoded
- *
- * This method is used to dispatch an message representing an
- * incoming method call from a client. It decodes the payload
- * to obtain method call arguments, invokves the method and
- * then sends a reply packet with the return values
- *
- * Returns 0 if the reply was sent, or -1 upon fatal error
- */
-static int
-remoteDispatchClientCall (struct qemud_server *server,
- struct qemud_client *client,
- struct qemud_client_message *msg,
- bool qemu_protocol)
-{
- XDR xdr;
- remote_error rerr;
- dispatch_args args;
- dispatch_ret ret;
- const dispatch_data *data = NULL;
- int rv = -1;
- unsigned int len;
- virConnectPtr conn = NULL;
-
- memset(&args, 0, sizeof args);
- memset(&ret, 0, sizeof ret);
- memset(&rerr, 0, sizeof rerr);
-
- if (msg->hdr.status != REMOTE_OK) {
- remoteDispatchFormatError (&rerr, _("status (%d) != REMOTE_OK"),
- (int) msg->hdr.status);
- goto rpc_error;
- }
-
- /* If client is marked as needing auth, don't allow any RPC ops,
- * except for authentication ones
- */
- if (client->auth) {
- if (msg->hdr.proc != REMOTE_PROC_AUTH_LIST &&
- msg->hdr.proc != REMOTE_PROC_AUTH_SASL_INIT &&
- msg->hdr.proc != REMOTE_PROC_AUTH_SASL_START &&
- msg->hdr.proc != REMOTE_PROC_AUTH_SASL_STEP &&
- msg->hdr.proc != REMOTE_PROC_AUTH_POLKIT
- ) {
- /* Explicitly *NOT* calling remoteDispatchAuthError() because
- we want back-compatability with libvirt clients which don't
- support the VIR_ERR_AUTH_FAILED error code */
- remoteDispatchFormatError (&rerr, "%s", _("authentication required"));
- goto rpc_error;
- }
- }
-
- if (qemu_protocol)
- data = qemuGetDispatchData(msg->hdr.proc);
- else
- data = remoteGetDispatchData(msg->hdr.proc);
-
- if (!data) {
- remoteDispatchFormatError (&rerr, _("unknown procedure: %d"),
- msg->hdr.proc);
- goto rpc_error;
- }
-
- /* De-serialize payload with args from the wire message */
- xdrmem_create (&xdr,
- msg->buffer + msg->bufferOffset,
- msg->bufferLength - msg->bufferOffset,
- XDR_DECODE);
- if (!((data->args_filter)(&xdr, &args))) {
- xdr_destroy (&xdr);
- remoteDispatchFormatError (&rerr, "%s", _("parse args failed"));
- goto rpc_error;
- }
- xdr_destroy (&xdr);
-
- /* Call function. */
- conn = client->conn;
- virMutexUnlock(&client->lock);
-
- /*
- * When the RPC handler is called:
- *
- * - Server object is unlocked
- * - Client object is unlocked
- *
- * Without locking, it is safe to use:
- *
- * 'conn', 'rerr', 'args and 'ret'
- */
- rv = (data->fn)(server, client, conn, &msg->hdr, &rerr, &args, &ret);
-
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
-
- xdr_free (data->args_filter, (char*)&args);
-
- if (rv < 0)
- goto rpc_error;
-
- /* Return header. We're re-using same message object, so
- * only need to tweak type/status fields */
- /*msg->hdr.prog = msg->hdr.prog;*/
- /*msg->hdr.vers = msg->hdr.vers;*/
- /*msg->hdr.proc = msg->hdr.proc;*/
- msg->hdr.type = REMOTE_REPLY;
- /*msg->hdr.serial = msg->hdr.serial;*/
- msg->hdr.status = REMOTE_OK;
-
- if (remoteEncodeClientMessageHeader(msg) < 0) {
- xdr_free (data->ret_filter, (char*)&ret);
- remoteDispatchFormatError(&rerr, "%s", _("failed to serialize reply header"));
- goto xdr_hdr_error;
- }
-
-
- /* Now for the payload */
- xdrmem_create (&xdr,
- msg->buffer,
- msg->bufferLength,
- XDR_ENCODE);
-
- if (xdr_setpos(&xdr, msg->bufferOffset) == 0) {
- remoteDispatchFormatError(&rerr, "%s", _("failed to change XDR reply offset"));
- goto xdr_error;
- }
-
- /* If OK, serialise return structure, if error serialise error. */
- /* Serialise reply data */
- if (!((data->ret_filter) (&xdr, &ret))) {
- remoteDispatchFormatError(&rerr, "%s", _("failed to serialize reply payload (probable message size limit)"));
- goto xdr_error;
- }
-
- /* Update the length word. */
- msg->bufferOffset += xdr_getpos (&xdr);
- len = msg->bufferOffset;
- if (xdr_setpos (&xdr, 0) == 0) {
- remoteDispatchFormatError(&rerr, "%s", _("failed to change XDR reply offset"));
- goto xdr_error;
- }
-
- if (!xdr_u_int (&xdr, &len)) {
- remoteDispatchFormatError(&rerr, "%s", _("failed to update reply length header"));
- goto xdr_error;
- }
-
- xdr_destroy (&xdr);
- xdr_free (data->ret_filter, (char*)&ret);
-
- /* Reset ready for I/O */
- msg->bufferLength = len;
- msg->bufferOffset = 0;
-
- /* Put reply on end of tx queue to send out */
- qemudClientMessageQueuePush(&client->tx, msg);
- qemudUpdateClientEvent(client);
-
- return 0;
-
-xdr_error:
- /* Bad stuff serializing reply. Try to send a little info
- * back to client to assist in bug reporting/diagnosis */
- xdr_free (data->ret_filter, (char*)&ret);
- xdr_destroy (&xdr);
- /* fallthrough */
-
-xdr_hdr_error:
- VIR_WARN("Failed to serialize reply for program '%d' proc '%d' as XDR",
- msg->hdr.prog, msg->hdr.proc);
- /* fallthrough */
-
-rpc_error:
- /* Bad stuff (de-)serializing message, but we have an
- * RPC error message we can send back to the client */
- rv = remoteSerializeReplyError(client, &rerr, &msg->hdr);
-
- if (rv >= 0)
- VIR_FREE(msg);
-
- return rv;
-}
-
-
-int
-remoteSendStreamData(struct qemud_client *client,
- struct qemud_client_stream *stream,
- const char *data,
- unsigned int len)
-{
- struct qemud_client_message *msg;
- XDR xdr;
-
- VIR_DEBUG("client=%p stream=%p data=%p len=%d", client, stream, data, len);
-
- if (VIR_ALLOC(msg) < 0) {
- return -1;
- }
-
- /* Return header. We're re-using same message object, so
- * only need to tweak type/status fields */
- msg->hdr.prog = REMOTE_PROGRAM;
- msg->hdr.vers = REMOTE_PROTOCOL_VERSION;
- msg->hdr.proc = stream->procedure;
- msg->hdr.type = REMOTE_STREAM;
- msg->hdr.serial = stream->serial;
- /*
- * NB
- * data != NULL + len > 0 => REMOTE_CONTINUE (Sending back data)
- * data != NULL + len == 0 => REMOTE_CONTINUE (Sending read EOF)
- * data == NULL => REMOTE_OK (Sending finish handshake confirmation)
- */
- msg->hdr.status = data ? REMOTE_CONTINUE : REMOTE_OK;
-
- if (remoteEncodeClientMessageHeader(msg) < 0)
- goto fatal_error;
-
- if (data && len) {
- if ((msg->bufferLength - msg->bufferOffset) < len)
- goto fatal_error;
-
- /* Now for the payload */
- xdrmem_create (&xdr,
- msg->buffer,
- msg->bufferLength,
- XDR_ENCODE);
-
- /* Skip over existing header already written */
- if (xdr_setpos(&xdr, msg->bufferOffset) == 0)
- goto xdr_error;
-
- memcpy(msg->buffer + msg->bufferOffset, data, len);
- msg->bufferOffset += len;
-
- /* Update the length word. */
- len = msg->bufferOffset;
- if (xdr_setpos (&xdr, 0) == 0)
- goto xdr_error;
-
- if (!xdr_u_int (&xdr, &len))
- goto xdr_error;
-
- xdr_destroy (&xdr);
-
- VIR_DEBUG("Total %d", msg->bufferOffset);
- }
- if (data)
- msg->streamTX = 1;
-
- /* Reset ready for I/O */
- msg->bufferLength = msg->bufferOffset;
- msg->bufferOffset = 0;
-
- /* Put reply on end of tx queue to send out */
- qemudClientMessageQueuePush(&client->tx, msg);
- qemudUpdateClientEvent(client);
-
- return 0;
-
-xdr_error:
- xdr_destroy (&xdr);
-fatal_error:
- VIR_FREE(msg);
- VIR_WARN("Failed to serialize stream data for proc %d as XDR",
- stream->procedure);
- return -1;
-}
+++ /dev/null
-/*
- * dispatch.h: RPC message dispatching infrastructure
- *
- * Copyright (C) 2007, 2008, 2009 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Richard W.M. Jones <rjones@redhat.com>
- * Author: Daniel P. Berrange <berrange@redhat.com>
- */
-
-#ifndef __LIBVIRTD_DISPATCH_H__
-# define __LIBVIRTD_DISPATCH_H__
-
-
-# include "libvirtd.h"
-
-
-int
-remoteDecodeClientMessageHeader (struct qemud_client_message *req);
-int
-remoteEncodeClientMessageHeader (struct qemud_client_message *req);
-
-int
-remoteDispatchClientRequest (struct qemud_server *server,
- struct qemud_client *client,
- struct qemud_client_message *req);
-
-
-void remoteDispatchFormatError (remote_error *rerr,
- const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(2, 3);
-
-void remoteDispatchAuthError (remote_error *rerr);
-void remoteDispatchGenericError (remote_error *rerr);
-void remoteDispatchError(remote_error *rerr);
-
-
-int
-remoteSerializeReplyError(struct qemud_client *client,
- remote_error *rerr,
- remote_message_header *req);
-int
-remoteSerializeStreamError(struct qemud_client *client,
- remote_error *rerr,
- int proc,
- int serial);
-
-
-int
-remoteSendStreamData(struct qemud_client *client,
- struct qemud_client_stream *stream,
- const char *data,
- unsigned int len);
-
-#endif /* __LIBVIRTD_DISPATCH_H__ */
#include <config.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/poll.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <string.h>
-#include <errno.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
#include <getopt.h>
-#include <fnmatch.h>
+#include <stdlib.h>
#include <grp.h>
-#include <signal.h>
-#include <netdb.h>
#include <locale.h>
#include "libvirt_internal.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
#include "libvirtd.h"
-#include "dispatch.h"
#include "util.h"
#include "uuid.h"
#include "remote_driver.h"
#include "conf.h"
-#include "event_poll.h"
#include "memory.h"
-#include "stream.h"
+#include "conf.h"
+#include "virnetserver.h"
+#include "threads.h"
+#include "remote.h"
+#include "remote_driver.h"
#include "hooks.h"
+#include "uuid.h"
#include "virtaudit.h"
-#ifdef HAVE_AVAHI
-# include "mdns.h"
-#endif
#ifdef WITH_DRIVER_MODULES
# include "driver.h"
# endif
#endif
-
-#ifdef __sun
-# include <ucred.h>
-# include <priv.h>
-
-# ifndef PRIV_VIRT_MANAGE
-# define PRIV_VIRT_MANAGE ((const char *)"virt_manage")
-# endif
-
-# ifndef PRIV_XVM_CONTROL
-# define PRIV_XVM_CONTROL ((const char *)"xvm_control")
-# endif
-
-# define PU_RESETGROUPS 0x0001 /* Remove supplemental groups */
-# define PU_CLEARLIMITSET 0x0008 /* L=0 */
-
-extern int __init_daemon_priv(int, uid_t, gid_t, ...);
-
-# define SYSTEM_UID 60
-
-static gid_t unix_sock_gid = 60; /* Not used */
-static int unix_sock_rw_mask = 0666;
-static int unix_sock_ro_mask = 0666;
-
-#else
-
-static gid_t unix_sock_gid = 0; /* Only root by default */
-static int unix_sock_rw_mask = 0700; /* Allow user only */
-static int unix_sock_ro_mask = 0777; /* Allow world */
-
-#endif /* __sun */
-
#include "configmake.h"
-static int godaemon = 0; /* -d: Be a daemon */
-static int verbose = 0; /* -v: Verbose mode */
-static int timeout = -1; /* -t: Shutdown timeout */
-static int sigwrite = -1; /* Signal handler pipe */
-static int ipsock = 0; /* -l Listen for TCP/IP */
-
-/* Defaults for configuration file elements */
-static int listen_tls = 1;
-static int listen_tcp = 0;
-static char *listen_addr = (char *) LIBVIRTD_LISTEN_ADDR;
-static char *tls_port = (char *) LIBVIRTD_TLS_PORT;
-static char *tcp_port = (char *) LIBVIRTD_TCP_PORT;
+virNetSASLContextPtr saslCtxt = NULL;
+virNetServerProgramPtr remoteProgram = NULL;
+virNetServerProgramPtr qemuProgram = NULL;
-static char *unix_sock_dir = NULL;
+struct daemonConfig {
+ char *host_uuid;
-#if HAVE_POLKIT
-static int auth_unix_rw = REMOTE_AUTH_POLKIT;
-static int auth_unix_ro = REMOTE_AUTH_POLKIT;
-#else
-static int auth_unix_rw = REMOTE_AUTH_NONE;
-static int auth_unix_ro = REMOTE_AUTH_NONE;
-#endif /* HAVE_POLKIT */
-#if HAVE_SASL
-static int auth_tcp = REMOTE_AUTH_SASL;
-#else
-static int auth_tcp = REMOTE_AUTH_NONE;
-#endif
-static int auth_tls = REMOTE_AUTH_NONE;
+ int listen_tls;
+ int listen_tcp;
+ char *listen_addr;
+ char *tls_port;
+ char *tcp_port;
-static int mdns_adv = 1;
-static char *mdns_name = NULL;
+ char *unix_sock_ro_perms;
+ char *unix_sock_rw_perms;
+ char *unix_sock_group;
+ char *unix_sock_dir;
-static int tls_no_verify_certificate = 0;
-static char **tls_allowed_dn_list = NULL;
+ int auth_unix_rw;
+ int auth_unix_ro;
+ int auth_tcp;
+ int auth_tls;
-static char *key_file = (char *) LIBVIRT_SERVERKEY;
-static char *cert_file = (char *) LIBVIRT_SERVERCERT;
-static char *ca_file = (char *) LIBVIRT_CACERT;
-static char *crl_file = (char *) "";
+ int mdns_adv;
+ char *mdns_name;
-static gnutls_certificate_credentials_t x509_cred;
-static gnutls_dh_params_t dh_params;
+ int tls_no_verify_certificate;
+ char **tls_allowed_dn_list;
+ char **sasl_allowed_username_list;
-static int min_workers = 5;
-static int max_workers = 20;
-static int max_clients = 20;
+ char *key_file;
+ char *cert_file;
+ char *ca_file;
+ char *crl_file;
-/* Total number of 'in-process' RPC calls allowed across all clients */
-static int max_requests = 20;
-/* Total number of 'in-process' RPC calls allowed by a single client*/
-static int max_client_requests = 5;
+ int min_workers;
+ int max_workers;
+ int max_clients;
-static int audit_level = 1;
-static int audit_logging = 0;
+ int max_requests;
+ int max_client_requests;
-#define DH_BITS 1024
+ int log_level;
+ char *log_filters;
+ char *log_outputs;
+ int log_buffer_size;
-static sig_atomic_t sig_errors = 0;
-static int sig_lasterrno = 0;
-static const char *argv0;
+ int audit_level;
+ int audit_logging;
+};
enum {
VIR_DAEMON_ERR_NONE = 0,
"Unable to look for hook scripts",
"Unable to initialize audit system")
-static void sig_handler(int sig, siginfo_t * siginfo,
- void* context ATTRIBUTE_UNUSED) {
- int origerrno;
- int r;
-
- /* set the sig num in the struct */
- siginfo->si_signo = sig;
-
- origerrno = errno;
- r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
- if (r == -1) {
- sig_errors++;
- sig_lasterrno = errno;
- }
- errno = origerrno;
-}
-
-static void sig_fatal(int sig, siginfo_t * siginfo ATTRIBUTE_UNUSED,
- void* context ATTRIBUTE_UNUSED) {
- struct sigaction sig_action;
- int origerrno;
-
- origerrno = errno;
- virLogEmergencyDumpAll(sig);
-
- /*
- * If the signal is fatal, avoid looping over this handler
- * by desactivating it
- */
- if (sig != SIGUSR2) {
- sig_action.sa_flags = SA_SIGINFO;
- sig_action.sa_handler = SIG_IGN;
- sigaction(sig, &sig_action, NULL);
- }
- errno = origerrno;
-}
-
-static void qemudDispatchClientEvent(int watch, int fd, int events, void *opaque);
-static void qemudDispatchServerEvent(int watch, int fd, int events, void *opaque);
-static int qemudStartWorker(struct qemud_server *server, struct qemud_worker *worker);
-
-void
-qemudClientMessageQueuePush(struct qemud_client_message **queue,
- struct qemud_client_message *msg)
-{
- struct qemud_client_message *tmp = *queue;
-
- if (tmp) {
- while (tmp->next)
- tmp = tmp->next;
- tmp->next = msg;
- } else {
- *queue = msg;
- }
-}
-
-struct qemud_client_message *
-qemudClientMessageQueueServe(struct qemud_client_message **queue)
-{
- struct qemud_client_message *tmp = *queue;
-
- if (tmp) {
- *queue = tmp->next;
- tmp->next = NULL;
- }
-
- return tmp;
-}
-
-static int
-remoteCheckCertFile(const char *type, const char *file)
-{
- struct stat sb;
- if (stat(file, &sb) < 0) {
- char ebuf[1024];
- VIR_ERROR(_("Cannot access %s '%s': %s"),
- type, file, virStrerror(errno, ebuf, sizeof ebuf));
- return -1;
- }
- return 0;
-}
-
-static int
-remoteInitializeGnuTLS (void)
+static int daemonForkIntoBackground(const char *argv0)
{
- int err;
-
- err = gnutls_certificate_allocate_credentials (&x509_cred);
- if (err) {
- VIR_ERROR(_("gnutls_certificate_allocate_credentials: %s"),
- gnutls_strerror (err));
- return -1;
- }
-
- if (ca_file && ca_file[0] != '\0') {
- if (remoteCheckCertFile("CA certificate", ca_file) < 0)
- return -1;
-
- VIR_DEBUG("loading CA cert from %s", ca_file);
- err = gnutls_certificate_set_x509_trust_file (x509_cred, ca_file,
- GNUTLS_X509_FMT_PEM);
- if (err < 0) {
- VIR_ERROR(_("gnutls_certificate_set_x509_trust_file: %s"),
- gnutls_strerror (err));
- return -1;
- }
- }
-
- if (crl_file && crl_file[0] != '\0') {
- if (remoteCheckCertFile("CA revocation list", crl_file) < 0)
- return -1;
-
- VIR_DEBUG("loading CRL from %s", crl_file);
- err = gnutls_certificate_set_x509_crl_file (x509_cred, crl_file,
- GNUTLS_X509_FMT_PEM);
- if (err < 0) {
- VIR_ERROR(_("gnutls_certificate_set_x509_crl_file: %s"),
- gnutls_strerror (err));
- return -1;
- }
- }
-
- if (cert_file && cert_file[0] != '\0' && key_file && key_file[0] != '\0') {
- if (remoteCheckCertFile("server certificate", cert_file) < 0)
- return -1;
- if (remoteCheckCertFile("server key", key_file) < 0)
- return -1;
- VIR_DEBUG("loading cert and key from %s and %s", cert_file, key_file);
- err =
- gnutls_certificate_set_x509_key_file (x509_cred,
- cert_file, key_file,
- GNUTLS_X509_FMT_PEM);
- if (err < 0) {
- VIR_ERROR(_("gnutls_certificate_set_x509_key_file: %s"),
- gnutls_strerror (err));
- return -1;
- }
- }
-
- /* 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.
- */
- err = gnutls_dh_params_init (&dh_params);
- if (err < 0) {
- VIR_ERROR(_("gnutls_dh_params_init: %s"), gnutls_strerror (err));
- return -1;
- }
- err = gnutls_dh_params_generate2 (dh_params, DH_BITS);
- if (err < 0) {
- VIR_ERROR(_("gnutls_dh_params_generate2: %s"), gnutls_strerror (err));
- return -1;
- }
-
- gnutls_certificate_set_dh_params (x509_cred, dh_params);
-
- return 0;
-}
-
-static void
-qemudDispatchSignalEvent(int watch ATTRIBUTE_UNUSED,
- int fd ATTRIBUTE_UNUSED,
- int events ATTRIBUTE_UNUSED,
- void *opaque) {
- struct qemud_server *server = (struct qemud_server *)opaque;
- siginfo_t siginfo;
-
- virMutexLock(&server->lock);
-
- if (saferead(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
- char ebuf[1024];
- VIR_ERROR(_("Failed to read from signal pipe: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- virMutexUnlock(&server->lock);
- return;
- }
-
- switch (siginfo.si_signo) {
- case SIGHUP:
- VIR_INFO("Reloading configuration on SIGHUP");
- virHookCall(VIR_HOOK_DRIVER_DAEMON, "-",
- VIR_HOOK_DAEMON_OP_RELOAD, SIGHUP, "SIGHUP", NULL);
- if (virStateReload() < 0)
- VIR_WARN("Error while reloading drivers");
-
- break;
-
- case SIGINT:
- case SIGQUIT:
- case SIGTERM:
- VIR_WARN("Shutting down on signal %d", siginfo.si_signo);
- server->quitEventThread = 1;
- break;
-
- default:
- VIR_INFO("Received unexpected signal %d", siginfo.si_signo);
- break;
- }
-
- virMutexUnlock(&server->lock);
-}
-
-
-static int daemonForkIntoBackground(void) {
int statuspipe[2];
if (pipe(statuspipe) < 0)
return -1;
}
}
-static int qemudWritePidFile(const char *pidFile) {
+static int daemonWritePidFile(const char *pidFile, const char *argv0)
+{
int fd;
FILE *fh;
char ebuf[1024];
return 0;
}
-static int qemudListenUnix(struct qemud_server *server,
- char *path, int readonly, int auth) {
- struct qemud_socket *sock;
- mode_t oldmask;
- char ebuf[1024];
-
- if (VIR_ALLOC(sock) < 0) {
- VIR_ERROR(_("Failed to allocate memory for struct qemud_socket"));
- return -1;
- }
-
- sock->readonly = readonly;
- sock->type = QEMUD_SOCK_TYPE_UNIX;
- sock->auth = auth;
- sock->path = path;
- sock->addr.len = sizeof(sock->addr.data.un);
- if (!(sock->addrstr = strdup(path))) {
- VIR_ERROR(_("Failed to copy socket address: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- goto cleanup;
- }
-
- if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
- VIR_ERROR(_("Failed to create socket: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- goto cleanup;
- }
-
- if (virSetCloseExec(sock->fd) < 0 ||
- virSetNonBlock(sock->fd) < 0)
- goto cleanup;
-
- sock->addr.data.un.sun_family = AF_UNIX;
- if (virStrcpyStatic(sock->addr.data.un.sun_path, path) == NULL) {
- VIR_ERROR(_("Path %s too long for unix socket"), path);
- goto cleanup;
- }
- if (sock->addr.data.un.sun_path[0] == '@')
- sock->addr.data.un.sun_path[0] = '\0';
-
- oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask);
- if (bind(sock->fd, &sock->addr.data.sa, sock->addr.len) < 0) {
- VIR_ERROR(_("Failed to bind socket to '%s': %s"),
- path, virStrerror(errno, ebuf, sizeof ebuf));
- umask(oldmask);
- goto cleanup;
- }
- umask(oldmask);
-
- /* chown() doesn't work for abstract sockets but we use them only
- * if libvirtd runs unprivileged
- */
- if (server->privileged && chown(path, -1, unix_sock_gid)) {
- VIR_ERROR(_("Failed to change group ID of '%s' to %d: %s"),
- path, unix_sock_gid,
- virStrerror(errno, ebuf, sizeof ebuf));
- goto cleanup;
- }
-
- if (listen(sock->fd, 30) < 0) {
- VIR_ERROR(_("Failed to listen for connections on '%s': %s"),
- path, virStrerror(errno, ebuf, sizeof ebuf));
- goto cleanup;
- }
-
- sock->next = server->sockets;
- server->sockets = sock;
- server->nsockets++;
-
- return 0;
-
- cleanup:
- VIR_FORCE_CLOSE(sock->fd);
- VIR_FREE(sock);
- return -1;
-}
-
-/* See: http://people.redhat.com/drepper/userapi-ipv6.html */
-static int
-remoteMakeSockets (int *fds, int max_fds, int *nfds_r, const char *node, const char *service)
-{
- struct addrinfo *ai;
- struct addrinfo hints;
- memset (&hints, 0, sizeof hints);
- hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
- hints.ai_socktype = SOCK_STREAM;
-
- int e = getaddrinfo (node, service, &hints, &ai);
- if (e != 0) {
- VIR_ERROR(_("getaddrinfo: %s"), gai_strerror (e));
- return -1;
- }
-
- struct addrinfo *runp = ai;
- while (runp && *nfds_r < max_fds) {
- char ebuf[1024];
- fds[*nfds_r] = socket (runp->ai_family, runp->ai_socktype,
- runp->ai_protocol);
- if (fds[*nfds_r] == -1) {
- VIR_ERROR(_("socket: %s"), virStrerror (errno, ebuf, sizeof ebuf));
- return -1;
- }
-
- int opt = 1;
- setsockopt (fds[*nfds_r], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
-
-#ifdef IPV6_V6ONLY
- if (runp->ai_family == PF_INET6) {
- int on = 1;
- /*
- * Normally on Linux an INET6 socket will bind to the INET4
- * address too. If getaddrinfo returns results with INET4
- * first though, this will result in INET6 binding failing.
- * We can trivially cope with multiple server sockets, so
- * we force it to only listen on IPv6
- */
- setsockopt(fds[*nfds_r], IPPROTO_IPV6,IPV6_V6ONLY,
- (void*)&on, sizeof on);
- }
-#endif
-
- if (bind (fds[*nfds_r], runp->ai_addr, runp->ai_addrlen) == -1) {
- if (errno != EADDRINUSE) {
- VIR_ERROR(_("bind: %s"), virStrerror (errno, ebuf, sizeof ebuf));
- return -1;
- }
- VIR_FORCE_CLOSE(fds[*nfds_r]);
- } else {
- ++*nfds_r;
- }
- runp = runp->ai_next;
- }
-
- freeaddrinfo (ai);
- return 0;
-}
-/* Listen on the named/numbered TCP port. On a machine with IPv4 and
- * IPv6 interfaces this may generate several sockets.
- */
static int
-remoteListenTCP (struct qemud_server *server,
- const char *addr,
- const char *port,
- int type,
- int auth)
+daemonPidFilePath(bool privileged,
+ char **pidfile)
{
- int fds[2];
- int nfds = 0;
- int i;
- struct qemud_socket *sock;
-
- if (remoteMakeSockets (fds, 2, &nfds, addr, port) == -1)
- return -1;
-
- for (i = 0; i < nfds; ++i) {
- char ebuf[1024];
-
- if (VIR_ALLOC(sock) < 0) {
- VIR_ERROR(_("remoteListenTCP: calloc: %s"),
- virStrerror (errno, ebuf, sizeof ebuf));
- goto cleanup;
- }
-
- sock->addr.len = sizeof(sock->addr.data.stor);
- sock->readonly = 0;
- sock->next = server->sockets;
- server->sockets = sock;
- server->nsockets++;
-
- sock->fd = fds[i];
- sock->type = type;
- sock->auth = auth;
-
- if (getsockname(sock->fd, &sock->addr.data.sa, &sock->addr.len) < 0)
- goto cleanup;
+ if (privileged) {
+ if (!(*pidfile = strdup(LOCALSTATEDIR "/run/libvirtd.pid")))
+ goto no_memory;
+ } else {
+ char *userdir = NULL;
- if (!(sock->addrstr = virSocketFormatAddrFull(&sock->addr, true, ";")))
- goto cleanup;
+ if (!(userdir = virGetUserDirectory(geteuid())))
+ goto error;
- if (virSetCloseExec(sock->fd) < 0 ||
- virSetNonBlock(sock->fd) < 0)
- goto cleanup;
+ if (virAsprintf(pidfile, "%s/.libvirt/libvirtd.pid", userdir) < 0)
+ goto no_memory;
- if (listen (sock->fd, 30) < 0) {
- VIR_ERROR(_("remoteListenTCP: listen: %s"),
- virStrerror (errno, ebuf, sizeof ebuf));
- goto cleanup;
- }
+ VIR_FREE(userdir);
}
return 0;
-cleanup:
- for (i = 0; i < nfds; ++i)
- VIR_FORCE_CLOSE(fds[i]);
+no_memory:
+ virReportOOMError();
+error:
return -1;
}
-static int qemudInitPaths(struct qemud_server *server,
- char **sockname,
- char **roSockname)
+static int
+daemonUnixSocketPaths(struct daemonConfig *config,
+ bool privileged,
+ char **sockfile,
+ char **rosockfile)
{
- char *base_dir_prefix = NULL;
- char *sock_dir_prefix = NULL;
- int ret = -1;
-
- /* The base_dir_prefix is the base under which all libvirtd
- * files live */
- if (server->privileged) {
- if (!(base_dir_prefix = strdup (LOCALSTATEDIR)))
+ if (config->unix_sock_dir) {
+ if (virAsprintf(sockfile, "%s/libvirt-sock", config->unix_sock_dir) < 0)
goto no_memory;
- } else {
- uid_t uid = geteuid();
- if (!(base_dir_prefix = virGetUserDirectory(uid)))
- goto cleanup;
- }
-
- /* The unix_sock_dir is the location under which all
- * unix domain sockets live */
- if (unix_sock_dir) {
- if (!(sock_dir_prefix = strdup(unix_sock_dir)))
+ if (privileged &&
+ virAsprintf(rosockfile, "%s/libvirt-sock-ro", config->unix_sock_dir) < 0)
goto no_memory;
-
- /* Change the group ownership of /var/run/libvirt to unix_sock_gid */
- if (server->privileged) {
- if (chown(unix_sock_dir, -1, unix_sock_gid) < 0)
- VIR_ERROR(_("Failed to change group ownership of %s"),
- unix_sock_dir);
- }
} else {
- if (server->privileged) {
- if (virAsprintf(&sock_dir_prefix, "%s/run/libvirt",
- base_dir_prefix) < 0)
+ if (privileged) {
+ if (!(*sockfile = strdup(LOCALSTATEDIR "/run/libvirt/libvirt-sock")))
goto no_memory;
- } else {
- if (virAsprintf(&sock_dir_prefix, "%s/.libvirt",
- base_dir_prefix) < 0)
+ if (!(*rosockfile = strdup(LOCALSTATEDIR "/run/libvirt/libvirt-sock-ro")))
goto no_memory;
- }
- }
+ } else {
+ char *userdir = NULL;
- if (server->privileged) {
- if (virAsprintf(sockname, "%s/libvirt-sock",
- sock_dir_prefix) < 0)
- goto no_memory;
- if (virAsprintf(roSockname, "%s/libvirt-sock-ro",
- sock_dir_prefix) < 0)
- goto no_memory;
- unlink(*sockname);
- unlink(*roSockname);
- } else {
- if (virAsprintf(sockname, "@%s/libvirt-sock",
- sock_dir_prefix) < 0)
- goto no_memory;
- /* There is no RO socket in unprivileged mode,
- * since the user always has full RW access
- * to their private instance */
- }
+ if (!(userdir = virGetUserDirectory(geteuid())))
+ goto error;
- if (server->privileged) {
- if (virAsprintf(&server->logDir, "%s/log/libvirt",
- base_dir_prefix) < 0)
- goto no_memory;
- } else {
- if (virAsprintf(&server->logDir, "%s/.libvirt/log",
- base_dir_prefix) < 0)
- goto no_memory;
- }
+ if (virAsprintf(sockfile, "@%s/.libvirt/libvirt-sock", userdir) < 0) {
+ VIR_FREE(userdir);
+ goto no_memory;
+ }
- ret = 0;
+ VIR_FREE(userdir);
+ }
+ }
+ return 0;
no_memory:
- if (ret != 0)
- virReportOOMError();
-
- cleanup:
- VIR_FREE(base_dir_prefix);
- VIR_FREE(sock_dir_prefix);
- return ret;
+ virReportOOMError();
+error:
+ return -1;
}
-static void virshErrorHandler(void *opaque ATTRIBUTE_UNUSED, virErrorPtr err ATTRIBUTE_UNUSED)
+
+static void daemonErrorHandler(void *opaque ATTRIBUTE_UNUSED,
+ virErrorPtr err ATTRIBUTE_UNUSED)
{
/* Don't do anything, since logging infrastructure already
* took care of reporting the error */
return priority;
}
-
-static struct qemud_server *qemudInitialize(void) {
- struct qemud_server *server;
-
- if (VIR_ALLOC(server) < 0) {
- VIR_ERROR(_("Failed to allocate struct qemud_server"));
- return NULL;
- }
-
- server->privileged = geteuid() == 0 ? 1 : 0;
- server->sigread = server->sigwrite = -1;
-
- if (virMutexInit(&server->lock) < 0) {
- VIR_ERROR(_("cannot initialize mutex"));
- VIR_FREE(server);
- return NULL;
- }
- if (virCondInit(&server->job) < 0) {
- VIR_ERROR(_("cannot initialize condition variable"));
- virMutexDestroy(&server->lock);
- VIR_FREE(server);
- return NULL;
- }
-
- if (virEventRegisterDefaultImpl() < 0) {
- virMutexDestroy(&server->lock);
- if (virCondDestroy(&server->job) < 0)
- {}
- VIR_FREE(server);
- return NULL;
- }
-
+static void daemonInitialize(void)
+{
/*
* Note that the order is important: the first ones have a higher
* priority when calling virStateInitialize. We must register
umlRegister();
# endif
#endif
-
- return server;
}
-static int qemudNetworkInit(struct qemud_server *server) {
- char *sockname = NULL;
- char *roSockname = NULL;
-#if HAVE_SASL
- int err;
-#endif /* HAVE_SASL */
- if (qemudInitPaths(server, &sockname, &roSockname) < 0)
- goto cleanup;
+static int daemonSetupNetworking(virNetServerPtr srv,
+ struct daemonConfig *config,
+ const char *sock_path,
+ const char *sock_path_ro,
+ bool ipsock,
+ bool privileged)
+{
+ virNetServerServicePtr svc = NULL;
+ virNetServerServicePtr svcRO = NULL;
+ virNetServerServicePtr svcTCP = NULL;
+ virNetServerServicePtr svcTLS = NULL;
+ gid_t unix_sock_gid = 0;
+ int unix_sock_ro_mask = 0;
+ int unix_sock_rw_mask = 0;
+
+ if (config->unix_sock_group) {
+ if (virGetGroupID(config->unix_sock_group, &unix_sock_gid) < 0)
+ return -1;
+ }
- if (qemudListenUnix(server, sockname, 0, auth_unix_rw) < 0)
- goto cleanup;
- sockname = NULL;
+ if (virStrToLong_i(config->unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
+ VIR_ERROR(_("Failed to parse mode '%s'"), config->unix_sock_ro_perms);
+ goto error;
+ }
- if (roSockname != NULL && qemudListenUnix(server, roSockname, 1, auth_unix_ro) < 0)
- goto cleanup;
- roSockname = NULL;
+ 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;
+ }
-#if HAVE_SASL
- if (auth_unix_rw == REMOTE_AUTH_SASL ||
- auth_unix_ro == REMOTE_AUTH_SASL ||
- auth_tcp == REMOTE_AUTH_SASL ||
- auth_tls == REMOTE_AUTH_SASL) {
- if ((err = sasl_server_init(NULL, "libvirt")) != SASL_OK) {
- VIR_ERROR(_("Failed to initialize SASL authentication %s"),
- sasl_errstring(err, NULL, NULL));
- goto cleanup;
- }
- }
-#endif
-
-#if HAVE_POLKIT0
- if (auth_unix_rw == REMOTE_AUTH_POLKIT ||
- auth_unix_ro == REMOTE_AUTH_POLKIT) {
- DBusError derr;
-
- dbus_connection_set_change_sigpipe(FALSE);
- dbus_threads_init_default();
+ if (!(svc = virNetServerServiceNewUNIX(sock_path,
+ unix_sock_rw_mask,
+ unix_sock_gid,
+ config->auth_unix_rw,
+ false,
+ NULL)))
+ goto error;
+ if (sock_path_ro &&
+ !(svcRO = virNetServerServiceNewUNIX(sock_path_ro,
+ unix_sock_ro_mask,
+ unix_sock_gid,
+ config->auth_unix_ro,
+ true,
+ NULL)))
+ goto error;
- dbus_error_init(&derr);
- server->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
- if (!(server->sysbus)) {
- VIR_ERROR(_("Failed to connect to system bus for PolicyKit auth: %s"),
- derr.message);
- dbus_error_free(&derr);
- goto cleanup;
- }
- dbus_connection_set_exit_on_disconnect(server->sysbus, FALSE);
- }
-#endif
+ if (virNetServerAddService(srv, svc, NULL) < 0)
+ goto error;
+ if (svcRO &&
+ virNetServerAddService(srv, svcRO, NULL) < 0)
+ goto error;
if (ipsock) {
- if (listen_tcp && remoteListenTCP (server, listen_addr, tcp_port, QEMUD_SOCK_TYPE_TCP, auth_tcp) < 0)
- goto cleanup;
-
- if (listen_tls) {
- if (remoteInitializeGnuTLS () < 0)
- goto cleanup;
-
- if (remoteListenTCP (server, listen_addr, tls_port, QEMUD_SOCK_TYPE_TLS, auth_tls) < 0)
- goto cleanup;
- }
- }
-
-#ifdef HAVE_AVAHI
- if (server->privileged && mdns_adv) {
- struct libvirtd_mdns_group *group;
- struct qemud_socket *sock;
- int port = 0;
- int ret;
-
- server->mdns = libvirtd_mdns_new();
-
- if (!mdns_name) {
- char *groupname, *localhost, *tmp;
-
- localhost = virGetHostname(NULL);
- if (localhost == NULL)
- /* we couldn't resolve the hostname; assume that we are
- * running in disconnected operation, and report a less
- * useful Avahi string
- */
- ret = virAsprintf(&groupname, "Virtualization Host");
- else {
- /* Extract the host part of the potentially FQDN */
- if ((tmp = strchr(localhost, '.')))
- *tmp = '\0';
- ret = virAsprintf(&groupname, "Virtualization Host %s",
- localhost);
- }
- VIR_FREE(localhost);
- if (ret < 0) {
- virReportOOMError();
- goto cleanup;
- }
- group = libvirtd_mdns_add_group(server->mdns, groupname);
- VIR_FREE(groupname);
- } else {
- group = libvirtd_mdns_add_group(server->mdns, mdns_name);
- }
-
- /*
- * See if there's a TLS enabled port we can advertise. Cowardly
- * don't bother to advertise TCP since we don't want people using
- * them for real world apps
- */
- sock = server->sockets;
- while (sock) {
- if (virSocketGetPort(&sock->addr) != -1 &&
- sock->type == QEMUD_SOCK_TYPE_TLS) {
- port = virSocketGetPort(&sock->addr);
- break;
- }
- sock = sock->next;
- }
-
- /*
- * Add the primary entry - we choose SSH because its most likely to always
- * be available
- */
- libvirtd_mdns_add_entry(group, "_libvirt._tcp", port);
- libvirtd_mdns_start(server->mdns);
- }
-#endif
-
- return 0;
-
- cleanup:
- VIR_FREE(sockname);
- VIR_FREE(roSockname);
- return -1;
-}
-
-static int qemudNetworkEnable(struct qemud_server *server) {
- struct qemud_socket *sock;
-
- sock = server->sockets;
- while (sock) {
- if ((sock->watch = virEventAddHandle(sock->fd,
- VIR_EVENT_HANDLE_READABLE |
- VIR_EVENT_HANDLE_ERROR |
- VIR_EVENT_HANDLE_HANGUP,
- qemudDispatchServerEvent,
- server, NULL)) < 0) {
- VIR_ERROR(_("Failed to add server event callback"));
- return -1;
- }
-
- sock = sock->next;
- }
- return 0;
-}
-
-
-static gnutls_session_t
-remoteInitializeTLSSession (void)
-{
- gnutls_session_t session;
- int err;
-
- err = gnutls_init (&session, GNUTLS_SERVER);
- if (err != 0) goto failed;
-
- /* avoid calling all the priority functions, since the defaults
- * are adequate.
- */
- err = gnutls_set_default_priority (session);
- if (err != 0) goto failed;
-
- err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
- if (err != 0) goto failed;
-
- /* request client certificate if any.
- */
- gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
-
- gnutls_dh_set_prime_bits (session, DH_BITS);
-
- return session;
-
-failed:
- VIR_ERROR(_("remoteInitializeTLSSession: %s"),
- gnutls_strerror (err));
- return NULL;
-}
-
-/* Check DN is on tls_allowed_dn_list. */
-static int
-remoteCheckDN (const char *dname)
-{
- char **wildcards;
-
- /* If the list is not set, allow any DN. */
- wildcards = tls_allowed_dn_list;
- if (!wildcards)
- return 1;
-
- while (*wildcards) {
- if (fnmatch (*wildcards, dname, 0) == 0)
- return 1;
- wildcards++;
- }
-
- /* Print the client's DN. */
- VIR_DEBUG("remoteCheckDN: failed: client DN is %s", dname);
-
- return 0; /* Not found. */
-}
-
-static int
-remoteCheckCertificate(struct qemud_client *client)
-{
- int ret;
- unsigned int status;
- const gnutls_datum_t *certs;
- unsigned int nCerts, i;
- time_t now;
- char name[256];
- size_t namesize = sizeof name;
-
- memset(name, 0, namesize);
-
- if ((ret = gnutls_certificate_verify_peers2 (client->tlssession, &status)) < 0){
- VIR_ERROR(_("Failed to verify certificate peers: %s"),
- gnutls_strerror (ret));
- goto authdeny;
- }
-
- if (status != 0) {
- if (status & GNUTLS_CERT_INVALID)
- VIR_ERROR(_("The client certificate is not trusted."));
-
- if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
- VIR_ERROR(_("The client certificate has unknown issuer."));
-
- if (status & GNUTLS_CERT_REVOKED)
- VIR_ERROR(_("The client certificate has been revoked."));
-
-#ifndef GNUTLS_1_0_COMPAT
- if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
- VIR_ERROR(_("The client certificate uses an insecure algorithm."));
-#endif
-
- goto authdeny;
- }
-
- if (gnutls_certificate_type_get(client->tlssession) != GNUTLS_CRT_X509) {
- VIR_ERROR(_("Only x509 certificates are supported"));
- goto authdeny;
- }
-
- if (!(certs = gnutls_certificate_get_peers(client->tlssession, &nCerts))) {
- VIR_ERROR(_("The certificate has no peers"));
- goto authdeny;
- }
-
- now = time (NULL);
-
- for (i = 0; i < nCerts; i++) {
- gnutls_x509_crt_t cert;
+ if (config->listen_tcp) {
+ if (!(svcTCP = virNetServerServiceNewTCP(config->listen_addr,
+ config->tcp_port,
+ config->auth_tcp,
+ false,
+ NULL)))
+ goto error;
- if (gnutls_x509_crt_init (&cert) < 0) {
- VIR_ERROR(_("Unable to initialize certificate"));
- goto authfail;
+ if (virNetServerAddService(srv, svcTCP,
+ config->mdns_adv ? "_libvirt._tcp" : NULL) < 0)
+ goto error;
}
- if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
- VIR_ERROR(_("Unable to load certificate"));
- gnutls_x509_crt_deinit (cert);
- goto authfail;
- }
+ if (config->listen_tls) {
+ virNetTLSContextPtr ctxt = NULL;
- if (i == 0) {
- ret = gnutls_x509_crt_get_dn (cert, name, &namesize);
- if (ret != 0) {
- VIR_ERROR(_("Failed to get certificate distinguished name: %s"),
- gnutls_strerror(ret));
- gnutls_x509_crt_deinit (cert);
- goto authfail;
+ if (config->ca_file ||
+ config->cert_file ||
+ config->key_file) {
+ if (!(ctxt = virNetTLSContextNewServer(config->ca_file,
+ config->crl_file,
+ config->cert_file,
+ config->key_file,
+ (const char *const*)config->tls_allowed_dn_list,
+ config->tls_no_verify_certificate ? false : true)))
+ goto error;
+ } else {
+ if (!(ctxt = virNetTLSContextNewServerPath(NULL,
+ !privileged,
+ (const char *const*)config->tls_allowed_dn_list,
+ config->tls_no_verify_certificate ? false : true)))
+ goto error;
}
- if (!remoteCheckDN (name)) {
- /* This is the most common error: make it informative. */
- VIR_ERROR(_("Client's Distinguished Name is not on the list "
- "of allowed clients (tls_allowed_dn_list). Use "
- "'certtool -i --infile clientcert.pem' to view the"
- "Distinguished Name field in the client certificate,"
- "or run this daemon with --verbose option."));
- gnutls_x509_crt_deinit (cert);
- goto authdeny;
+ if (!(svcTLS =
+ virNetServerServiceNewTCP(config->listen_addr,
+ config->tls_port,
+ config->auth_tls,
+ false,
+ ctxt))) {
+ virNetTLSContextFree(ctxt);
+ goto error;
}
- }
-
- if (gnutls_x509_crt_get_expiration_time (cert) < now) {
- VIR_ERROR(_("The client certificate has expired"));
- gnutls_x509_crt_deinit (cert);
- goto authdeny;
- }
+ if (virNetServerAddService(srv, svcTLS,
+ config->mdns_adv &&
+ !config->listen_tcp ? "_libvirt._tcp" : NULL) < 0)
+ goto error;
- if (gnutls_x509_crt_get_activation_time (cert) > now) {
- VIR_ERROR(_("The client certificate is not yet active"));
- gnutls_x509_crt_deinit (cert);
- goto authdeny;
+ virNetTLSContextFree(ctxt);
}
}
- PROBE(CLIENT_TLS_ALLOW, "fd=%d, name=%s", client->fd, (char *)name);
- return 0;
-
-authdeny:
- PROBE(CLIENT_TLS_DENY, "fd=%d, name=%s", client->fd, (char *)name);
- return -1;
-
-authfail:
- PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
- return -1;
-}
-
-/* Check the client's access. */
-static int
-remoteCheckAccess (struct qemud_client *client)
-{
- struct qemud_client_message *confirm;
-
- /* Verify client certificate. */
- if (remoteCheckCertificate (client) == -1) {
- VIR_ERROR(_("remoteCheckCertificate: "
- "failed to verify client's certificate"));
- if (!tls_no_verify_certificate) return -1;
- else VIR_INFO("remoteCheckCertificate: tls_no_verify_certificate "
- "is set so the bad certificate is ignored");
- }
-
- if (client->tx) {
- VIR_INFO("%s",
- _("client had unexpected data pending tx after access check"));
- return -1;
- }
-
- if (VIR_ALLOC(confirm) < 0)
- return -1;
-
- /* Checks have succeeded. Write a '\1' byte back to the client to
- * indicate this (otherwise the socket is abruptly closed).
- * (NB. The '\1' byte is sent in an encrypted record).
- */
- confirm->async = 1;
- confirm->bufferLength = 1;
- confirm->bufferOffset = 0;
- confirm->buffer[0] = '\1';
-
- client->tx = confirm;
- return 0;
-}
-
-#if HAVE_POLKIT
-int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid) {
-# ifdef SO_PEERCRED
- struct ucred cr;
- unsigned int cr_len = sizeof (cr);
-
- if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) < 0) {
- char ebuf[1024];
- VIR_ERROR(_("Failed to verify client credentials: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- return -1;
- }
-
- *pid = cr.pid;
- *uid = cr.uid;
-# else
- /* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
-# error "UNIX socket credentials not supported/implemented on this platform yet..."
-# endif
- return 0;
-}
-#endif
-
-
-static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock) {
- int fd;
- virSocketAddr addr;
- char *addrstr = NULL;
- struct qemud_client *client = NULL;
- int no_slow_start = 1;
- int i;
-
- addr.len = sizeof(addr.data.stor);
- if ((fd = accept(sock->fd, &addr.data.sa, &addr.len)) < 0) {
- char ebuf[1024];
- if (errno == EAGAIN)
- return 0;
- VIR_ERROR(_("Failed to accept connection: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- return -1;
- }
- if (!(addrstr = virSocketFormatAddrFull(&addr, true, ";"))) {
- VIR_ERROR(_("Failed to format addresss: out of memory"));
- goto error;
- }
-
- PROBE(CLIENT_CONNECT, "fd=%d, readonly=%d localAddr=%s remoteAddr=%s",
- fd, sock->readonly, sock->addrstr, addrstr);
-
- if (server->nclients >= max_clients) {
- VIR_ERROR(_("Too many active clients (%d), dropping connection from %s"),
- max_clients, addrstr);
- goto error;
- }
-
- if (VIR_RESIZE_N(server->clients, server->nclients_max,
- server->nclients, 1) < 0) {
- VIR_ERROR(_("Out of memory allocating clients"));
- goto error;
- }
-
-#ifdef __sun
- {
- ucred_t *ucred = NULL;
- const priv_set_t *privs;
-
- if (getpeerucred (fd, &ucred) == -1 ||
- (privs = ucred_getprivset (ucred, PRIV_EFFECTIVE)) == NULL) {
- if (ucred != NULL)
- ucred_free (ucred);
- goto error;
- }
-
- if (!priv_ismember (privs, PRIV_VIRT_MANAGE)) {
- ucred_free (ucred);
+ if (config->auth_unix_rw == REMOTE_AUTH_SASL ||
+ config->auth_unix_ro == REMOTE_AUTH_SASL ||
+ config->auth_tcp == REMOTE_AUTH_SASL ||
+ config->auth_tls == REMOTE_AUTH_SASL) {
+ saslCtxt = virNetSASLContextNewServer(
+ (const char *const*)config->sasl_allowed_username_list);
+ if (!saslCtxt)
goto error;
- }
-
- ucred_free (ucred);
- }
-#endif /* __sun */
-
- /* Disable Nagle. Unix sockets will ignore this. */
- setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
- sizeof no_slow_start);
-
- if (virSetCloseExec(fd) < 0 ||
- virSetNonBlock(fd) < 0) {
- goto error;
}
- if (VIR_ALLOC(client) < 0)
- goto error;
- if (virMutexInit(&client->lock) < 0) {
- VIR_ERROR(_("cannot initialize mutex"));
- goto error;
- }
-
- client->magic = QEMUD_CLIENT_MAGIC;
- client->fd = fd;
- client->readonly = sock->readonly;
- client->type = sock->type;
- client->auth = sock->auth;
- client->addr = addr;
- client->addrstr = addrstr;
- addrstr = NULL;
-
- for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
- client->domainEventCallbackID[i] = -1;
- }
-
- /* Prepare one for packet receive */
- if (VIR_ALLOC(client->rx) < 0)
- goto error;
- client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
+#if HAVE_POLKIT0
+ if (auth_unix_rw == REMOTE_AUTH_POLKIT ||
+ auth_unix_ro == REMOTE_AUTH_POLKIT) {
+ DBusError derr;
+ dbus_connection_set_change_sigpipe(FALSE);
+ dbus_threads_init_default();
-#if HAVE_POLKIT
- /* Only do policy checks for non-root - allow root user
- through with no checks, as a fail-safe - root can easily
- change policykit policy anyway, so its pointless trying
- to restrict root */
- if (client->auth == REMOTE_AUTH_POLKIT) {
- uid_t uid;
- pid_t pid;
-
- if (qemudGetSocketIdentity(client->fd, &uid, &pid) < 0)
+ dbus_error_init(&derr);
+ server->sysbus = dbus_bus_get(DBUS_BUS_SYSTEM, &derr);
+ if (!(server->sysbus)) {
+ VIR_ERROR(_("Failed to connect to system bus for PolicyKit auth: %s"),
+ derr.message);
+ dbus_error_free(&derr);
goto error;
-
- /* Client is running as root, so disable auth */
- if (uid == 0) {
- VIR_INFO("Turn off polkit auth for privileged client pid %d from %s",
- pid, client->addrstr);
- client->auth = REMOTE_AUTH_NONE;
}
+ dbus_connection_set_exit_on_disconnect(server->sysbus, FALSE);
}
#endif
- if (client->type != QEMUD_SOCK_TYPE_TLS) {
- /* Plain socket, so prepare to read first message */
- if (qemudRegisterClientEvent (server, client) < 0)
- goto error;
- } else {
- int ret;
-
- client->tlssession = remoteInitializeTLSSession ();
- if (client->tlssession == NULL)
- goto error;
-
- gnutls_transport_set_ptr (client->tlssession,
- (gnutls_transport_ptr_t) (long) fd);
-
- /* Begin the TLS handshake. */
- ret = gnutls_handshake (client->tlssession);
- if (ret == 0) {
- client->handshake = 0;
-
- /* Unlikely, but ... Next step is to check the certificate. */
- if (remoteCheckAccess (client) == -1)
- goto error;
-
- /* Handshake & cert check OK, so prepare to read first message */
- if (qemudRegisterClientEvent(server, client) < 0)
- goto error;
- } else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
- /* Most likely, need to do more handshake data */
- client->handshake = 1;
-
- if (qemudRegisterClientEvent (server, client) < 0)
- goto error;
- } else {
- PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
- VIR_ERROR(_("TLS handshake failed for client %s: %s"),
- client->addrstr, gnutls_strerror (ret));
- goto error;
- }
- }
-
- server->clients[server->nclients++] = client;
-
- if (server->nclients > server->nactiveworkers &&
- server->nactiveworkers < server->nworkers) {
- for (i = 0 ; i < server->nworkers ; i++) {
- if (!server->workers[i].hasThread) {
- if (qemudStartWorker(server, &server->workers[i]) < 0)
- return -1;
- server->nactiveworkers++;
- break;
- }
- }
- }
-
-
return 0;
error:
- if (client) {
- if (client->tlssession) gnutls_deinit (client->tlssession);
- if (client) {
- VIR_FREE(client->addrstr);
- VIR_FREE(client->rx);
- }
- VIR_FREE(client);
- }
- VIR_FREE(addrstr);
- VIR_FORCE_CLOSE(fd);
- PROBE(CLIENT_DISCONNECT, "fd=%d", fd);
+ virNetServerServiceFree(svcTLS);
+ virNetServerServiceFree(svcTCP);
+ virNetServerServiceFree(svc);
+ virNetServerServiceFree(svcRO);
return -1;
}
-/*
- * You must hold lock for at least the client
- * We don't free stuff here, merely disconnect the client's
- * network socket & resources.
- * We keep the libvirt connection open until any async
- * jobs have finished, then clean it up elsehwere
- */
-void qemudDispatchClientFailure(struct qemud_client *client) {
- if (client->watch != -1) {
- virEventRemoveHandle(client->watch);
- client->watch = -1;
- }
-
- /* Deregister event delivery callback */
- if (client->conn) {
- int i;
-
- for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
- if (client->domainEventCallbackID[i] != -1) {
- VIR_DEBUG("Deregistering to relay remote events %d", i);
- virConnectDomainEventDeregisterAny(client->conn,
- client->domainEventCallbackID[i]);
- }
- client->domainEventCallbackID[i] = -1;
- }
- }
-
-#if HAVE_SASL
- if (client->saslconn) {
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- }
- VIR_FREE(client->saslUsername);
-#endif
- if (client->tlssession) {
- gnutls_deinit (client->tlssession);
- client->tlssession = NULL;
- }
- if (client->fd != -1) {
- PROBE(CLIENT_DISCONNECT, "fd=%d", client->fd);
- VIR_FORCE_CLOSE(client->fd);
- }
- VIR_FREE(client->addrstr);
-}
-
-
-/* Caller must hold server lock */
-static struct qemud_client *qemudPendingJob(struct qemud_server *server)
-{
- int i;
- for (i = 0 ; i < server->nclients ; i++) {
- virMutexLock(&server->clients[i]->lock);
- if (server->clients[i]->dx) {
- /* Delibrately don't unlock client - caller wants the lock */
- return server->clients[i];
- }
- virMutexUnlock(&server->clients[i]->lock);
- }
- return NULL;
-}
-
-static void *qemudWorker(void *data)
-{
- struct qemud_worker *worker = data;
- struct qemud_server *server = worker->server;
-
- while (1) {
- struct qemud_client *client = NULL;
- struct qemud_client_message *msg;
-
- virMutexLock(&server->lock);
- while ((client = qemudPendingJob(server)) == NULL) {
- if (worker->quitRequest ||
- virCondWait(&server->job, &server->lock) < 0) {
- virMutexUnlock(&server->lock);
- return NULL;
- }
- }
- if (worker->quitRequest) {
- virMutexUnlock(&client->lock);
- virMutexUnlock(&server->lock);
- return NULL;
- }
- worker->processingCall = 1;
- virMutexUnlock(&server->lock);
-
- /* We own a locked client now... */
- client->refs++;
-
- /* Remove our message from dispatch queue while we use it */
- msg = qemudClientMessageQueueServe(&client->dx);
-
- /* This function drops the lock during dispatch,
- * and re-acquires it before returning */
- if (remoteDispatchClientRequest (server, client, msg) < 0) {
- VIR_FREE(msg);
- qemudDispatchClientFailure(client);
- client->refs--;
- virMutexUnlock(&client->lock);
- continue;
- }
-
- client->refs--;
- virMutexUnlock(&client->lock);
-
- virMutexLock(&server->lock);
- worker->processingCall = 0;
- virMutexUnlock(&server->lock);
- }
-}
-
-static int
-qemudStartWorker(struct qemud_server *server,
- struct qemud_worker *worker)
+static int daemonShutdownCheck(virNetServerPtr srv ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
{
- pthread_attr_t attr;
- int ret = -1;
-
- if (pthread_attr_init(&attr) != 0)
- return -1;
- /* We want to join workers, so don't detach them */
- /*pthread_attr_setdetachstate(&attr, 1);*/
-
- if (worker->hasThread)
- goto cleanup;
-
- worker->server = server;
- worker->hasThread = 1;
- worker->quitRequest = 0;
- worker->processingCall = 0;
-
- if (pthread_create(&worker->thread,
- &attr,
- qemudWorker,
- worker) != 0) {
- worker->hasThread = 0;
- worker->server = NULL;
- goto cleanup;
- }
-
- ret = 0;
-cleanup:
- pthread_attr_destroy(&attr);
- return ret;
-}
-
-
-/*
- * Read data into buffer using wire decoding (plain or TLS)
- *
- * Returns:
- * -1 on error or EOF
- * 0 on EAGAIN
- * n number of bytes
- */
-static ssize_t qemudClientReadBuf(struct qemud_client *client,
- char *data, ssize_t len) {
- ssize_t ret;
-
- if (len < 0) {
- VIR_ERROR(_("unexpected negative length request %lld"),
- (long long int) len);
- qemudDispatchClientFailure(client);
- return -1;
- }
-
- /* VIR_DEBUG("qemudClientRead: len = %d", len);*/
-
- if (!client->tlssession) {
- char ebuf[1024];
- ret = read (client->fd, data, len);
- if (ret == -1 && (errno == EAGAIN ||
- errno == EINTR))
- return 0;
- if (ret <= 0) {
- if (ret != 0)
- VIR_ERROR(_("read: %s"),
- virStrerror (errno, ebuf, sizeof ebuf));
- qemudDispatchClientFailure(client);
- return -1;
- }
- } else {
- ret = gnutls_record_recv (client->tlssession, data, len);
-
- if (ret < 0 && (ret == GNUTLS_E_AGAIN ||
- ret == GNUTLS_E_INTERRUPTED))
- return 0;
- if (ret <= 0) {
- if (ret != 0)
- VIR_ERROR(_("gnutls_record_recv: %s"),
- gnutls_strerror (ret));
- qemudDispatchClientFailure(client);
- return -1;
- }
- }
-
- return ret;
-}
-
-/*
- * Read data into buffer without decoding
- *
- * Returns:
- * -1 on error or EOF
- * 0 on EAGAIN
- * n number of bytes
- */
-static ssize_t qemudClientReadPlain(struct qemud_client *client) {
- ssize_t ret;
- ret = qemudClientReadBuf(client,
- client->rx->buffer + client->rx->bufferOffset,
- client->rx->bufferLength - client->rx->bufferOffset);
- if (ret <= 0)
- return ret; /* -1 error, 0 eagain */
-
- client->rx->bufferOffset += ret;
- return ret;
-}
-
-#if HAVE_SASL
-/*
- * Read data into buffer decoding with SASL
- *
- * Returns:
- * -1 on error or EOF
- * 0 on EAGAIN
- * n number of bytes
- */
-static ssize_t qemudClientReadSASL(struct qemud_client *client) {
- ssize_t got, want;
-
- /* We're doing a SSF data read, so now its times to ensure
- * future writes are under SSF too.
- *
- * cf remoteSASLCheckSSF in remote.c
- */
- client->saslSSF |= QEMUD_SASL_SSF_WRITE;
-
- /* Need to read some more data off the wire */
- if (client->saslDecoded == NULL) {
- int ret;
- ssize_t encodedLen;
-
- encodedLen = qemudClientReadBuf(client, client->saslTemporary,
- sizeof(client->saslTemporary));
-
- if (encodedLen <= 0)
- return encodedLen;
-
- ret = sasl_decode(client->saslconn, client->saslTemporary, encodedLen,
- &client->saslDecoded, &client->saslDecodedLength);
-
- if (ret != SASL_OK) {
- VIR_ERROR(_("failed to decode SASL data %s"),
- sasl_errstring(ret, NULL, NULL));
- qemudDispatchClientFailure(client);
- return -1;
- }
-
- client->saslDecodedOffset = 0;
- }
-
- /* Some buffered decoded data to return now */
- got = client->saslDecodedLength - client->saslDecodedOffset;
- want = client->rx->bufferLength - client->rx->bufferOffset;
-
- if (want > got)
- want = got;
-
- memcpy(client->rx->buffer + client->rx->bufferOffset,
- client->saslDecoded + client->saslDecodedOffset, want);
- client->saslDecodedOffset += want;
- client->rx->bufferOffset += want;
-
- if (client->saslDecodedOffset == client->saslDecodedLength) {
- client->saslDecoded = NULL;
- client->saslDecodedOffset = client->saslDecodedLength = 0;
- }
-
- return want;
-}
-#endif
-
-/*
- * Read as much data off wire as possible till we fill our
- * buffer, or would block on I/O
- */
-static ssize_t qemudClientRead(struct qemud_client *client) {
-#if HAVE_SASL
- if (client->saslSSF & QEMUD_SASL_SSF_READ)
- return qemudClientReadSASL(client);
- else
-#endif
- return qemudClientReadPlain(client);
-}
-
-
-/*
- * Read data until we get a complete message to process
- */
-static void qemudDispatchClientRead(struct qemud_server *server,
- struct qemud_client *client) {
- /* VIR_DEBUG("qemudDispatchClientRead: mode = %d", client->mode);*/
-
-readmore:
- if (qemudClientRead(client) < 0)
- return; /* Error */
-
- if (client->rx->bufferOffset < client->rx->bufferLength)
- return; /* Still not read enough */
-
- /* Either done with length word header */
- if (client->rx->bufferLength == REMOTE_MESSAGE_HEADER_XDR_LEN) {
- unsigned int len;
- XDR x;
-
- xdrmem_create(&x, client->rx->buffer, client->rx->bufferLength, XDR_DECODE);
-
- if (!xdr_u_int(&x, &len)) {
- xdr_destroy (&x);
- VIR_DEBUG("Failed to decode packet length");
- qemudDispatchClientFailure(client);
- return;
- }
- xdr_destroy (&x);
-
- if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
- VIR_DEBUG("Packet length %u too small", len);
- qemudDispatchClientFailure(client);
- return;
- }
-
- /* Length includes the size of the length word itself */
- len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
-
- if (len > REMOTE_MESSAGE_MAX) {
- VIR_DEBUG("Packet length %u too large", len);
- qemudDispatchClientFailure(client);
- return;
- }
-
- /* Prepare to read rest of message */
- client->rx->bufferLength += len;
-
- qemudUpdateClientEvent(client);
-
- /* Try and read payload immediately instead of going back
- into poll() because chances are the data is already
- waiting for us */
- goto readmore;
- } else {
- /* Grab the completed message */
- struct qemud_client_message *msg = qemudClientMessageQueueServe(&client->rx);
- struct qemud_client_filter *filter;
-
- /* Decode the header so we can use it for routing decisions */
- if (remoteDecodeClientMessageHeader(msg) < 0) {
- VIR_FREE(msg);
- qemudDispatchClientFailure(client);
- }
-
- /* Check if any filters match this message */
- filter = client->filters;
- while (filter) {
- int ret;
- ret = (filter->query)(client, msg, filter->opaque);
- if (ret == 1) {
- msg = NULL;
- break;
- } else if (ret == -1) {
- VIR_FREE(msg);
- qemudDispatchClientFailure(client);
- return;
- }
- filter = filter->next;
- }
-
- /* Move completed message to the end of the dispatch queue */
- if (msg)
- qemudClientMessageQueuePush(&client->dx, msg);
- client->nrequests++;
-
- /* Possibly need to create another receive buffer */
- if ((client->nrequests < max_client_requests &&
- VIR_ALLOC(client->rx) < 0)) {
- qemudDispatchClientFailure(client);
- } else {
- if (client->rx)
- client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
-
- qemudUpdateClientEvent(client);
-
- /* Tell one of the workers to get on with it... */
- virCondSignal(&server->job);
- }
- }
-}
-
-
-/*
- * Send a chunk of data using wire encoding (plain or TLS)
- *
- * Returns:
- * -1 on error
- * 0 on EAGAIN
- * n number of bytes
- */
-static ssize_t qemudClientWriteBuf(struct qemud_client *client,
- const char *data, ssize_t len) {
- ssize_t ret;
-
- if (len < 0) {
- VIR_ERROR(_("unexpected negative length request %lld"),
- (long long int) len);
- qemudDispatchClientFailure(client);
- return -1;
- }
-
- if (!client->tlssession) {
- char ebuf[1024];
- if ((ret = write(client->fd, data, len)) == -1) {
- if (errno == EAGAIN || errno == EINTR)
- return 0;
- VIR_ERROR(_("write: %s"), virStrerror (errno, ebuf, sizeof ebuf));
- qemudDispatchClientFailure(client);
- return -1;
- }
- } else {
- ret = gnutls_record_send (client->tlssession, data, len);
- if (ret < 0) {
- if (ret == GNUTLS_E_INTERRUPTED ||
- ret == GNUTLS_E_AGAIN)
- return 0;
-
- VIR_ERROR(_("gnutls_record_send: %s"), gnutls_strerror (ret));
- qemudDispatchClientFailure(client);
- return -1;
- }
- }
- return ret;
-}
-
-
-/*
- * Send client->tx using no encoding
- *
- * Returns:
- * -1 on error or EOF
- * 0 on EAGAIN
- * n number of bytes
- */
-static int qemudClientWritePlain(struct qemud_client *client) {
- int ret = qemudClientWriteBuf(client,
- client->tx->buffer + client->tx->bufferOffset,
- client->tx->bufferLength - client->tx->bufferOffset);
- if (ret <= 0)
- return ret; /* -1 error, 0 = egain */
- client->tx->bufferOffset += ret;
- return ret;
-}
-
-
-#if HAVE_SASL
-/*
- * Send client->tx using SASL encoding
- *
- * Returns:
- * -1 on error
- * 0 on EAGAIN
- * n number of bytes
- */
-static int qemudClientWriteSASL(struct qemud_client *client) {
- int ret;
-
- /* Not got any pending encoded data, so we need to encode raw stuff */
- if (client->saslEncoded == NULL) {
- ret = sasl_encode(client->saslconn,
- client->tx->buffer + client->tx->bufferOffset,
- client->tx->bufferLength - client->tx->bufferOffset,
- &client->saslEncoded,
- &client->saslEncodedLength);
-
- if (ret != SASL_OK) {
- VIR_ERROR(_("failed to encode SASL data %s"),
- sasl_errstring(ret, NULL, NULL));
- qemudDispatchClientFailure(client);
- return -1;
- }
-
- client->saslEncodedOffset = 0;
- }
-
- /* Send some of the encoded stuff out on the wire */
- ret = qemudClientWriteBuf(client,
- client->saslEncoded + client->saslEncodedOffset,
- client->saslEncodedLength - client->saslEncodedOffset);
-
- if (ret <= 0)
- return ret; /* -1 error, 0 == egain */
-
- /* Note how much we sent */
- client->saslEncodedOffset += ret;
-
- /* Sent all encoded, so update raw buffer to indicate completion */
- if (client->saslEncodedOffset == client->saslEncodedLength) {
- client->saslEncoded = NULL;
- client->saslEncodedOffset = client->saslEncodedLength = 0;
-
- /* Mark as complete, so caller detects completion */
- client->tx->bufferOffset = client->tx->bufferLength;
- }
-
- return ret;
-}
-#endif
-
-/*
- * Send as much data in the client->tx as possible
- *
- * Returns:
- * -1 on error or EOF
- * 0 on EAGAIN
- * n number of bytes
- */
-static ssize_t qemudClientWrite(struct qemud_client *client) {
-#if HAVE_SASL
- if (client->saslSSF & QEMUD_SASL_SSF_WRITE)
- return qemudClientWriteSASL(client);
- else
-#endif
- return qemudClientWritePlain(client);
-}
-
-
-void
-qemudClientMessageRelease(struct qemud_client *client,
- struct qemud_client_message *msg)
-{
- if (msg->streamTX) {
- remoteStreamMessageFinished(client, msg);
- } else if (!msg->async)
- client->nrequests--;
-
- /* See if the recv queue is currently throttled */
- if (!client->rx &&
- client->nrequests < max_client_requests) {
- /* Reset message record for next RX attempt */
- memset(msg, 0, sizeof(*msg));
- client->rx = msg;
- /* Get ready to receive next message */
- client->rx->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN;
- } else {
- VIR_FREE(msg);
- }
-
- qemudUpdateClientEvent(client);
-}
-
-
-/*
- * Process all queued client->tx messages until
- * we would block on I/O
- */
-static void
-qemudDispatchClientWrite(struct qemud_client *client) {
- while (client->tx) {
- ssize_t ret;
-
- ret = qemudClientWrite(client);
- if (ret < 0) {
- qemudDispatchClientFailure(client);
- return;
- }
- if (ret == 0)
- return; /* Would block on write EAGAIN */
-
- if (client->tx->bufferOffset == client->tx->bufferLength) {
- struct qemud_client_message *reply;
-
- /* Get finished reply from head of tx queue */
- reply = qemudClientMessageQueueServe(&client->tx);
-
- qemudClientMessageRelease(client, reply);
-
- if (client->closing)
- qemudDispatchClientFailure(client);
- }
- }
-}
-
-static void
-qemudDispatchClientHandshake(struct qemud_client *client) {
- int ret;
- /* Continue the handshake. */
- ret = gnutls_handshake (client->tlssession);
- if (ret == 0) {
- client->handshake = 0;
-
- /* Finished. Next step is to check the certificate. */
- if (remoteCheckAccess (client) == -1)
- qemudDispatchClientFailure(client);
- else
- qemudUpdateClientEvent(client);
- } else if (ret == GNUTLS_E_AGAIN ||
- ret == GNUTLS_E_INTERRUPTED) {
- /* Carry on waiting for more handshake. Update
- the events just in case handshake data flow
- direction has changed */
- qemudUpdateClientEvent (client);
- } else {
- PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd);
- /* Fatal error in handshake */
- VIR_ERROR(_("TLS handshake failed: %s"),
- gnutls_strerror (ret));
- qemudDispatchClientFailure(client);
- }
-}
-
-static void
-qemudDispatchClientEvent(int watch, int fd, int events, void *opaque) {
- struct qemud_server *server = (struct qemud_server *)opaque;
- struct qemud_client *client = NULL;
- int i;
-
- virMutexLock(&server->lock);
-
- for (i = 0 ; i < server->nclients ; i++) {
- virMutexLock(&server->clients[i]->lock);
- if (server->clients[i]->watch == watch) {
- client = server->clients[i];
- break;
- }
- virMutexUnlock(&server->clients[i]->lock);
- }
-
- virMutexUnlock(&server->lock);
-
- if (!client) {
- return;
- }
-
- if (client->fd != fd) {
- virMutexUnlock(&client->lock);
- return;
- }
-
- if (events & (VIR_EVENT_HANDLE_WRITABLE |
- VIR_EVENT_HANDLE_READABLE)) {
- if (client->handshake) {
- qemudDispatchClientHandshake(client);
- } else {
- if (events & VIR_EVENT_HANDLE_WRITABLE)
- qemudDispatchClientWrite(client);
- if (events & VIR_EVENT_HANDLE_READABLE)
- qemudDispatchClientRead(server, client);
- }
- }
-
- /* NB, will get HANGUP + READABLE at same time upon
- * disconnect */
- if (events & (VIR_EVENT_HANDLE_ERROR |
- VIR_EVENT_HANDLE_HANGUP))
- qemudDispatchClientFailure(client);
-
- virMutexUnlock(&client->lock);
-}
-
-
-/*
- * @client: a locked client object
- */
-static int
-qemudCalculateHandleMode(struct qemud_client *client) {
- int mode = 0;
-
- if (client->handshake) {
- if (gnutls_record_get_direction (client->tlssession) == 0)
- mode |= VIR_EVENT_HANDLE_READABLE;
- else
- mode |= VIR_EVENT_HANDLE_WRITABLE;
- } else {
- /* If there is a message on the rx queue then
- * we're wanting more input */
- if (client->rx)
- mode |= VIR_EVENT_HANDLE_READABLE;
-
- /* If there are one or more messages to send back to client,
- then monitor for writability on socket */
- if (client->tx)
- mode |= VIR_EVENT_HANDLE_WRITABLE;
- }
-
- return mode;
-}
-
-/*
- * @server: a locked or unlocked server object
- * @client: a locked client object
- */
-int qemudRegisterClientEvent(struct qemud_server *server,
- struct qemud_client *client) {
- int mode;
-
- mode = qemudCalculateHandleMode(client);
-
- if ((client->watch = virEventAddHandle(client->fd,
- mode,
- qemudDispatchClientEvent,
- server, NULL)) < 0)
- return -1;
-
- return 0;
-}
-
-/*
- * @client: a locked client object
- */
-void qemudUpdateClientEvent(struct qemud_client *client) {
- int mode;
-
- mode = qemudCalculateHandleMode(client);
-
- virEventUpdateHandle(client->watch, mode);
-}
-
-
-static void
-qemudDispatchServerEvent(int watch, int fd, int events, void *opaque) {
- struct qemud_server *server = (struct qemud_server *)opaque;
- struct qemud_socket *sock;
-
- virMutexLock(&server->lock);
-
- sock = server->sockets;
-
- while (sock) {
- if (sock->watch == watch)
- break;
-
- sock = sock->next;
- }
-
- if (sock && sock->fd == fd && events)
- qemudDispatchServer(server, sock);
-
- virMutexUnlock(&server->lock);
-}
-
-
-static int qemudOneLoop(void) {
- sig_atomic_t errors;
-
- if (virEventRunDefaultImpl() < 0)
- return -1;
-
- /* Check for any signal handling errors and log them. */
- errors = sig_errors;
- if (errors) {
- char ebuf[1024];
- sig_errors -= errors;
- VIR_ERROR(_("Signal handler reported %d errors: last error: %s"),
- errors, virStrerror (sig_lasterrno, ebuf, sizeof ebuf));
- return -1;
- }
-
- return 0;
-}
-
-static void qemudInactiveTimer(int timerid, void *data) {
- struct qemud_server *server = (struct qemud_server *)data;
-
- if (virStateActive() ||
- server->clients) {
- VIR_DEBUG("Timer expired but still active, not shutting down");
- virEventUpdateTimeout(timerid, -1);
- } else {
- VIR_DEBUG("Timer expired and inactive, shutting down");
- server->quitEventThread = 1;
- }
-}
-
-static void qemudFreeClient(struct qemud_client *client) {
- while (client->rx) {
- struct qemud_client_message *msg
- = qemudClientMessageQueueServe(&client->rx);
- VIR_FREE(msg);
- }
- while (client->dx) {
- struct qemud_client_message *msg
- = qemudClientMessageQueueServe(&client->dx);
- VIR_FREE(msg);
- }
- while (client->tx) {
- struct qemud_client_message *msg
- = qemudClientMessageQueueServe(&client->tx);
- VIR_FREE(msg);
- }
-
- while (client->streams)
- remoteRemoveClientStream(client, client->streams);
-
- if (client->conn)
- virConnectClose(client->conn);
- virMutexDestroy(&client->lock);
- VIR_FREE(client->addrstr);
- VIR_FREE(client);
-}
-
-static void *qemudRunLoop(void *opaque) {
- struct qemud_server *server = opaque;
- int timerid = -1;
- int i;
- int timerActive = 0;
-
- virMutexLock(&server->lock);
-
- if (timeout > 0 &&
- (timerid = virEventAddTimeout(-1,
- qemudInactiveTimer,
- server, NULL)) < 0) {
- VIR_ERROR(_("Failed to register shutdown timeout"));
- return NULL;
- }
-
- if (min_workers > max_workers)
- max_workers = min_workers;
-
- server->nworkers = max_workers;
- if (VIR_ALLOC_N(server->workers, server->nworkers) < 0) {
- VIR_ERROR(_("Failed to allocate workers"));
- return NULL;
- }
-
- for (i = 0 ; i < min_workers ; i++) {
- if (qemudStartWorker(server, &server->workers[i]) < 0)
- goto cleanup;
- server->nactiveworkers++;
- }
-
- for (;!server->quitEventThread;) {
- /* A shutdown timeout is specified, so check
- * if any drivers have active state, if not
- * shutdown after timeout seconds
- */
- if (timeout > 0) {
- if (timerActive) {
- if (server->clients) {
- VIR_DEBUG("Deactivating shutdown timer %d", timerid);
- virEventUpdateTimeout(timerid, -1);
- timerActive = 0;
- }
- } else {
- if (!virStateActive() &&
- !server->clients) {
- VIR_DEBUG("Activating shutdown timer %d", timerid);
- virEventUpdateTimeout(timerid, timeout * 1000);
- timerActive = 1;
- }
- }
- }
-
- virMutexUnlock(&server->lock);
- if (qemudOneLoop() < 0) {
- virMutexLock(&server->lock);
- VIR_DEBUG("Loop iteration error, exiting");
- break;
- }
- virMutexLock(&server->lock);
-
- reprocess:
- for (i = 0 ; i < server->nclients ; i++) {
- int inactive;
- virMutexLock(&server->clients[i]->lock);
- inactive = server->clients[i]->fd == -1
- && server->clients[i]->refs == 0;
- virMutexUnlock(&server->clients[i]->lock);
- if (inactive) {
- qemudFreeClient(server->clients[i]);
- server->nclients--;
- if (i < server->nclients)
- memmove(server->clients + i,
- server->clients + i + 1,
- sizeof (*server->clients) * (server->nclients - i));
-
- VIR_SHRINK_N(server->clients, server->nclients_max,
- server->nclients_max - server->nclients);
- goto reprocess;
- }
- }
-
- /* If number of active workers exceeds both the min_workers
- * threshold and the number of clients, then kill some
- * off */
- for (i = 0 ; (i < server->nworkers &&
- server->nactiveworkers > server->nclients &&
- server->nactiveworkers > min_workers) ; i++) {
-
- if (server->workers[i].hasThread &&
- !server->workers[i].processingCall) {
- server->workers[i].quitRequest = 1;
-
- virCondBroadcast(&server->job);
- virMutexUnlock(&server->lock);
- pthread_join(server->workers[i].thread, NULL);
- virMutexLock(&server->lock);
- server->workers[i].hasThread = 0;
- server->nactiveworkers--;
- }
- }
- }
-
-cleanup:
- for (i = 0 ; i < server->nworkers ; i++) {
- if (!server->workers[i].hasThread)
- continue;
-
- server->workers[i].quitRequest = 1;
- virCondBroadcast(&server->job);
-
- virMutexUnlock(&server->lock);
- pthread_join(server->workers[i].thread, NULL);
- virMutexLock(&server->lock);
- server->workers[i].hasThread = 0;
- }
- VIR_FREE(server->workers);
- for (i = 0; i < server->nclients; i++)
- qemudFreeClient(server->clients[i]);
- server->nclients = 0;
- VIR_SHRINK_N(server->clients, server->nclients_max, server->nclients_max);
-
- virMutexUnlock(&server->lock);
- return NULL;
-}
-
-
-static int
-qemudStartEventLoop(struct qemud_server *server)
-{
- pthread_attr_t attr;
- int ret = -1;
-
- if (pthread_attr_init(&attr) != 0)
- return -1;
- /* We want to join the eventloop, so don't detach it */
- /*pthread_attr_setdetachstate(&attr, 1);*/
-
- if (pthread_create(&server->eventThread,
- &attr,
- qemudRunLoop,
- server) != 0)
- goto cleanup;
-
- server->hasEventThread = 1;
-
- ret = 0;
-cleanup:
- pthread_attr_destroy(&attr);
- return ret;
-}
-
-
-static void qemudCleanup(struct qemud_server *server) {
- struct qemud_socket *sock;
-
- VIR_FORCE_CLOSE(server->sigread);
- VIR_FORCE_CLOSE(server->sigwrite);
-
- sock = server->sockets;
- while (sock) {
- struct qemud_socket *next = sock->next;
- if (sock->watch)
- virEventRemoveHandle(sock->watch);
- VIR_FORCE_CLOSE(sock->fd);
-
- /* Unlink unix domain sockets which are not in
- * the abstract namespace */
- if (sock->path &&
- sock->path[0] != '@')
- unlink(sock->path);
- VIR_FREE(sock->path);
- VIR_FREE(sock->addrstr);
-
- VIR_FREE(sock);
- sock = next;
- }
- VIR_FREE(server->logDir);
-
-#ifdef HAVE_SASL
- if (server->saslUsernameWhitelist) {
- char **list = server->saslUsernameWhitelist;
- while (*list) {
- VIR_FREE(*list);
- list++;
- }
- VIR_FREE(server->saslUsernameWhitelist);
- }
-#endif
-
-#if HAVE_POLKIT0
- if (server->sysbus)
- dbus_connection_unref(server->sysbus);
-#endif
-
- virStateCleanup();
-
- if (virCondDestroy(&server->job) < 0) {
- ;
- }
- virMutexDestroy(&server->lock);
+ if (virStateActive())
+ return 0;
- VIR_FREE(server);
+ return 1;
}
+
/* Allocate an array of malloc'd strings from the config file, filename
* (used only in diagnostics), using handle "conf". Upon error, return -1
* and free any allocated memory. Otherwise, save the array in *list_arg
virConfValuePtr p = virConfGetValue (conf, #var_name); \
if (p) { \
if (checkType (p, filename, #var_name, VIR_CONF_STRING) < 0) \
- goto free_and_fail; \
- (var_name) = strdup (p->str); \
- if ((var_name) == NULL) { \
- char ebuf[1024]; \
- VIR_ERROR(_("remoteReadConfigFile: %s"), \
- virStrerror(errno, ebuf, sizeof ebuf)); \
- goto free_and_fail; \
+ goto error; \
+ VIR_FREE(data->var_name); \
+ if (!(data->var_name = strdup (p->str))) { \
+ virReportOOMError(); \
+ goto error; \
} \
} \
} while (0)
virConfValuePtr p = virConfGetValue (conf, #var_name); \
if (p) { \
if (checkType (p, filename, #var_name, VIR_CONF_LONG) < 0) \
- goto free_and_fail; \
- (var_name) = p->l; \
+ goto error; \
+ data->var_name = p->l; \
} \
} while (0)
return 0;
if (STREQ(p->str, "none")) {
- *auth = REMOTE_AUTH_NONE;
-#if HAVE_SASL
+ *auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
} else if (STREQ(p->str, "sasl")) {
- *auth = REMOTE_AUTH_SASL;
-#endif
-#if HAVE_POLKIT
+ *auth = VIR_NET_SERVER_SERVICE_AUTH_SASL;
} else if (STREQ(p->str, "polkit")) {
- *auth = REMOTE_AUTH_POLKIT;
-#endif
+ *auth = VIR_NET_SERVER_SERVICE_AUTH_POLKIT;
} else {
VIR_ERROR(_("remoteReadConfigFile: %s: %s: unsupported auth %s"),
filename, key, p->str);
return 0;
}
-#ifdef HAVE_SASL
-static inline int
-remoteReadSaslAllowedUsernameList (virConfPtr conf,
- struct qemud_server *server,
- const char *filename)
-{
- return
- remoteConfigGetStringList (conf, "sasl_allowed_username_list",
- &server->saslUsernameWhitelist, filename);
-}
-#else
-static inline int
-remoteReadSaslAllowedUsernameList (virConfPtr conf ATTRIBUTE_UNUSED,
- struct qemud_server *server ATTRIBUTE_UNUSED,
- const char *filename ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-#endif
-
/*
* Set up the logging environment
* By default if daemonized all errors go to the logfile libvirtd.log,
* informational and debug messages. Default size if 64 kB.
*/
static int
-qemudSetLogging(struct qemud_server *server, virConfPtr conf,
- const char *filename)
+daemonSetupLogging(struct daemonConfig *config,
+ bool privileged,
+ bool verbose,
+ bool godaemon)
{
- int log_level = 0;
- int log_buffer_size = 64;
- char *log_filters = NULL;
- char *log_outputs = NULL;
- char *log_file = NULL;
- int ret = -1;
-
- GET_CONF_INT (conf, filename, log_buffer_size);
- virLogSetBufferSize(log_buffer_size);
-
virLogReset();
/*
* level has been set, we must process variables in the opposite
* order, each one overriding the previous.
*/
- GET_CONF_INT (conf, filename, log_level);
- if (log_level != 0)
- virLogSetDefaultPriority(log_level);
+ if (config->log_level != 0)
+ virLogSetDefaultPriority(config->log_level);
virLogSetFromEnv();
- if (virLogGetNbFilters() == 0) {
- GET_CONF_STR (conf, filename, log_filters);
- virLogParseFilters(log_filters);
- }
+ virLogSetBufferSize(config->log_buffer_size);
- if (virLogGetNbOutputs() == 0) {
- GET_CONF_STR (conf, filename, log_outputs);
- virLogParseOutputs(log_outputs);
- }
+ if (virLogGetNbFilters() == 0)
+ virLogParseFilters(config->log_filters);
+
+ if (virLogGetNbOutputs() == 0)
+ virLogParseOutputs(config->log_outputs);
/*
* If no defined outputs, then direct to libvirtd.log when running
char *tmp = NULL;
if (godaemon) {
- if (server->privileged) {
+ if (privileged) {
if (virAsprintf(&tmp, "%d:file:%s/log/libvirt/libvirtd.log",
virLogGetDefaultPriority(),
LOCALSTATEDIR) == -1)
- goto out_of_memory;
+ goto no_memory;
} else {
char *userdir = virGetUserDirectory(geteuid());
if (!userdir)
- goto free_and_fail;
+ goto error;
if (virAsprintf(&tmp, "%d:file:%s/.libvirt/libvirtd.log",
virLogGetDefaultPriority(), userdir) == -1) {
VIR_FREE(userdir);
- goto out_of_memory;
+ goto no_memory;
}
VIR_FREE(userdir);
}
} else {
if (virAsprintf(&tmp, "%d:stderr", virLogGetDefaultPriority()) < 0)
- goto out_of_memory;
+ goto no_memory;
}
virLogParseOutputs(tmp);
VIR_FREE(tmp);
if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
virLogSetDefaultPriority(VIR_LOG_INFO);
- ret = 0;
+ return 0;
+
+no_memory:
+ virReportOOMError();
+error:
+ return -1;
+}
+
-free_and_fail:
- VIR_FREE(log_filters);
- VIR_FREE(log_outputs);
- VIR_FREE(log_file);
- return(ret);
+static int
+daemonConfigFilePath(bool privileged, char **configfile)
+{
+ if (privileged) {
+ if (!(*configfile = strdup(SYSCONFDIR "/libvirt/libvirtd.conf")))
+ goto no_memory;
+ } else {
+ char *userdir = NULL;
+
+ if (!(userdir = virGetUserDirectory(geteuid())))
+ goto error;
+
+ if (virAsprintf(configfile, "%s/.libvirt/libvirtd.conf", userdir) < 0) {
+ VIR_FREE(userdir);
+ goto no_memory;
+ }
+ VIR_FREE(userdir);
+ }
+
+ return 0;
-out_of_memory:
+no_memory:
virReportOOMError();
- goto free_and_fail;
+error:
+ return -1;
}
-/*
- * Stop logging
- */
static void
-qemudStopLogging(void)
+daemonConfigFree(struct daemonConfig *data);
+
+static struct daemonConfig*
+daemonConfigNew(bool privileged)
{
- virLogShutdown();
+ struct daemonConfig *data;
+ char *localhost;
+ int ret;
+
+ if (VIR_ALLOC(data) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ data->listen_tls = 1;
+ data->listen_tcp = 0;
+
+ if (!(data->tls_port = strdup(LIBVIRTD_TLS_PORT)))
+ goto no_memory;
+ if (!(data->tcp_port = strdup(LIBVIRTD_TCP_PORT)))
+ goto no_memory;
+
+ /* Only default to PolicyKit if running as root */
+#if HAVE_POLKIT
+ if (privileged) {
+ data->auth_unix_rw = REMOTE_AUTH_POLKIT;
+ data->auth_unix_ro = REMOTE_AUTH_POLKIT;
+ } else {
+#endif
+ data->auth_unix_rw = REMOTE_AUTH_NONE;
+ data->auth_unix_ro = REMOTE_AUTH_NONE;
+#if HAVE_POLKIT
+ }
+#endif
+
+ if (data->auth_unix_rw == REMOTE_AUTH_POLKIT)
+ data->unix_sock_rw_perms = strdup("0777"); /* Allow world */
+ else
+ data->unix_sock_rw_perms = strdup("0700"); /* Allow user only */
+ data->unix_sock_ro_perms = strdup("0777"); /* Always allow world */
+ if (!data->unix_sock_ro_perms ||
+ !data->unix_sock_rw_perms)
+ goto no_memory;
+
+#if HAVE_SASL
+ data->auth_tcp = REMOTE_AUTH_SASL;
+#else
+ data->auth_tcp = REMOTE_AUTH_NONE;
+#endif
+ data->auth_tls = REMOTE_AUTH_NONE;
+
+ data->mdns_adv = 1;
+
+ data->min_workers = 5;
+ data->max_workers = 20;
+ data->max_clients = 20;
+
+ data->max_requests = 20;
+ data->max_client_requests = 5;
+
+ data->log_buffer_size = 64;
+
+ data->audit_level = 1;
+ data->audit_logging = 0;
+
+ localhost = virGetHostname(NULL);
+ if (localhost == NULL) {
+ /* we couldn't resolve the hostname; assume that we are
+ * running in disconnected operation, and report a less
+ * useful Avahi string
+ */
+ ret = virAsprintf(&data->mdns_name, "Virtualization Host");
+ } else {
+ char *tmp;
+ /* Extract the host part of the potentially FQDN */
+ if ((tmp = strchr(localhost, '.')))
+ *tmp = '\0';
+ ret = virAsprintf(&data->mdns_name, "Virtualization Host %s",
+ localhost);
+ }
+ VIR_FREE(localhost);
+ if (ret < 0)
+ goto no_memory;
+
+ return data;
+
+no_memory:
+ virReportOOMError();
+ daemonConfigFree(data);
+ return NULL;
+}
+
+static void
+daemonConfigFree(struct daemonConfig *data)
+{
+ char **tmp;
+
+ if (!data)
+ return;
+
+ VIR_FREE(data->listen_addr);
+ VIR_FREE(data->tls_port);
+ VIR_FREE(data->tcp_port);
+
+ VIR_FREE(data->unix_sock_ro_perms);
+ VIR_FREE(data->unix_sock_rw_perms);
+ VIR_FREE(data->unix_sock_group);
+ VIR_FREE(data->unix_sock_dir);
+ VIR_FREE(data->mdns_name);
+
+ tmp = data->tls_allowed_dn_list;
+ while (tmp && *tmp) {
+ VIR_FREE(*tmp);
+ tmp++;
+ }
+ VIR_FREE(data->tls_allowed_dn_list);
+
+ tmp = data->sasl_allowed_username_list;
+ while (tmp && *tmp) {
+ VIR_FREE(*tmp);
+ tmp++;
+ }
+ VIR_FREE(data->sasl_allowed_username_list);
+
+ VIR_FREE(data->key_file);
+ VIR_FREE(data->ca_file);
+ VIR_FREE(data->cert_file);
+ VIR_FREE(data->crl_file);
+
+ VIR_FREE(data->log_filters);
+ VIR_FREE(data->log_outputs);
+
+ VIR_FREE(data);
}
+
/* Read the config file if it exists.
* Only used in the remote case, hence the name.
*/
static int
-remoteReadConfigFile (struct qemud_server *server, const char *filename)
+daemonConfigLoad(struct daemonConfig *data,
+ const char *filename)
{
virConfPtr conf;
- /* The following variable names must match the corresponding
- configuration strings. */
- char *unix_sock_ro_perms = NULL;
- char *unix_sock_rw_perms = NULL;
- char *unix_sock_group = NULL;
- char *buf = NULL;
- char *host_uuid = NULL;
-
-#if HAVE_POLKIT
- /* Change the default back to no auth for non-root */
- if (!server->privileged && auth_unix_rw == REMOTE_AUTH_POLKIT)
- auth_unix_rw = REMOTE_AUTH_NONE;
- if (!server->privileged && auth_unix_ro == REMOTE_AUTH_POLKIT)
- auth_unix_ro = REMOTE_AUTH_NONE;
-#endif
-
conf = virConfReadFile (filename, 0);
- if (!conf) return -1;
-
- /*
- * First get all the logging settings and activate them
- */
- if (qemudSetLogging(server, conf, filename) < 0)
- goto free_and_fail;
+ if (!conf)
+ return -1;
GET_CONF_INT (conf, filename, listen_tcp);
GET_CONF_INT (conf, filename, listen_tls);
GET_CONF_STR (conf, filename, tcp_port);
GET_CONF_STR (conf, filename, listen_addr);
- if (remoteConfigGetAuth(conf, "auth_unix_rw", &auth_unix_rw, filename) < 0)
- goto free_and_fail;
+ if (remoteConfigGetAuth(conf, "auth_unix_rw", &data->auth_unix_rw, filename) < 0)
+ goto error;
#if HAVE_POLKIT
/* Change default perms to be wide-open if PolicyKit is enabled.
* Admin can always override in config file
*/
- if (auth_unix_rw == REMOTE_AUTH_POLKIT)
- unix_sock_rw_mask = 0777;
+ if (data->auth_unix_rw == REMOTE_AUTH_POLKIT) {
+ VIR_FREE(data->unix_sock_rw_perms);
+ if (!(data->unix_sock_rw_perms = strdup("0777")))
+ goto no_memory;
+ }
#endif
- if (remoteConfigGetAuth(conf, "auth_unix_ro", &auth_unix_ro, filename) < 0)
- goto free_and_fail;
- if (remoteConfigGetAuth(conf, "auth_tcp", &auth_tcp, filename) < 0)
- goto free_and_fail;
- if (remoteConfigGetAuth(conf, "auth_tls", &auth_tls, filename) < 0)
- goto free_and_fail;
+ if (remoteConfigGetAuth(conf, "auth_unix_ro", &data->auth_unix_ro, filename) < 0)
+ goto error;
+ if (remoteConfigGetAuth(conf, "auth_tcp", &data->auth_tcp, filename) < 0)
+ goto error;
+ if (remoteConfigGetAuth(conf, "auth_tls", &data->auth_tls, filename) < 0)
+ goto error;
GET_CONF_STR (conf, filename, unix_sock_group);
- if (unix_sock_group) {
- if (!server->privileged) {
- VIR_WARN("Cannot set group when not running as root");
- } else {
- int ret;
- struct group grpdata, *grp;
- size_t maxbuf = sysconf(_SC_GETGR_R_SIZE_MAX);
-
- if (maxbuf == -1)
- maxbuf = 1024;
-
- if (VIR_ALLOC_N(buf, maxbuf) < 0) {
- VIR_ERROR(_("Failed to allocate memory for buffer"));
- goto free_and_fail;
- }
-
- while ((ret = getgrnam_r(unix_sock_group, &grpdata,
- buf, maxbuf,
- &grp)) == ERANGE) {
- maxbuf *= 2;
- if (maxbuf > 65536 || VIR_REALLOC_N(buf, maxbuf) < 0) {
- VIR_ERROR(_("Failed to reallocate enough memory for buffer"));
- goto free_and_fail;
- }
- }
-
- if (ret != 0 || !grp) {
- VIR_ERROR(_("Failed to lookup group '%s'"), unix_sock_group);
- goto free_and_fail;
- }
- unix_sock_gid = grp->gr_gid;
- VIR_FREE(buf);
- }
- VIR_FREE(unix_sock_group);
- }
-
GET_CONF_STR (conf, filename, unix_sock_ro_perms);
- if (unix_sock_ro_perms) {
- if (virStrToLong_i (unix_sock_ro_perms, NULL, 8, &unix_sock_ro_mask) != 0) {
- VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_ro_perms);
- goto free_and_fail;
- }
- VIR_FREE(unix_sock_ro_perms);
- }
-
GET_CONF_STR (conf, filename, unix_sock_rw_perms);
- if (unix_sock_rw_perms) {
- if (virStrToLong_i (unix_sock_rw_perms, NULL, 8, &unix_sock_rw_mask) != 0) {
- VIR_ERROR(_("Failed to parse mode '%s'"), unix_sock_rw_perms);
- goto free_and_fail;
- }
- VIR_FREE(unix_sock_rw_perms);
- }
GET_CONF_STR (conf, filename, unix_sock_dir);
GET_CONF_STR (conf, filename, ca_file);
GET_CONF_STR (conf, filename, crl_file);
- if (remoteConfigGetStringList (conf, "tls_allowed_dn_list",
- &tls_allowed_dn_list, filename) < 0)
- goto free_and_fail;
+ if (remoteConfigGetStringList(conf, "tls_allowed_dn_list",
+ &data->tls_allowed_dn_list, filename) < 0)
+ goto error;
+
- if (remoteReadSaslAllowedUsernameList (conf, server, filename) < 0)
- goto free_and_fail;
+ if (remoteConfigGetStringList(conf, "sasl_allowed_username_list",
+ &data->sasl_allowed_username_list, filename) < 0)
+ goto error;
GET_CONF_INT (conf, filename, min_workers);
GET_CONF_INT (conf, filename, audit_logging);
GET_CONF_STR (conf, filename, host_uuid);
- if (virSetHostUUIDStr(host_uuid)) {
- VIR_ERROR(_("invalid host UUID: %s"), host_uuid);
- goto free_and_fail;
- }
- VIR_FREE(host_uuid);
+ GET_CONF_INT (conf, filename, log_level);
+ GET_CONF_STR (conf, filename, log_filters);
+ GET_CONF_STR (conf, filename, log_outputs);
+ GET_CONF_INT (conf, filename, log_buffer_size);
virConfFree (conf);
return 0;
- free_and_fail:
+no_memory:
+ virReportOOMError();
+error:
virConfFree (conf);
- VIR_FREE(host_uuid);
- VIR_FREE(mdns_name);
- VIR_FREE(unix_sock_ro_perms);
- VIR_FREE(unix_sock_rw_perms);
- VIR_FREE(unix_sock_group);
- VIR_FREE(buf);
-
- /* Don't bother trying to free listen_addr, tcp_port, tls_port, key_file,
- cert_file, ca_file, or crl_file, since they are initialized to
- non-malloc'd strings. Besides, these are static variables, and callers
- are unlikely to call this function more than once, so there wouldn't
- even be a real leak. */
-
- if (tls_allowed_dn_list) {
- int i;
- for (i = 0; tls_allowed_dn_list[i]; i++)
- VIR_FREE(tls_allowed_dn_list[i]);
- VIR_FREE(tls_allowed_dn_list);
- }
-
return -1;
}
/* Display version information. */
static void
-version (void)
+daemonVersion(const char *argv0)
{
printf ("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
}
#ifdef __sun
static int
-qemudSetupPrivs (void)
+daemonSetupPrivs(void)
{
chown ("/var/run/libvirt", SYSTEM_UID, SYSTEM_UID);
return 0;
}
#else
-# define qemudSetupPrivs() 0
+# define daemonSetupPrivs() 0
#endif
-/*
- * Doing anything non-trivial in signal handlers is pretty dangerous,
- * since there are very few async-signal safe POSIX funtions. To
- * deal with this we setup a very simple signal handler. It simply
- * writes the signal number to a pipe. The main event loop then sees
- * the signal on the pipe and can safely do the processing from
- * event loop context
- */
-static int
-daemonSetupSignals(struct qemud_server *server)
+static void daemonShutdownHandler(virNetServerPtr srv,
+ siginfo_t *sig ATTRIBUTE_UNUSED,
+ void *opaque ATTRIBUTE_UNUSED)
{
- struct sigaction sig_action;
- int sigpipe[2];
+ virNetServerQuit(srv);
+}
- if (pipe(sigpipe) < 0)
+static int daemonSetupSignals(virNetServerPtr srv)
+{
+ if (virNetServerAddSignalHandler(srv, SIGINT, daemonShutdownHandler, NULL) < 0)
return -1;
+ if (virNetServerAddSignalHandler(srv, SIGQUIT, daemonShutdownHandler, NULL) < 0)
+ return -1;
+ if (virNetServerAddSignalHandler(srv, SIGTERM, daemonShutdownHandler, NULL) < 0)
+ return -1;
+ return 0;
+}
- if (virSetNonBlock(sigpipe[0]) < 0 ||
- virSetNonBlock(sigpipe[1]) < 0 ||
- virSetCloseExec(sigpipe[0]) < 0 ||
- virSetCloseExec(sigpipe[1]) < 0) {
- char ebuf[1024];
- VIR_ERROR(_("Failed to create pipe: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- goto error;
- }
-
- sig_action.sa_sigaction = sig_handler;
- sig_action.sa_flags = SA_SIGINFO;
- sigemptyset(&sig_action.sa_mask);
-
- sigaction(SIGHUP, &sig_action, NULL);
- sigaction(SIGINT, &sig_action, NULL);
- sigaction(SIGQUIT, &sig_action, NULL);
- sigaction(SIGTERM, &sig_action, NULL);
+static void daemonRunStateInit(void *opaque)
+{
+ virNetServerPtr srv = opaque;
- /*
- * catch fatal errors to dump a log, also hook to USR2 for dynamic
- * debugging purposes or testing
- */
- sig_action.sa_sigaction = sig_fatal;
- sigaction(SIGFPE, &sig_action, NULL);
- sigaction(SIGSEGV, &sig_action, NULL);
- sigaction(SIGILL, &sig_action, NULL);
- sigaction(SIGABRT, &sig_action, NULL);
- sigaction(SIGBUS, &sig_action, NULL);
- sigaction(SIGUSR2, &sig_action, NULL);
-
- sig_action.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &sig_action, NULL);
-
- if (virEventAddHandle(sigpipe[0],
- VIR_EVENT_HANDLE_READABLE,
- qemudDispatchSignalEvent,
- server, NULL) < 0) {
- VIR_ERROR(_("Failed to register callback for signal pipe"));
- goto error;
+ /* Start the stateful HV drivers
+ * This is delibrately 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)) < 0) {
+ VIR_ERROR(_("Driver state initialization failed"));
+ virNetServerFree(srv);
+ return;
}
- server->sigread = sigpipe[0];
- server->sigwrite = sigpipe[1];
- sigwrite = sigpipe[1];
+ /* Only now accept clients from network */
+ virNetServerUpdateServices(srv, true);
+ virNetServerFree(srv);
+}
+static int daemonStateInit(virNetServerPtr srv)
+{
+ virThread thr;
+ virNetServerRef(srv);
+ if (virThreadCreate(&thr, false, daemonRunStateInit, srv) < 0) {
+ virNetServerFree(srv);
+ return -1;
+ }
return 0;
-
-error:
- VIR_FORCE_CLOSE(sigpipe[0]);
- VIR_FORCE_CLOSE(sigpipe[1]);
- return -1;
}
/* Print command-line usage. */
static void
-usage (void)
+daemonUsage(const char *argv0, bool privileged)
{
fprintf (stderr,
_("\n\
| --version Display version information.\n\
-p | --pid-file <file> Change name of PID file.\n\
\n\
-libvirt management daemon:\n\
-\n\
+libvirt management daemon:\n"), argv0);
+
+ if (privileged) {
+ fprintf(stderr,
+ _("\n\
Default paths:\n\
\n\
Configuration file (unless overridden by -f):\n\
%s/libvirt/libvirtd.conf\n\
\n\
- Sockets (as root):\n\
+ Sockets:\n\
%s/run/libvirt/libvirt-sock\n\
%s/run/libvirt/libvirt-sock-ro\n\
\n\
- Sockets (as non-root):\n\
+ TLS:\n\
+ CA certificate: %s/pki/CA/caert.pem\n\
+ Server certificate: %s/pki/libvirt/servercert.pem\n\
+ Server private key: %s/pki/libvirt/private/serverkey.pem\n\
+\n\
+ PID file (unless overridden by -p):\n\
+ %s/run/libvirtd.pid\n\
+\n"),
+ SYSCONFDIR,
+ LOCALSTATEDIR,
+ LOCALSTATEDIR,
+ SYSCONFDIR,
+ SYSCONFDIR,
+ SYSCONFDIR,
+ LOCALSTATEDIR);
+ } else {
+ fprintf(stderr,
+ "%s", _("\n\
+ Default paths:\n\
+\n\
+ Configuration file (unless overridden by -f):\n\
+ $HOME/.libvirt/libvirtd.conf\n\
+\n\
+ Sockets:\n\
$HOME/.libvirt/libvirt-sock (in UNIX abstract namespace)\n\
\n\
TLS:\n\
- CA certificate: %s\n\
- Server certificate: %s\n\
- Server private key: %s\n\
+ CA certificate: $HOME/.pki/libvirt/cacert.pem\n\
+ Server certificate: $HOME/.pki/libvirt/servercert.pem\n\
+ Server private key: $HOME/.pki/libvirt/serverkey.pem\n\
\n\
- PID file (unless overridden by --pid-file):\n\
- %s\n\
-\n"),
- argv0,
- SYSCONFDIR,
- LOCALSTATEDIR,
- LOCALSTATEDIR,
- LIBVIRT_CACERT,
- LIBVIRT_SERVERCERT,
- LIBVIRT_SERVERKEY,
- (REMOTE_PID_FILE[0] != '\0'
- ? REMOTE_PID_FILE
- : _("(disabled in ./configure)")));
+ PID file:\n\
+ $HOME/.libvirt/libvirtd.pid\n\
+\n"));
+ }
}
enum {
#define MAX_LISTEN 5
int main(int argc, char **argv) {
- struct qemud_server *server = NULL;
- const char *pid_file = NULL;
- const char *remote_config_file = NULL;
+ virNetServerPtr srv = NULL;
+ char *remote_config_file = NULL;
int statuswrite = -1;
int ret = 1;
- argv0 = argv[0];
+ char *pid_file = NULL;
+ char *sock_file = NULL;
+ char *sock_file_ro = NULL;
+ int timeout = -1; /* -t: Shutdown timeout */
+ int verbose = 0;
+ int godaemon = 0;
+ int ipsock = 0;
+ struct daemonConfig *config;
+ bool privileged = geteuid() == 0 ? true : false;
struct option opts[] = {
{ "verbose", no_argument, &verbose, 1},
bindtextdomain (PACKAGE, LOCALEDIR) == NULL ||
textdomain(PACKAGE) == NULL ||
virInitialize() < 0) {
- fprintf(stderr, _("%s: initialization failed\n"), argv0);
+ fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
exit(EXIT_FAILURE);
}
break;
case 'p':
- pid_file = optarg;
+ VIR_FREE(pid_file);
+ if (!(pid_file = strdup(optarg)))
+ exit(EXIT_FAILURE);
break;
case 'f':
- remote_config_file = optarg;
+ VIR_FREE(remote_config_file);
+ if (!(remote_config_file = strdup(optarg)))
+ exit(EXIT_FAILURE);
break;
case OPT_VERSION:
- version ();
+ daemonVersion(argv[0]);
return 0;
case '?':
- usage ();
+ daemonUsage(argv[0], privileged);
return 2;
default:
fprintf (stderr, _("%s: internal error: unknown flag: %c\n"),
- argv0, c);
+ argv[0], c);
exit (EXIT_FAILURE);
}
}
- if (remote_config_file == NULL) {
- static const char *default_config_file
- = SYSCONFDIR "/libvirt/libvirtd.conf";
- remote_config_file =
- (access(default_config_file, R_OK) == 0
- ? default_config_file
- : "/dev/null");
+ if (!(config = daemonConfigNew(privileged)))
+ exit(EXIT_FAILURE);
+
+ /* No explicit config, so try and find a default one */
+ if (remote_config_file == NULL &&
+ daemonConfigFilePath(privileged,
+ &remote_config_file) < 0)
+ exit(EXIT_FAILURE);
+
+ /* Read the config file if it exists*/
+ if (remote_config_file &&
+ daemonConfigLoad(config, remote_config_file) < 0)
+ exit(EXIT_FAILURE);
+
+ if (config->host_uuid &&
+ virSetHostUUIDStr(config->host_uuid) < 0) {
+ VIR_ERROR(_("invalid host UUID: %s"), config->host_uuid);
+ exit(EXIT_FAILURE);
}
+ if (daemonSetupLogging(config, privileged, verbose, godaemon) < 0)
+ exit(EXIT_FAILURE);
+
+ if (!pid_file && privileged &&
+ daemonPidFilePath(privileged,
+ &pid_file) < 0)
+ exit(EXIT_FAILURE);
+
+ if (daemonUnixSocketPaths(config,
+ privileged,
+ &sock_file,
+ &sock_file_ro) < 0)
+ exit(EXIT_FAILURE);
+
if (godaemon) {
char ebuf[1024];
if (chdir("/") < 0) {
VIR_ERROR(_("cannot change to root directory: %s"),
virStrerror(errno, ebuf, sizeof(ebuf)));
- goto error;
+ goto cleanup;
}
- if ((statuswrite = daemonForkIntoBackground()) < 0) {
+ if ((statuswrite = daemonForkIntoBackground(argv[0])) < 0) {
VIR_ERROR(_("Failed to fork as daemon: %s"),
virStrerror(errno, ebuf, sizeof ebuf));
- goto error;
+ goto cleanup;
}
}
- /* If running as root and no PID file is set, use the default */
- if (pid_file == NULL &&
- geteuid() == 0 &&
- REMOTE_PID_FILE[0] != '\0')
- pid_file = REMOTE_PID_FILE;
-
/* If we have a pidfile set, claim it now, exiting if already taken */
if (pid_file != NULL &&
- qemudWritePidFile (pid_file) < 0) {
- pid_file = NULL; /* Prevent unlinking of someone else's pid ! */
+ daemonWritePidFile(pid_file, argv[0]) < 0) {
+ VIR_FREE(pid_file); /* Prevent unlinking of someone else's pid ! */
ret = VIR_DAEMON_ERR_PIDFILE;
- goto error;
+ goto cleanup;
}
/* Ensure the rundir exists (on tmpfs on some systems) */
- if (geteuid() == 0) {
+ if (privileged) {
const char *rundir = LOCALSTATEDIR "/run/libvirt";
mode_t old_umask;
virStrerror(errno, ebuf, sizeof(ebuf)));
ret = VIR_DAEMON_ERR_RUNDIR;
umask(old_umask);
- goto error;
+ goto cleanup;
}
}
umask(old_umask);
}
+ if (!(srv = virNetServerNew(config->min_workers,
+ config->max_workers,
+ config->max_clients,
+ config->mdns_adv ? config->mdns_name : NULL,
+ remoteClientInitHook))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+
/* Beyond this point, nothing should rely on using
* getuid/geteuid() == 0, for privilege level checks.
- * It must all use the flag 'server->privileged'
- * which is also passed into all libvirt stateful
- * drivers
*/
- if (qemudSetupPrivs() < 0) {
+ if (daemonSetupPrivs() < 0) {
ret = VIR_DAEMON_ERR_PRIVS;
- goto error;
+ goto cleanup;
}
- /* Initialise GnuTLS. Required even if we don't use TLS
- * for libvirtd, because QEMU driver needs to be able to
- * parse x590 certificates for seamless migration */
- gnutls_global_init();
+ daemonInitialize();
- if (!(server = qemudInitialize())) {
+ remoteProcs[REMOTE_PROC_AUTH_LIST].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_SASL_INIT].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_SASL_STEP].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_SASL_START].needAuth = false;
+ remoteProcs[REMOTE_PROC_AUTH_POLKIT].needAuth = false;
+ if (!(remoteProgram = virNetServerProgramNew(REMOTE_PROGRAM,
+ REMOTE_PROTOCOL_VERSION,
+ remoteProcs,
+ remoteNProcs))) {
ret = VIR_DAEMON_ERR_INIT;
- goto error;
+ goto cleanup;
+ }
+ if (virNetServerAddProgram(srv, remoteProgram) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
}
- if ((daemonSetupSignals(server)) < 0) {
- ret = VIR_DAEMON_ERR_SIGNAL;
- goto error;
+ if (!(qemuProgram = virNetServerProgramNew(QEMU_PROGRAM,
+ QEMU_PROTOCOL_VERSION,
+ qemuProcs,
+ qemuNProcs))) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
+ }
+ if (virNetServerAddProgram(srv, qemuProgram) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
}
- /* Read the config file (if it exists). */
- if (remoteReadConfigFile (server, remote_config_file) < 0) {
- ret = VIR_DAEMON_ERR_CONFIG;
- goto error;
+ if (timeout != -1)
+ virNetServerAutoShutdown(srv,
+ timeout,
+ daemonShutdownCheck,
+ NULL);
+
+ if ((daemonSetupSignals(srv)) < 0) {
+ ret = VIR_DAEMON_ERR_SIGNAL;
+ goto cleanup;
}
- if (audit_level) {
+ if (config->audit_level) {
if (virAuditOpen() < 0) {
- if (audit_level > 1) {
+ if (config->audit_level > 1) {
ret = VIR_DAEMON_ERR_AUDIT;
- goto error;
+ goto cleanup;
}
}
}
- virAuditLog(audit_logging);
+ virAuditLog(config->audit_logging);
/* setup the hooks if any */
if (virHookInitialize() < 0) {
ret = VIR_DAEMON_ERR_HOOKS;
- goto error;
+ goto cleanup;
}
/* Disable error func, now logging is setup */
- virSetErrorFunc(NULL, virshErrorHandler);
+ virSetErrorFunc(NULL, daemonErrorHandler);
virSetErrorLogPriorityFunc(daemonErrorLogFilter);
/*
virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_START,
0, "start", NULL);
- if (qemudNetworkInit(server) < 0) {
+ if (daemonSetupNetworking(srv, config,
+ sock_file, sock_file_ro,
+ ipsock, privileged) < 0) {
ret = VIR_DAEMON_ERR_NETWORK;
- goto error;
+ goto cleanup;
}
/* Tell parent of daemon that basic initialization is complete
VIR_FORCE_CLOSE(statuswrite);
}
- /* Start the event loop in a background thread, since
- * state initialization needs events to be being processed */
- if (qemudStartEventLoop(server) < 0) {
- VIR_ERROR(_("Event thread startup failed"));
- goto error;
- }
-
- /* Start the stateful HV drivers
- * This is delibrately 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(server->privileged) < 0) {
- VIR_ERROR(_("Driver state initialization failed"));
- goto shutdown;
+ /* Initialize drivers & then start accepting new clients from network */
+ if (daemonStateInit(srv) < 0) {
+ ret = VIR_DAEMON_ERR_INIT;
+ goto cleanup;
}
- /* Start accepting new clients from network */
- virMutexLock(&server->lock);
- if (qemudNetworkEnable(server) < 0) {
- VIR_ERROR(_("Network event loop enablement failed"));
- goto shutdown;
- }
- virMutexUnlock(&server->lock);
+ /* Run event loop. */
+ virNetServerRun(srv);
ret = 0;
-shutdown:
- /* In a non-0 shutdown scenario we need to tell event loop
- * to quit immediately. Otherwise in normal case we just
- * sit in the thread join forever. Sure this means the
- * main thread doesn't do anything useful ever, but that's
- * not too much of drain on resources
- */
- if (ret != 0) {
- virMutexLock(&server->lock);
- if (server->hasEventThread)
- /* This SIGQUIT triggers the shutdown process */
- kill(getpid(), SIGQUIT);
- virMutexUnlock(&server->lock);
- }
- pthread_join(server->eventThread, NULL);
-
virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", VIR_HOOK_DAEMON_OP_SHUTDOWN,
0, "shutdown", NULL);
-error:
+cleanup:
+ virNetServerProgramFree(remoteProgram);
+ virNetServerProgramFree(qemuProgram);
+ virNetServerFree(srv);
if (statuswrite != -1) {
if (ret != 0) {
/* Tell parent of daemon what failed */
}
VIR_FORCE_CLOSE(statuswrite);
}
- if (server)
- qemudCleanup(server);
if (pid_file)
unlink (pid_file);
- qemudStopLogging();
+
+ VIR_FREE(sock_file);
+ VIR_FREE(sock_file_ro);
+ VIR_FREE(pid_file);
+ VIR_FREE(remote_config_file);
+ daemonConfigFree(config);
+ virLogShutdown();
+
return ret;
}
# include <config.h>
-# include <gnutls/gnutls.h>
-# include <gnutls/x509.h>
-# include "gnutls_1_0_compat.h"
-# if HAVE_SASL
-# include <sasl/sasl.h>
-# endif
-
# if HAVE_POLKIT0
# include <dbus/dbus.h>
# endif
# include "logging.h"
# include "threads.h"
# include "network.h"
+# include "virnetsaslcontext.h"
+# include "virnetserverprogram.h"
# if WITH_DTRACE
# ifndef LIBVIRTD_PROBES_H
#NAME ": " FMT, __VA_ARGS__);
# endif
-# ifdef __GNUC__
-# ifdef HAVE_ANSIDECL_H
-# include <ansidecl.h>
-# endif
-
-# ifndef __GNUC_PREREQ
-# if defined __GNUC__ && defined __GNUC_MINOR__
-# define __GNUC_PREREQ(maj, min) \
- ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
-# else
-# define __GNUC_PREREQ(maj,min) 0
-# endif
-# endif
-
-/**
- * ATTRIBUTE_UNUSED:
- *
- * Macro to flag conciously unused parameters to functions
- */
-# ifndef ATTRIBUTE_UNUSED
-# define ATTRIBUTE_UNUSED __attribute__((__unused__))
-# endif
-
-/**
- * ATTRIBUTE_FMT_PRINTF
- *
- * Macro used to check printf like functions, if compiling
- * with gcc.
- *
- * We use gnulib which guarentees we always have GNU style
- * printf format specifiers even on broken Win32 platforms
- * hence we have to force 'gnu_printf' for new GCC
- */
-# ifndef ATTRIBUTE_FMT_PRINTF
-# if __GNUC_PREREQ (4, 4)
-# define ATTRIBUTE_FMT_PRINTF(fmtpos,argpos) __attribute__((__format__ (gnu_printf, fmtpos,argpos)))
-# else
-# define ATTRIBUTE_FMT_PRINTF(fmtpos,argpos) __attribute__((__format__ (printf, fmtpos,argpos)))
-# endif
-# endif
-
-# ifndef ATTRIBUTE_RETURN_CHECK
-# if __GNUC_PREREQ (3, 4)
-# define ATTRIBUTE_RETURN_CHECK __attribute__((__warn_unused_result__))
-# else
-# define ATTRIBUTE_RETURN_CHECK
-# endif
-# endif
-
-# else
-# ifndef ATTRIBUTE_UNUSED
-# define ATTRIBUTE_UNUSED
-# endif
-# ifndef ATTRIBUTE_FMT_PRINTF
-# define ATTRIBUTE_FMT_PRINTF(...)
-# endif
-# ifndef ATTRIBUTE_RETURN_CHECK
-# define ATTRIBUTE_RETURN_CHECK
-# endif
-# endif
-
-/* Whether we're passing reads & writes through a sasl SSF */
-enum qemud_sasl_ssf {
- QEMUD_SASL_SSF_NONE = 0,
- QEMUD_SASL_SSF_READ = 1,
- QEMUD_SASL_SSF_WRITE = 2,
-};
-
-enum qemud_sock_type {
- QEMUD_SOCK_TYPE_UNIX = 0,
- QEMUD_SOCK_TYPE_TCP = 1,
- QEMUD_SOCK_TYPE_TLS = 2,
-};
-
-struct qemud_client_message {
- char buffer [REMOTE_MESSAGE_MAX + REMOTE_MESSAGE_HEADER_XDR_LEN];
- unsigned int bufferLength;
- unsigned int bufferOffset;
-
- unsigned int async : 1;
- unsigned int streamTX : 1;
-
- remote_message_header hdr;
-
- struct qemud_client_message *next;
-};
-
-struct qemud_client;
-
-/* Allow for filtering of incoming messages to a custom
- * dispatch processing queue, instead of client->dx.
- */
-typedef int (*qemud_client_filter_func)(struct qemud_client *client,
- struct qemud_client_message *msg, void *opaque);
-struct qemud_client_filter {
- qemud_client_filter_func query;
- void *opaque;
-
- struct qemud_client_filter *next;
-};
-
-struct qemud_client_stream {
- virStreamPtr st;
- int procedure;
- int serial;
-
- unsigned int recvEOF : 1;
- unsigned int closed : 1;
-
- struct qemud_client_filter filter;
-
- struct qemud_client_message *rx;
- int tx;
-
- struct qemud_client_stream *next;
-};
+typedef struct daemonClientStream daemonClientStream;
+typedef daemonClientStream *daemonClientStreamPtr;
+typedef struct daemonClientPrivate daemonClientPrivate;
+typedef daemonClientPrivate *daemonClientPrivatePtr;
/* Stores the per-client connection state */
-struct qemud_client {
+struct daemonClientPrivate {
+ /* Hold while accessing any data except conn */
virMutex lock;
- int magic;
-
- int fd;
- int watch;
- unsigned int readonly :1;
- unsigned int closing :1;
int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST];
- virSocketAddr addr;
- const char *addrstr;
-
- int type; /* qemud_sock_type */
- gnutls_session_t tlssession;
- int auth;
- unsigned int handshake :1; /* If we're in progress for TLS handshake */
-# if HAVE_SASL
- sasl_conn_t *saslconn;
- int saslSSF;
- const char *saslDecoded;
- unsigned int saslDecodedLength;
- unsigned int saslDecodedOffset;
- const char *saslEncoded;
- unsigned int saslEncodedLength;
- unsigned int saslEncodedOffset;
- char *saslUsername;
- char saslTemporary[8192]; /* temorary holds data to be decoded */
-# endif
-
- /* Count of meages in 'dx' or 'tx' queue
- * ie RPC calls in progress. Does not count
- * async events which are not used for
- * throttling calculations */
- int nrequests;
- /* Zero or one messages being received. Zero if
- * nrequests >= max_clients and throttling */
- struct qemud_client_message *rx;
- /* Zero or many messages waiting for a worker
- * to process them */
- struct qemud_client_message *dx;
- /* Zero or many messages waiting for transmit
- * back to client, including async events */
- struct qemud_client_message *tx;
- /* Filters to capture messages that would otherwise
- * end up on the 'dx' queue */
- struct qemud_client_filter *filters;
-
- /* Data streams */
- struct qemud_client_stream *streams;
-
+ virNetSASLSessionPtr sasl;
/* This is only valid if a remote open call has been made on this
* connection, otherwise it will be NULL. Also if remote close is
* called, it will be set back to NULL if that succeeds.
*/
virConnectPtr conn;
- int refs;
-
-};
-
-# define QEMUD_CLIENT_MAGIC 0x7788aaee
-
-struct qemud_socket {
- char *path;
-
- virSocketAddr addr;
- const char *addrstr;
-
- int fd;
- int watch;
- int readonly;
- int type; /* qemud_sock_type */
- int auth;
-
- struct qemud_socket *next;
+ daemonClientStreamPtr streams;
};
-struct qemud_worker {
- pthread_t thread;
- unsigned int hasThread :1;
- unsigned int processingCall :1;
- unsigned int quitRequest :1;
-
- /* back-pointer to our server */
- struct qemud_server *server;
-};
+extern virNetSASLContextPtr saslCtxt;
+extern virNetServerProgramPtr remoteProgram;
+extern virNetServerProgramPtr qemuProgram;
/* Main server state */
struct qemud_server {
- virMutex lock;
- virCond job;
-
int privileged;
- size_t nworkers;
- size_t nactiveworkers;
- struct qemud_worker *workers;
- size_t nsockets;
- struct qemud_socket *sockets;
- size_t nclients;
- size_t nclients_max;
- struct qemud_client **clients;
-
int sigread;
int sigwrite;
char *logDir;
# endif
};
-void qemudLog(int priority, const char *fmt, ...)
- ATTRIBUTE_FMT_PRINTF(2,3);
-
-
-
-int qemudRegisterClientEvent(struct qemud_server *server,
- struct qemud_client *client);
-void qemudUpdateClientEvent(struct qemud_client *client);
-
-void qemudDispatchClientFailure(struct qemud_client *client);
-
-void
-qemudClientMessageQueuePush(struct qemud_client_message **queue,
- struct qemud_client_message *msg);
-struct qemud_client_message *
-qemudClientMessageQueueServe(struct qemud_client_message **queue);
-
-void
-qemudClientMessageRelease(struct qemud_client *client,
- struct qemud_client_message *msg);
-
# if HAVE_POLKIT
int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid);
#include <config.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/poll.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-#include <string.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <arpa/inet.h>
#include "virterror_internal.h"
#if HAVE_POLKIT0
#endif
#include "remote.h"
-#include "dispatch.h"
-
+#include "libvirtd.h"
#include "libvirt_internal.h"
#include "datatypes.h"
#include "memory.h"
+#include "logging.h"
#include "util.h"
#include "stream.h"
#include "uuid.h"
#include "libvirt/libvirt-qemu.h"
#include "command.h"
#include "intprops.h"
+#include "virnetserverservice.h"
+
+#include "remote_protocol.h"
+#include "qemu_protocol.h"
-#define VIR_FROM_THIS VIR_FROM_REMOTE
+
+#define VIR_FROM_THIS VIR_FROM_RPC
#define virNetError(code, ...) \
virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);
static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
+static int
+remoteSerializeTypedParameters(virTypedParameterPtr params,
+ int nparams,
+ remote_typed_param **ret_params_val,
+ u_int *ret_params_len);
+static virTypedParameterPtr
+remoteDeserializeTypedParameters(remote_typed_param *args_params_val,
+ u_int args_params_len,
+ int limit,
+ int *nparams);
-#include "remote_dispatch_prototypes.h"
-#include "qemu_dispatch_prototypes.h"
-
-static const dispatch_data const dispatch_table[] = {
-#include "remote_dispatch_table.h"
-};
-
-static const dispatch_data const qemu_dispatch_table[] = {
-#include "qemu_dispatch_table.h"
-};
-
-const dispatch_data const *remoteGetDispatchData(int proc)
-{
- if (proc >= ARRAY_CARDINALITY(dispatch_table) ||
- dispatch_table[proc].fn == NULL) {
- return NULL;
- }
-
- return &(dispatch_table[proc]);
-}
-
-const dispatch_data const *qemuGetDispatchData(int proc)
-{
- if (proc >= ARRAY_CARDINALITY(qemu_dispatch_table) ||
- qemu_dispatch_table[proc].fn == NULL) {
- return NULL;
- }
+#include "remote_dispatch.h"
+#include "qemu_dispatch.h"
- return &(qemu_dispatch_table[proc]);
-}
/* Prototypes */
static void
-remoteDispatchDomainEventSend(struct qemud_client *client,
+remoteDispatchDomainEventSend(virNetServerClientPtr client,
+ virNetServerProgramPtr program,
int procnr,
xdrproc_t proc,
void *data);
int detail,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_lifecycle_msg data;
if (!client)
VIR_DEBUG("Relaying domain lifecycle event %d %d", event, detail);
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
data.event = event;
data.detail = detail;
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
(xdrproc_t)xdr_remote_domain_event_lifecycle_msg, &data);
- virMutexUnlock(&client->lock);
-
return 0;
}
virDomainPtr dom,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_reboot_msg data;
if (!client)
VIR_DEBUG("Relaying domain reboot event %s %d", dom->name, dom->id);
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_REBOOT,
(xdrproc_t)xdr_remote_domain_event_reboot_msg, &data);
- virMutexUnlock(&client->lock);
-
return 0;
}
long long offset,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_rtc_change_msg data;
if (!client)
VIR_DEBUG("Relaying domain rtc change event %s %d %lld", dom->name, dom->id, offset);
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
data.offset = offset;
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
(xdrproc_t)xdr_remote_domain_event_rtc_change_msg, &data);
- virMutexUnlock(&client->lock);
-
return 0;
}
int action,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_watchdog_msg data;
if (!client)
VIR_DEBUG("Relaying domain watchdog event %s %d %d", dom->name, dom->id, action);
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
data.action = action;
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
(xdrproc_t)xdr_remote_domain_event_watchdog_msg, &data);
- virMutexUnlock(&client->lock);
-
return 0;
}
int action,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_io_error_msg data;
if (!client)
VIR_DEBUG("Relaying domain io error %s %d %s %s %d", dom->name, dom->id, srcPath, devAlias, action);
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
data.devAlias = (char*)devAlias;
data.action = action;
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
(xdrproc_t)xdr_remote_domain_event_io_error_msg, &data);
- virMutexUnlock(&client->lock);
-
return 0;
}
const char *reason,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_io_error_reason_msg data;
if (!client)
VIR_DEBUG("Relaying domain io error %s %d %s %s %d %s",
dom->name, dom->id, srcPath, devAlias, action, reason);
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
data.action = action;
data.reason = (char*)reason;
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
(xdrproc_t)xdr_remote_domain_event_io_error_reason_msg, &data);
- virMutexUnlock(&client->lock);
-
return 0;
}
virDomainEventGraphicsSubjectPtr subject,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_graphics_msg data;
int i;
VIR_DEBUG(" %s=%s", subject->identities[i].type, subject->identities[i].name);
}
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
data.subject.subject_len = subject->nidentity;
if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0) {
- VIR_WARN("cannot allocate memory for graphics event subject");
+ virReportOOMError();
return -1;
}
for (i = 0 ; i < data.subject.subject_len ; i++) {
data.subject.subject_val[i].name = (char*)subject->identities[i].name;
}
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
(xdrproc_t)xdr_remote_domain_event_graphics_msg, &data);
VIR_FREE(data.subject.subject_val);
- virMutexUnlock(&client->lock);
-
return 0;
}
virDomainPtr dom,
void *opaque)
{
- struct qemud_client *client = opaque;
+ virNetServerClientPtr client = opaque;
remote_domain_event_control_error_msg data;
if (!client)
VIR_DEBUG("Relaying domain control error %s %d", dom->name, dom->id);
- virMutexLock(&client->lock);
-
/* build return data */
memset(&data, 0, sizeof data);
make_nonnull_domain(&data.dom, dom);
- remoteDispatchDomainEventSend(client,
+ remoteDispatchDomainEventSend(client, remoteProgram,
REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR,
(xdrproc_t)xdr_remote_domain_event_control_error_msg, &data);
- virMutexUnlock(&client->lock);
-
return 0;
}
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
+/*
+ * You must hold lock for at least the client
+ * We don't free stuff here, merely disconnect the client's
+ * network socket & resources.
+ * We keep the libvirt connection open until any async
+ * jobs have finished, then clean it up elsewhere
+ */
+static void remoteClientFreeFunc(void *data)
+{
+ struct daemonClientPrivate *priv = data;
+
+ /* Deregister event delivery callback */
+ if (priv->conn) {
+ int i;
+
+ for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) {
+ if (priv->domainEventCallbackID[i] != -1) {
+ VIR_DEBUG("Deregistering to relay remote events %d", i);
+ virConnectDomainEventDeregisterAny(priv->conn,
+ priv->domainEventCallbackID[i]);
+ }
+ priv->domainEventCallbackID[i] = -1;
+ }
+
+ virConnectClose(priv->conn);
+ }
+
+ VIR_FREE(priv);
+}
+
+
+
+int remoteClientInitHook(virNetServerPtr srv ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client)
+{
+ struct daemonClientPrivate *priv;
+ int i;
+
+ if (VIR_ALLOC(priv) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (virMutexInit(&priv->lock) < 0) {
+ VIR_FREE(priv);
+ virReportOOMError();
+ return -1;
+ }
+
+ for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++)
+ priv->domainEventCallbackID[i] = -1;
+
+ virNetServerClientSetPrivateData(client, priv, remoteClientFreeFunc);
+ return 0;
+}
+
/*----- Functions. -----*/
static int
-remoteDispatchOpen(struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- struct remote_open_args *args, void *ret ATTRIBUTE_UNUSED)
+remoteDispatchOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ struct remote_open_args *args)
{
const char *name;
int flags;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
int rv = -1;
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
-
- if (conn) {
+ VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
+ virMutexLock(&priv->lock);
+ /* Already opened? */
+ if (priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection already open"));
goto cleanup;
}
* the connection to be readonly.
*/
flags = args->flags;
- if (client->readonly) flags |= VIR_CONNECT_RO;
+ if (virNetServerClientGetReadonly(client))
+ flags |= VIR_CONNECT_RO;
- client->conn =
+ priv->conn =
flags & VIR_CONNECT_RO
? virConnectOpenReadOnly(name)
: virConnectOpen(name);
- if (client->conn == NULL)
+ if (priv->conn == NULL)
goto cleanup;
rv = 0;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
- virMutexUnlock(&client->lock);
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
return rv;
}
static int
-remoteDispatchClose(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr ATTRIBUTE_UNUSED,
- void *args ATTRIBUTE_UNUSED, void *ret ATTRIBUTE_UNUSED)
+remoteDispatchClose(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED)
{
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
-
- client->closing = 1;
-
- virMutexUnlock(&client->lock);
+ virNetServerClientClose(client);
return 0;
}
+
static int
-remoteDispatchDomainGetSchedulerType(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_get_scheduler_type_args *args,
remote_domain_get_scheduler_type_ret *ret)
{
char *type;
int nparams;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (!(type = virDomainGetSchedulerType(dom, &nparams)))
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
return rv;
}
static int
-remoteDispatchDomainGetSchedulerParameters(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_get_scheduler_parameters_args *args,
remote_domain_get_scheduler_parameters_ret *ret)
{
virTypedParameterPtr params = NULL;
int nparams = args->nparams;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
if (VIR_ALLOC_N(params, nparams) < 0)
goto no_memory;
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (virDomainGetSchedulerParameters(dom, params, &nparams) < 0)
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
VIR_FREE(params);
}
static int
-remoteDispatchDomainGetSchedulerParametersFlags(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_get_scheduler_parameters_flags_args *args,
remote_domain_get_scheduler_parameters_flags_ret *ret)
{
virTypedParameterPtr params = NULL;
int nparams = args->nparams;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
if (VIR_ALLOC_N(params, nparams) < 0)
goto no_memory;
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (virDomainGetSchedulerParametersFlags(dom, params, &nparams,
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
VIR_FREE(params);
}
static int
-remoteDispatchDomainMemoryStats(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_memory_stats_args *args,
remote_domain_memory_stats_ret *ret)
{
struct _virDomainMemoryStat *stats;
int nr_stats, i;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
/* Allocate stats array for making dispatch call */
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
VIR_FREE(stats);
}
static int
-remoteDispatchDomainBlockPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainBlockPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_block_peek_args *args,
remote_domain_block_peek_ret *ret)
{
size_t size;
unsigned int flags;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
path = args->path;
offset = args->offset;
cleanup:
if (rv < 0) {
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(ret->buffer.buffer_val);
}
if (dom)
}
static int
-remoteDispatchDomainMemoryPeek(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMemoryPeek(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_memory_peek_args *args,
remote_domain_memory_peek_ret *ret)
{
size_t size;
unsigned int flags;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
offset = args->offset;
size = args->size;
cleanup:
if (rv < 0) {
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(ret->buffer.buffer_val);
}
if (dom)
}
static int
-remoteDispatchDomainGetSecurityLabel(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainGetSecurityLabel(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_get_security_label_args *args,
remote_domain_get_security_label_ret *ret)
{
virDomainPtr dom = NULL;
virSecurityLabelPtr seclabel = NULL;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (VIR_ALLOC(seclabel) < 0) {
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
VIR_FREE(seclabel);
}
static int
-remoteDispatchNodeGetSecurityModel(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchNodeGetSecurityModel(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_node_get_security_model_ret *ret)
{
virSecurityModel secmodel;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
memset(&secmodel, 0, sizeof secmodel);
- if (virNodeGetSecurityModel(conn, &secmodel) < 0)
+ if (virNodeGetSecurityModel(priv->conn, &secmodel) < 0)
goto cleanup;
ret->model.model_len = strlen(secmodel.model) + 1;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
return rv;
}
static int
-remoteDispatchDomainGetVcpuPinInfo(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_get_vcpu_pin_info_args *args,
remote_domain_get_vcpu_pin_info_ret *ret)
{
unsigned char *cpumaps = NULL;
int num;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(cpumaps);
if (dom)
virDomainFree(dom);
}
static int
-remoteDispatchDomainGetVcpus(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_get_vcpus_args *args,
remote_domain_get_vcpus_ret *ret)
{
unsigned char *cpumaps = NULL;
int info_len, i;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
cleanup:
if (rv < 0) {
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(ret->info.info_val);
}
VIR_FREE(cpumaps);
}
static int
-remoteDispatchDomainMigratePrepare(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_migrate_prepare_args *args,
remote_domain_migrate_prepare_ret *ret)
{
char **uri_out;
char *dname;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (virDomainMigratePrepare(conn, &cookie, &cookielen,
+ if (virDomainMigratePrepare(priv->conn, &cookie, &cookielen,
uri_in, uri_out,
args->flags, dname, args->resource) < 0)
goto cleanup;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(uri_out);
return rv;
}
static int
-remoteDispatchDomainMigratePrepare2(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMigratePrepare2(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_migrate_prepare2_args *args,
remote_domain_migrate_prepare2_ret *ret)
{
char **uri_out;
char *dname;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (virDomainMigratePrepare2(conn, &cookie, &cookielen,
+ if (virDomainMigratePrepare2(priv->conn, &cookie, &cookielen,
uri_in, uri_out,
args->flags, dname, args->resource,
args->dom_xml) < 0)
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
return rv;
}
static int
-remoteDispatchDomainGetMemoryParameters(struct qemud_server *server
- ATTRIBUTE_UNUSED,
- struct qemud_client *client
- ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *
- hdr ATTRIBUTE_UNUSED,
- remote_error * rerr,
- remote_domain_get_memory_parameters_args
- * args,
- remote_domain_get_memory_parameters_ret
- * ret)
+remoteDispatchDomainGetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_memory_parameters_args *args,
+ remote_domain_get_memory_parameters_ret *ret)
{
virDomainPtr dom = NULL;
virTypedParameterPtr params = NULL;
int nparams = args->nparams;
unsigned int flags;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (virDomainGetMemoryParameters(dom, params, &nparams, flags) < 0)
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
VIR_FREE(params);
}
static int
-remoteDispatchDomainGetBlkioParameters(struct qemud_server *server
- ATTRIBUTE_UNUSED,
- struct qemud_client *client
- ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *
- hdr ATTRIBUTE_UNUSED,
- remote_error * rerr,
- remote_domain_get_blkio_parameters_args
- * args,
- remote_domain_get_blkio_parameters_ret
- * ret)
+remoteDispatchDomainGetBlkioParameters(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_blkio_parameters_args *args,
+ remote_domain_get_blkio_parameters_ret *ret)
{
virDomainPtr dom = NULL;
virTypedParameterPtr params = NULL;
int nparams = args->nparams;
unsigned int flags;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (virDomainGetBlkioParameters(dom, params, &nparams, flags) < 0)
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(params);
if (dom)
virDomainFree(dom);
}
static int
-remoteDispatchNodeGetCPUStats (struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- remote_node_get_cpu_stats_args *args,
- remote_node_get_cpu_stats_ret *ret)
+remoteDispatchNodeGetCPUStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_cpu_stats_args *args,
+ remote_node_get_cpu_stats_ret *ret)
{
virNodeCPUStatsPtr params = NULL;
int i;
int nparams = args->nparams;
unsigned int flags;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (virNodeGetCPUStats(conn, cpuNum, params, &nparams, flags) < 0)
+ if (virNodeGetCPUStats(priv->conn, cpuNum, params, &nparams, flags) < 0)
goto cleanup;
/* In this case, we need to send back the number of stats
cleanup:
if (rv < 0) {
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (ret->params.params_val) {
for (i = 0; i < nparams; i++)
VIR_FREE(ret->params.params_val[i].field);
}
static int
-remoteDispatchNodeGetMemoryStats (struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- remote_node_get_memory_stats_args *args,
- remote_node_get_memory_stats_ret *ret)
+remoteDispatchNodeGetMemoryStats(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_node_get_memory_stats_args *args,
+ remote_node_get_memory_stats_ret *ret)
{
virNodeMemoryStatsPtr params = NULL;
int i;
int nparams = args->nparams;
unsigned int flags;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (virNodeGetMemoryStats(conn, cellNum, params, &nparams, flags) < 0)
+ if (virNodeGetMemoryStats(priv->conn, cellNum, params, &nparams, flags) < 0)
goto cleanup;
/* In this case, we need to send back the number of parameters
cleanup:
if (rv < 0) {
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (ret->params.params_val) {
for (i = 0; i < nparams; i++)
VIR_FREE(ret->params.params_val[i].field);
/*-------------------------------------------------------------*/
static int
-remoteDispatchAuthList(struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthList(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_auth_list_ret *ret)
{
int rv = -1;
+ int auth = virNetServerClientGetAuth(client);
+ uid_t callerUid;
+ pid_t callerPid;
+
+ /* If the client is root then we want to bypass the
+ * policykit auth to avoid root being denied if
+ * some piece of polkit isn't present/running
+ */
+ if (auth == VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
+ if (virNetServerClientGetLocalIdentity(client, &callerUid, &callerPid) < 0) {
+ /* Don't do anything on error - it'll be validated at next
+ * phase of auth anyway */
+ virResetLastError();
+ } else if (callerUid == 0) {
+ char ident[100];
+ rv = snprintf(ident, sizeof ident, "pid:%d,uid:%d", callerPid, callerUid);
+ if (rv > 0 || rv < sizeof ident) {
+ VIR_INFO("Bypass polkit auth for privileged client %s",
+ ident);
+ if (virNetServerClientSetIdentity(client, ident) < 0)
+ virResetLastError();
+ else
+ auth = VIR_NET_SERVER_SERVICE_AUTH_NONE;
+ }
+ rv = -1;
+ }
+ }
ret->types.types_len = 1;
if (VIR_ALLOC_N(ret->types.types_val, ret->types.types_len) < 0) {
virReportOOMError();
goto cleanup;
}
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
- ret->types.types_val[0] = client->auth;
- virMutexUnlock(&client->lock);
+
+ switch (auth) {
+ case VIR_NET_SERVER_SERVICE_AUTH_NONE:
+ ret->types.types_val[0] = REMOTE_AUTH_NONE;
+ break;
+ case VIR_NET_SERVER_SERVICE_AUTH_POLKIT:
+ ret->types.types_val[0] = REMOTE_AUTH_POLKIT;
+ break;
+ case VIR_NET_SERVER_SERVICE_AUTH_SASL:
+ ret->types.types_val[0] = REMOTE_AUTH_SASL;
+ break;
+ default:
+ ret->types.types_val[0] = REMOTE_AUTH_NONE;
+ }
rv = 0;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
return rv;
}
-#if HAVE_SASL
/*
* Initializes the SASL session in prepare for authentication
* and gives the client a list of allowed mechanisms to choose
- *
- * XXX callbacks for stuff like password verification ?
*/
static int
-remoteDispatchAuthSaslInit(struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthSaslInit(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_auth_sasl_init_ret *ret)
{
- const char *mechlist = NULL;
- sasl_security_properties_t secprops;
- int err;
- virSocketAddr sa;
- char *localAddr, *remoteAddr;
+ virNetSASLSessionPtr sasl = NULL;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
+ virMutexLock(&priv->lock);
- VIR_DEBUG("Initialize SASL auth %d", client->fd);
- if (client->auth != REMOTE_AUTH_SASL ||
- client->saslconn != NULL) {
+ VIR_DEBUG("Initialize SASL auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+ priv->sasl != NULL) {
VIR_ERROR(_("client tried invalid SASL init request"));
goto authfail;
}
- /* Get local address in form IPADDR:PORT */
- sa.len = sizeof(sa.data.stor);
- if (getsockname(client->fd, &sa.data.sa, &sa.len) < 0) {
- char ebuf[1024];
- virNetError(VIR_ERR_INTERNAL_ERROR,
- _("failed to get sock address: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- goto error;
- }
- if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
- goto error;
-
- /* Get remote address in form IPADDR:PORT */
- sa.len = sizeof(sa.data.stor);
- if (getpeername(client->fd, &sa.data.sa, &sa.len) < 0) {
- char ebuf[1024];
- virNetError(VIR_ERR_INTERNAL_ERROR, _("failed to get peer address: %s"),
- virStrerror(errno, ebuf, sizeof ebuf));
- VIR_FREE(localAddr);
- goto error;
- }
- if ((remoteAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL) {
- VIR_FREE(localAddr);
- goto error;
- }
-
- err = sasl_server_new("libvirt",
- NULL, /* FQDN - just delegates to gethostname */
- NULL, /* User realm */
- localAddr,
- remoteAddr,
- NULL, /* XXX Callbacks */
- SASL_SUCCESS_DATA,
- &client->saslconn);
- VIR_FREE(localAddr);
- VIR_FREE(remoteAddr);
- if (err != SASL_OK) {
- VIR_ERROR(_("sasl context setup failed %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
- client->saslconn = NULL;
+ sasl = virNetSASLSessionNewServer(saslCtxt,
+ "libvirt",
+ virNetServerClientLocalAddrString(client),
+ virNetServerClientRemoteAddrString(client));
+ if (!sasl)
goto authfail;
- }
/* Inform SASL that we've got an external SSF layer from TLS */
- if (client->type == QEMUD_SOCK_TYPE_TLS) {
- gnutls_cipher_algorithm_t cipher;
- sasl_ssf_t ssf;
-
- cipher = gnutls_cipher_get(client->tlssession);
- if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
- VIR_ERROR(_("cannot get TLS cipher size"));
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+ if (virNetServerClientHasTLSSession(client)) {
+ int ssf;
+
+ if ((ssf = virNetServerClientGetTLSKeySize(client)) < 0)
goto authfail;
- }
- ssf *= 8; /* tls key size is bytes, sasl wants bits */
-
- err = sasl_setprop(client->saslconn, SASL_SSF_EXTERNAL, &ssf);
- if (err != SASL_OK) {
- VIR_ERROR(_("cannot set SASL external SSF %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+
+ ssf *= 8; /* key size is bytes, sasl wants bits */
+
+ VIR_DEBUG("Setting external SSF %d", ssf);
+ if (virNetSASLSessionExtKeySize(sasl, ssf) < 0)
goto authfail;
- }
}
- memset(&secprops, 0, sizeof secprops);
- if (client->type == QEMUD_SOCK_TYPE_TLS ||
- client->type == QEMUD_SOCK_TYPE_UNIX) {
+ if (virNetServerClientIsSecure(client))
/* If we've got TLS or UNIX domain sock, we don't care about SSF */
- secprops.min_ssf = 0;
- secprops.max_ssf = 0;
- secprops.maxbufsize = 8192;
- secprops.security_flags = 0;
- } else {
+ virNetSASLSessionSecProps(sasl, 0, 0, true);
+ else
/* Plain TCP, better get an SSF layer */
- secprops.min_ssf = 56; /* Good enough to require kerberos */
- secprops.max_ssf = 100000; /* Arbitrary big number */
- secprops.maxbufsize = 8192;
- /* Forbid any anonymous or trivially crackable auth */
- secprops.security_flags =
- SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
- }
-
- err = sasl_setprop(client->saslconn, SASL_SEC_PROPS, &secprops);
- if (err != SASL_OK) {
- VIR_ERROR(_("cannot set SASL security props %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- goto authfail;
- }
+ virNetSASLSessionSecProps(sasl,
+ 56, /* Good enough to require kerberos */
+ 100000, /* Arbitrary big number */
+ false); /* No anonymous */
- err = sasl_listmech(client->saslconn,
- NULL, /* Don't need to set user */
- "", /* Prefix */
- ",", /* Separator */
- "", /* Suffix */
- &mechlist,
- NULL,
- NULL);
- if (err != SASL_OK) {
- VIR_ERROR(_("cannot list SASL mechanisms %d (%s)"),
- err, sasl_errdetail(client->saslconn));
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- goto authfail;
- }
- VIR_DEBUG("Available mechanisms for client: '%s'", mechlist);
- ret->mechlist = strdup(mechlist);
- if (!ret->mechlist) {
- VIR_ERROR(_("cannot allocate mechlist"));
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+ if (!(ret->mechlist = virNetSASLSessionListMechanisms(sasl)))
goto authfail;
- }
+ VIR_DEBUG("Available mechanisms for client: '%s'", ret->mechlist);
- virMutexUnlock(&client->lock);
+ priv->sasl = sasl;
+ virMutexUnlock(&priv->lock);
return 0;
authfail:
- remoteDispatchAuthError(rerr);
-error:
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
- virMutexUnlock(&client->lock);
+ virResetLastError();
+ virNetError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
+ PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+ virNetServerClientGetFD(client), REMOTE_AUTH_SASL);
+ virNetSASLSessionFree(sasl);
+ virMutexUnlock(&priv->lock);
return -1;
}
-
-/* We asked for an SSF layer, so sanity check that we actually
- * got what we asked for
+/*
* Returns 0 if ok, -1 on error, -2 if rejected
*/
static int
-remoteSASLCheckSSF(struct qemud_client *client,
- remote_error *rerr) {
- const void *val;
- int err, ssf;
-
- if (client->type == QEMUD_SOCK_TYPE_TLS ||
- client->type == QEMUD_SOCK_TYPE_UNIX)
- return 0; /* TLS or UNIX domain sockets trivially OK */
-
- err = sasl_getprop(client->saslconn, SASL_SSF, &val);
- if (err != SASL_OK) {
- VIR_ERROR(_("cannot query SASL ssf on connection %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
- remoteDispatchAuthError(rerr);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- return -1;
+remoteSASLFinish(virNetServerClientPtr client)
+{
+ const char *identity;
+ struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
+ int ssf;
+
+ /* TLS or UNIX domain sockets trivially OK */
+ if (!virNetServerClientIsSecure(client)) {
+ if ((ssf = virNetSASLSessionGetKeySize(priv->sasl)) < 0)
+ goto error;
+
+ VIR_DEBUG("negotiated an SSF of %d", ssf);
+ if (ssf < 56) { /* 56 is good for Kerberos */
+ VIR_ERROR(_("negotiated SSF %d was not strong enough"), ssf);
+ return -2;
+ }
}
- ssf = *(const int *)val;
- VIR_DEBUG("negotiated an SSF of %d", ssf);
- if (ssf < 56) { /* 56 is good for Kerberos */
- VIR_ERROR(_("negotiated SSF %d was not strong enough"), ssf);
- remoteDispatchAuthError(rerr);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+
+ if (!(identity = virNetSASLSessionGetIdentity(priv->sasl)))
return -2;
- }
- /* Only setup for read initially, because we're about to send an RPC
- * reply which must be in plain text. When the next incoming RPC
- * arrives, we'll switch on writes too
- *
- * cf qemudClientReadSASL in qemud.c
- */
- client->saslSSF = QEMUD_SASL_SSF_READ;
+ if (!virNetSASLContextCheckIdentity(saslCtxt, identity))
+ return -2;
- /* We have a SSF !*/
- return 0;
-}
+ if (virNetServerClientSetIdentity(client, identity) < 0)
+ goto error;
-/*
- * Returns 0 if ok, -1 on error, -2 if rejected
- */
-static int
-remoteSASLCheckAccess(struct qemud_server *server,
- struct qemud_client *client,
- remote_error *rerr) {
- const void *val;
- int err;
- char **wildcards;
-
- err = sasl_getprop(client->saslconn, SASL_USERNAME, &val);
- if (err != SASL_OK) {
- VIR_ERROR(_("cannot query SASL username on connection %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
- remoteDispatchAuthError(rerr);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- return -1;
- }
- if (val == NULL) {
- VIR_ERROR(_("no client username was found"));
- remoteDispatchAuthError(rerr);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- return -1;
- }
- VIR_DEBUG("SASL client username %s", (const char *)val);
- client->saslUsername = strdup((const char*)val);
- if (client->saslUsername == NULL) {
- VIR_ERROR(_("out of memory copying username"));
- remoteDispatchAuthError(rerr);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- return -1;
- }
+ virNetServerClientSetSASLSession(client, priv->sasl);
+
+ VIR_DEBUG("Authentication successful %d", virNetServerClientGetFD(client));
+ PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
+ virNetServerClientGetFD(client), REMOTE_AUTH_SASL,
+ virNetSASLSessionGetIdentity(priv->sasl));
- /* If the list is not set, allow any DN. */
- wildcards = server->saslUsernameWhitelist;
- if (!wildcards)
- return 0; /* No ACL, allow all */
+ virNetSASLSessionFree(priv->sasl);
+ priv->sasl = NULL;
- while (*wildcards) {
- if (fnmatch(*wildcards, client->saslUsername, 0) == 0)
- return 0; /* Allowed */
- wildcards++;
- }
+ return 0;
- /* Denied */
- VIR_ERROR(_("SASL client %s not allowed in whitelist"), client->saslUsername);
- remoteDispatchAuthError(rerr);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
- return -2;
+error:
+ return -1;
}
-
/*
* This starts the SASL authentication negotiation.
*/
static int
-remoteDispatchAuthSaslStart(struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchAuthSaslStart(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_auth_sasl_start_args *args,
remote_auth_sasl_start_ret *ret)
{
const char *serverout;
- unsigned int serveroutlen;
+ size_t serveroutlen;
int err;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
+ virMutexLock(&priv->lock);
- VIR_DEBUG("Start SASL auth %d", client->fd);
- if (client->auth != REMOTE_AUTH_SASL ||
- client->saslconn == NULL) {
+ VIR_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+ priv->sasl == NULL) {
VIR_ERROR(_("client tried invalid SASL start request"));
goto authfail;
}
VIR_DEBUG("Using SASL mechanism %s. Data %d bytes, nil: %d",
args->mech, args->data.data_len, args->nil);
- err = sasl_server_start(client->saslconn,
- args->mech,
- /* NB, distinction of NULL vs "" is *critical* in SASL */
- args->nil ? NULL : args->data.data_val,
- args->data.data_len,
- &serverout,
- &serveroutlen);
- if (err != SASL_OK &&
- err != SASL_CONTINUE) {
- VIR_ERROR(_("sasl start failed %d (%s)"),
- err, sasl_errdetail(client->saslconn));
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+ err = virNetSASLSessionServerStart(priv->sasl,
+ args->mech,
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ args->nil ? NULL : args->data.data_val,
+ args->data.data_len,
+ &serverout,
+ &serveroutlen);
+ if (err != VIR_NET_SASL_COMPLETE &&
+ err != VIR_NET_SASL_CONTINUE)
goto authfail;
- }
+
if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
- VIR_ERROR(_("sasl start reply data too long %d"), serveroutlen);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+ VIR_ERROR(_("sasl start reply data too long %d"), (int)serveroutlen);
goto authfail;
}
/* NB, distinction of NULL vs "" is *critical* in SASL */
if (serverout) {
- if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0) {
- virReportOOMError();
- remoteDispatchError(rerr);
- goto error;
- }
+ if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
+ goto authfail;
memcpy(ret->data.data_val, serverout, serveroutlen);
} else {
ret->data.data_val = NULL;
ret->data.data_len = serveroutlen;
VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
- if (err == SASL_CONTINUE) {
+ if (err == VIR_NET_SASL_CONTINUE) {
ret->complete = 0;
} else {
/* Check username whitelist ACL */
- if ((err = remoteSASLCheckAccess(server, client, rerr)) < 0 ||
- (err = remoteSASLCheckSSF(client, rerr)) < 0) {
+ if ((err = remoteSASLFinish(client)) < 0) {
if (err == -2)
goto authdeny;
else
goto authfail;
}
- VIR_DEBUG("Authentication successful %d", client->fd);
- PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_SASL, client->saslUsername);
ret->complete = 1;
- client->auth = REMOTE_AUTH_NONE;
}
- virMutexUnlock(&client->lock);
+ virMutexUnlock(&priv->lock);
return 0;
authfail:
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
- remoteDispatchAuthError(rerr);
+ PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+ virNetServerClientGetFD(client), REMOTE_AUTH_SASL);
goto error;
authdeny:
PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_SASL, client->saslUsername);
+ virNetServerClientGetFD(client), REMOTE_AUTH_SASL,
+ virNetSASLSessionGetIdentity(priv->sasl));
goto error;
error:
- virMutexUnlock(&client->lock);
+ virNetSASLSessionFree(priv->sasl);
+ priv->sasl = NULL;
+ virResetLastError();
+ virNetError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
return -1;
}
static int
-remoteDispatchAuthSaslStep(struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchAuthSaslStep(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_auth_sasl_step_args *args,
remote_auth_sasl_step_ret *ret)
{
const char *serverout;
- unsigned int serveroutlen;
+ size_t serveroutlen;
int err;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
- VIR_DEBUG("Step SASL auth %d", client->fd);
- if (client->auth != REMOTE_AUTH_SASL ||
- client->saslconn == NULL) {
+ virMutexLock(&priv->lock);
+
+ VIR_DEBUG("Step SASL auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL ||
+ priv->sasl == NULL) {
VIR_ERROR(_("client tried invalid SASL start request"));
goto authfail;
}
- VIR_DEBUG("Using SASL Data %d bytes, nil: %d",
+ VIR_DEBUG("Step using SASL Data %d bytes, nil: %d",
args->data.data_len, args->nil);
- err = sasl_server_step(client->saslconn,
- /* NB, distinction of NULL vs "" is *critical* in SASL */
- args->nil ? NULL : args->data.data_val,
- args->data.data_len,
- &serverout,
- &serveroutlen);
- if (err != SASL_OK &&
- err != SASL_CONTINUE) {
- VIR_ERROR(_("sasl step failed %d (%s)"),
- err, sasl_errdetail(client->saslconn));
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+ err = virNetSASLSessionServerStep(priv->sasl,
+ /* NB, distinction of NULL vs "" is *critical* in SASL */
+ args->nil ? NULL : args->data.data_val,
+ args->data.data_len,
+ &serverout,
+ &serveroutlen);
+ if (err != VIR_NET_SASL_COMPLETE &&
+ err != VIR_NET_SASL_CONTINUE)
goto authfail;
- }
if (serveroutlen > REMOTE_AUTH_SASL_DATA_MAX) {
VIR_ERROR(_("sasl step reply data too long %d"),
- serveroutlen);
- sasl_dispose(&client->saslconn);
- client->saslconn = NULL;
+ (int)serveroutlen);
goto authfail;
}
/* NB, distinction of NULL vs "" is *critical* in SASL */
if (serverout) {
- if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0) {
- virReportOOMError();
- remoteDispatchError(rerr);
- goto error;
- }
+ if (VIR_ALLOC_N(ret->data.data_val, serveroutlen) < 0)
+ goto authfail;
memcpy(ret->data.data_val, serverout, serveroutlen);
} else {
ret->data.data_val = NULL;
ret->data.data_len = serveroutlen;
VIR_DEBUG("SASL return data %d bytes, nil; %d", ret->data.data_len, ret->nil);
- if (err == SASL_CONTINUE) {
+ if (err == VIR_NET_SASL_CONTINUE) {
ret->complete = 0;
} else {
/* Check username whitelist ACL */
- if ((err = remoteSASLCheckAccess(server, client, rerr)) < 0 ||
- (err = remoteSASLCheckSSF(client, rerr)) < 0) {
+ if ((err = remoteSASLFinish(client)) < 0) {
if (err == -2)
goto authdeny;
else
goto authfail;
}
- VIR_DEBUG("Authentication successful %d", client->fd);
- PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_SASL, client->saslUsername);
ret->complete = 1;
- client->auth = REMOTE_AUTH_NONE;
}
- virMutexUnlock(&client->lock);
+ virMutexUnlock(&priv->lock);
return 0;
authfail:
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
- remoteDispatchAuthError(rerr);
+ PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+ virNetServerClientGetFD(client), REMOTE_AUTH_SASL);
goto error;
authdeny:
PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_SASL, client->saslUsername);
+ virNetServerClientGetFD(client), REMOTE_AUTH_SASL,
+ virNetSASLSessionGetIdentity(priv->sasl));
goto error;
error:
- virMutexUnlock(&client->lock);
- return -1;
-}
-
-
-#else /* HAVE_SASL */
-static int
-remoteDispatchAuthSaslInit(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- void *args ATTRIBUTE_UNUSED,
- remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
-{
- VIR_ERROR(_("client tried unsupported SASL init request"));
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
- remoteDispatchAuthError(rerr);
- return -1;
-}
-
-static int
-remoteDispatchAuthSaslStart(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- remote_auth_sasl_start_args *args ATTRIBUTE_UNUSED,
- remote_auth_sasl_start_ret *ret ATTRIBUTE_UNUSED)
-{
- VIR_ERROR(_("client tried unsupported SASL start request"));
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
- remoteDispatchAuthError(rerr);
+ virNetSASLSessionFree(priv->sasl);
+ priv->sasl = NULL;
+ virResetLastError();
+ virNetError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
return -1;
}
-static int
-remoteDispatchAuthSaslStep(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- remote_auth_sasl_step_args *args ATTRIBUTE_UNUSED,
- remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED)
-{
- VIR_ERROR(_("client tried unsupported SASL step request"));
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL);
- remoteDispatchAuthError(rerr);
- return -1;
-}
-#endif /* HAVE_SASL */
#if HAVE_POLKIT1
static int
-remoteDispatchAuthPolkit(struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_auth_polkit_ret *ret)
{
pid_t callerPid = -1;
int status = -1;
char pidbuf[50];
char ident[100];
- int rv;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
memset(ident, 0, sizeof ident);
- virMutexLock(&server->lock);
- virMutexLock(&client->lock);
- virMutexUnlock(&server->lock);
-
- action = client->readonly ?
+ virMutexLock(&priv->lock);
+ action = virNetServerClientGetReadonly(client) ?
"org.libvirt.unix.monitor" :
"org.libvirt.unix.manage";
NULL
};
- VIR_DEBUG("Start PolicyKit auth %d", client->fd);
- if (client->auth != REMOTE_AUTH_POLKIT) {
+ VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
+ if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_POLKIT) {
VIR_ERROR(_("client tried invalid PolicyKit init request"));
goto authfail;
}
- if (qemudGetSocketIdentity(client->fd, &callerUid, &callerPid) < 0) {
- VIR_ERROR(_("cannot get peer socket identity"));
+ if (virNetServerClientGetLocalIdentity(client, &callerUid, &callerPid) < 0) {
goto authfail;
}
goto authdeny;
}
PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_POLKIT, (char *)ident);
+ virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, ident);
VIR_INFO("Policy allowed action %s from pid %d, uid %d",
action, callerPid, callerUid);
ret->complete = 1;
- client->auth = REMOTE_AUTH_NONE;
- virMutexUnlock(&client->lock);
+ virNetServerClientSetIdentity(client, ident);
+ virMutexUnlock(&priv->lock);
+
return 0;
+error:
+ virResetLastError();
+ virNetError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return -1;
+
authfail:
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_POLKIT);
+ PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+ virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT);
goto error;
authdeny:
PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_POLKIT, (char *)ident);
+ virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, (char *)ident);
goto error;
-
-error:
- remoteDispatchAuthError(rerr);
- virMutexUnlock(&client->lock);
- return -1;
}
#elif HAVE_POLKIT0
static int
-remoteDispatchAuthPolkit(struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_auth_polkit_ret *ret)
{
pid_t callerPid;
DBusError err;
const char *action;
char ident[100];
- int rv;
+ int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
memset(ident, 0, sizeof ident);
"org.libvirt.unix.monitor" :
"org.libvirt.unix.manage";
- VIR_DEBUG("Start PolicyKit auth %d", client->fd);
+ VIR_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client));
if (client->auth != REMOTE_AUTH_POLKIT) {
VIR_ERROR(_("client tried invalid PolicyKit init request"));
goto authfail;
}
- if (qemudGetSocketIdentity(client->fd, &callerUid, &callerPid) < 0) {
+ if (qemudGetSocketIdentity(virNetServerClientGetFD(client), &callerUid, &callerPid) < 0) {
VIR_ERROR(_("cannot get peer socket identity"));
goto authfail;
}
goto authdeny;
}
PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_POLKIT, ident);
+ virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, ident);
VIR_INFO("Policy allowed action %s from pid %d, uid %d, result %s",
action, callerPid, callerUid,
polkit_result_to_string_representation(pkresult));
virMutexUnlock(&client->lock);
return 0;
+error:
+ virResetLastError();
+ virNetError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&client->lock);
+ return -1;
+
authfail:
- PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_POLKIT);
+ PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d",
+ virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT);
goto error;
authdeny:
PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s",
- client->fd, REMOTE_AUTH_POLKIT, ident);
+ virNetServerClientGetFD(client), REMOTE_AUTH_POLKIT, ident);
goto error;
-
-error:
- remoteDispatchAuthError(rerr);
- virMutexUnlock(&client->lock);
- return -1;
}
#else /* !HAVE_POLKIT0 & !HAVE_POLKIT1*/
static int
-remoteDispatchAuthPolkit(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn ATTRIBUTE_UNUSED,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchAuthPolkit(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_auth_polkit_ret *ret ATTRIBUTE_UNUSED)
{
VIR_ERROR(_("client tried unsupported PolicyKit init request"));
- remoteDispatchAuthError(rerr);
+ virNetError(VIR_ERR_AUTH_FAILED, "%s",
+ _("authentication failed"));
+ virNetMessageSaveError(rerr);
return -1;
}
#endif /* HAVE_POLKIT1 */
**************************************************************/
static int
-remoteDispatchNodeDeviceGetParent(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchNodeDeviceGetParent(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_node_device_get_parent_args *args,
remote_node_device_get_parent_ret *ret)
{
virNodeDevicePtr dev = NULL;
const char *parent = NULL;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dev = virNodeDeviceLookupByName(conn, args->name)))
+ if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))
goto cleanup;
parent = virNodeDeviceGetParent(dev);
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dev)
virNodeDeviceFree(dev);
return rv;
* Register / deregister events
***************************/
static int
-remoteDispatchDomainEventsRegister(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr ATTRIBUTE_UNUSED,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchDomainEventsRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
remote_domain_events_register_ret *ret ATTRIBUTE_UNUSED)
{
int callbackID;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] != -1) {
+ virMutexLock(&priv->lock);
+
+ if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] != -1) {
virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d already registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE);
goto cleanup;
}
- if ((callbackID = virConnectDomainEventRegisterAny(conn,
+ if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
NULL,
VIR_DOMAIN_EVENT_ID_LIFECYCLE,
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
client, NULL)) < 0)
goto cleanup;
- client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = callbackID;
+ priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = callbackID;
rv = 0;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
return rv;
}
static int
-remoteDispatchDomainEventsDeregister(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr ATTRIBUTE_UNUSED,
- void *args ATTRIBUTE_UNUSED,
+remoteDispatchDomainEventsDeregister(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
remote_domain_events_deregister_ret *ret ATTRIBUTE_UNUSED)
{
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] < 0) {
+ virMutexLock(&priv->lock);
+
+ if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] < 0) {
virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d not registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE);
goto cleanup;
}
- if (virConnectDomainEventDeregisterAny(conn,
- client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE]) < 0)
+ if (virConnectDomainEventDeregisterAny(priv->conn,
+ priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE]) < 0)
goto cleanup;
- client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = -1;
+ priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = -1;
+
rv = 0;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
return rv;
}
static void
-remoteDispatchDomainEventSend(struct qemud_client *client,
+remoteDispatchDomainEventSend(virNetServerClientPtr client,
+ virNetServerProgramPtr program,
int procnr,
xdrproc_t proc,
void *data)
{
- struct qemud_client_message *msg = NULL;
- XDR xdr;
- unsigned int len;
+ virNetMessagePtr msg;
- if (VIR_ALLOC(msg) < 0)
+ if (!(msg = virNetMessageNew()))
return;
- msg->hdr.prog = REMOTE_PROGRAM;
- msg->hdr.vers = REMOTE_PROTOCOL_VERSION;
- msg->hdr.proc = procnr;
- msg->hdr.type = REMOTE_MESSAGE;
- msg->hdr.serial = 1;
- msg->hdr.status = REMOTE_OK;
+ msg->header.prog = virNetServerProgramGetID(program);
+ msg->header.vers = virNetServerProgramGetVersion(program);
+ msg->header.proc = procnr;
+ msg->header.type = VIR_NET_MESSAGE;
+ msg->header.serial = 1;
+ msg->header.status = VIR_NET_OK;
- if (remoteEncodeClientMessageHeader(msg) < 0)
+ if (virNetMessageEncodeHeader(msg) < 0)
goto cleanup;
- /* Serialise the return header and event. */
- xdrmem_create(&xdr,
- msg->buffer,
- msg->bufferLength,
- XDR_ENCODE);
-
- /* Skip over the header we just wrote */
- if (xdr_setpos(&xdr, msg->bufferOffset) == 0)
- goto xdr_cleanup;
-
- if (!(proc)(&xdr, data)) {
- VIR_WARN("Failed to serialize domain event %d", procnr);
- goto xdr_cleanup;
- }
-
- /* Update length word to include payload*/
- len = msg->bufferOffset = xdr_getpos(&xdr);
- if (xdr_setpos(&xdr, 0) == 0)
- goto xdr_cleanup;
-
- if (!xdr_u_int(&xdr, &len))
- goto xdr_cleanup;
-
- /* Send it. */
- msg->async = 1;
- msg->bufferLength = len;
- msg->bufferOffset = 0;
+ if (virNetMessageEncodePayload(msg, proc, data) < 0)
+ goto cleanup;
- VIR_DEBUG("Queue event %d %d", procnr, msg->bufferLength);
- qemudClientMessageQueuePush(&client->tx, msg);
- qemudUpdateClientEvent(client);
+ VIR_DEBUG("Queue event %d %zu", procnr, msg->bufferLength);
+ virNetServerClientSendMessage(client, msg);
- xdr_destroy(&xdr);
return;
-xdr_cleanup:
- xdr_destroy(&xdr);
cleanup:
- VIR_FREE(msg);
+ virNetMessageFree(msg);
}
static int
-remoteDispatchSecretGetValue(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchSecretGetValue(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_secret_get_value_args *args,
remote_secret_get_value_ret *ret)
{
size_t value_size;
unsigned char *value;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(secret = get_nonnull_secret(conn, args->secret)))
+ if (!(secret = get_nonnull_secret(priv->conn, args->secret)))
goto cleanup;
if (!(value = virSecretGetValue(secret, &value_size, args->flags)))
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (secret)
virSecretFree(secret);
return rv;
}
static int
-remoteDispatchDomainGetState(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainGetState(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_get_state_args *args,
remote_domain_get_state_ret *ret)
{
virDomainPtr dom = NULL;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (virDomainGetState(dom, &ret->state, &ret->reason, args->flags) < 0)
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
return rv;
}
static int
-remoteDispatchDomainEventsRegisterAny(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr ATTRIBUTE_UNUSED,
- remote_domain_events_register_any_args *args,
- void *ret ATTRIBUTE_UNUSED)
+remoteDispatchDomainEventsRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_domain_events_register_any_args *args)
{
int callbackID;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
+ virMutexLock(&priv->lock);
+
if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST ||
args->eventID < 0) {
virNetError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"), args->eventID);
goto cleanup;
}
- if (client->domainEventCallbackID[args->eventID] != -1) {
+ if (priv->domainEventCallbackID[args->eventID] != -1) {
virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d already registered"), args->eventID);
goto cleanup;
}
- if ((callbackID = virConnectDomainEventRegisterAny(conn,
+ if ((callbackID = virConnectDomainEventRegisterAny(priv->conn,
NULL,
args->eventID,
domainEventCallbacks[args->eventID],
client, NULL)) < 0)
goto cleanup;
- client->domainEventCallbackID[args->eventID] = callbackID;
+ priv->domainEventCallbackID[args->eventID] = callbackID;
rv = 0;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
return rv;
}
static int
-remoteDispatchDomainEventsDeregisterAny(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr ATTRIBUTE_UNUSED,
- remote_domain_events_deregister_any_args *args,
- void *ret ATTRIBUTE_UNUSED)
+remoteDispatchDomainEventsDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_domain_events_deregister_any_args *args)
{
int callbackID = -1;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
+ virMutexLock(&priv->lock);
+
if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST ||
args->eventID < 0) {
virNetError(VIR_ERR_INTERNAL_ERROR, _("unsupported event ID %d"), args->eventID);
goto cleanup;
}
- if ((callbackID = client->domainEventCallbackID[args->eventID]) < 0) {
+ callbackID = priv->domainEventCallbackID[args->eventID];
+ if (callbackID < 0) {
virNetError(VIR_ERR_INTERNAL_ERROR, _("domain event %d not registered"), args->eventID);
goto cleanup;
}
- if (virConnectDomainEventDeregisterAny(conn, callbackID) < 0)
+ if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0)
goto cleanup;
- client->domainEventCallbackID[args->eventID] = -1;
+ priv->domainEventCallbackID[args->eventID] = -1;
+
rv = 0;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
return rv;
}
static int
-qemuDispatchMonitorCommand(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+qemuDispatchMonitorCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
qemu_monitor_command_args *args,
qemu_monitor_command_ret *ret)
{
virDomainPtr dom = NULL;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (virDomainQemuMonitorCommand(dom, args->cmd, &ret->result,
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
return rv;
}
-#include "remote_dispatch_bodies.h"
-#include "qemu_dispatch_bodies.h"
-
-
static int
-remoteDispatchDomainMigrateBegin3(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMigrateBegin3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_migrate_begin3_args *args,
remote_domain_migrate_begin3_ret *ret)
{
char *cookieout = NULL;
int cookieoutlen = 0;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
return rv;
static int
-remoteDispatchDomainMigratePrepare3(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMigratePrepare3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_migrate_prepare3_args *args,
remote_domain_migrate_prepare3_ret *ret)
{
char **uri_out;
char *dname;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
goto cleanup;
}
- if (virDomainMigratePrepare3(conn,
+ if (virDomainMigratePrepare3(priv->conn,
args->cookie_in.cookie_in_val,
args->cookie_in.cookie_in_len,
&cookieout, &cookieoutlen,
cleanup:
if (rv < 0) {
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(uri_out);
}
return rv;
}
+
static int
-remoteDispatchDomainMigratePerform3(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMigratePerform3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_migrate_perform3_args *args,
remote_domain_migrate_perform3_ret *ret)
{
char *cookieout = NULL;
int cookieoutlen = 0;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
xmlin = args->xmlin == NULL ? NULL : *args->xmlin;
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
return rv;
static int
-remoteDispatchDomainMigrateFinish3(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
+remoteDispatchDomainMigrateFinish3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
remote_domain_migrate_finish3_args *args,
remote_domain_migrate_finish3_ret *ret)
{
char *uri;
char *dconnuri;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
uri = args->uri == NULL ? NULL : *args->uri;
dconnuri = args->dconnuri == NULL ? NULL : *args->dconnuri;
- if (!(dom = virDomainMigrateFinish3(conn, args->dname,
+ if (!(dom = virDomainMigrateFinish3(priv->conn, args->dname,
args->cookie_in.cookie_in_val,
args->cookie_in.cookie_in_len,
&cookieout, &cookieoutlen,
cleanup:
if (rv < 0) {
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
VIR_FREE(cookieout);
}
if (dom)
static int
-remoteDispatchDomainMigrateConfirm3(struct qemud_server *server ATTRIBUTE_UNUSED,
- struct qemud_client *client ATTRIBUTE_UNUSED,
- virConnectPtr conn,
- remote_message_header *hdr ATTRIBUTE_UNUSED,
- remote_error *rerr,
- remote_domain_migrate_confirm3_args *args,
- void *ret ATTRIBUTE_UNUSED)
+remoteDispatchDomainMigrateConfirm3(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_migrate_confirm3_args *args)
{
virDomainPtr dom = NULL;
int rv = -1;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
- if (!conn) {
+ if (!priv->conn) {
virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
goto cleanup;
}
- if (!(dom = get_nonnull_domain(conn, args->dom)))
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
goto cleanup;
if (virDomainMigrateConfirm3(dom,
cleanup:
if (rv < 0)
- remoteDispatchError(rerr);
+ virNetMessageSaveError(rerr);
if (dom)
virDomainFree(dom);
return rv;
#ifndef __LIBVIRTD_REMOTE_H__
# define __LIBVIRTD_REMOTE_H__
+# include "remote_protocol.h"
+# include "rpc/virnetserverprogram.h"
+# include "rpc/virnetserverclient.h"
-# include "libvirtd.h"
-typedef union {
-# include "remote_dispatch_args.h"
-} dispatch_args;
-verify(sizeof(dispatch_args) > 0);
-
-typedef union {
-# include "remote_dispatch_ret.h"
-} dispatch_ret;
-verify(sizeof(dispatch_ret) > 0);
-
-typedef union {
-# include "qemu_dispatch_args.h"
-} qemu_dispatch_args;
-verify(sizeof(qemu_dispatch_args) > 0);
-
-typedef union {
-# include "qemu_dispatch_ret.h"
-} qemu_dispatch_ret;
-verify(sizeof(qemu_dispatch_ret) > 0);
-
-
-
-/**
- * When the RPC handler is called:
- *
- * - Server object is unlocked
- * - Client object is unlocked
- *
- * Both must be locked before use. Server lock must
- * be held before attempting to lock client.
- *
- * Without any locking, it is safe to use:
- *
- * 'conn', 'rerr', 'args and 'ret'
- */
-typedef int (*dispatch_fn) (struct qemud_server *server,
- struct qemud_client *client,
- virConnectPtr conn,
- remote_message_header *hdr,
- remote_error *err,
- dispatch_args *args,
- dispatch_ret *ret);
-
-typedef struct {
- dispatch_fn fn;
- xdrproc_t args_filter;
- xdrproc_t ret_filter;
-} dispatch_data;
-
-
-const dispatch_data const *remoteGetDispatchData(int proc);
-const dispatch_data const *qemuGetDispatchData(int proc);
+extern virNetServerProgramProc remoteProcs[];
+extern size_t remoteNProcs;
+extern virNetServerProgramErrorHander remoteErr;
+extern virNetServerProgramProc qemuProcs[];
+extern size_t qemuNProcs;
+extern virNetServerProgramErrorHander qemuErr;
+int remoteClientInitHook(virNetServerPtr srv,
+ virNetServerClientPtr client);
#endif /* __LIBVIRTD_REMOTE_H__ */
#include <config.h>
#include "stream.h"
+#include "remote.h"
#include "memory.h"
-#include "dispatch.h"
#include "logging.h"
+#include "virnetserverclient.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_STREAMS
+#define virNetError(code, ...) \
+ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+struct daemonClientStream {
+ daemonClientPrivatePtr priv;
+
+ virNetServerProgramPtr prog;
+
+ virStreamPtr st;
+ int procedure;
+ int serial;
+
+ unsigned int recvEOF : 1;
+ unsigned int closed : 1;
+
+ int filterID;
+
+ virNetMessagePtr rx;
+ int tx;
+
+ daemonClientStreamPtr next;
+};
+
static int
-remoteStreamHandleWrite(struct qemud_client *client,
- struct qemud_client_stream *stream);
+daemonStreamHandleWrite(virNetServerClientPtr client,
+ daemonClientStream *stream);
static int
-remoteStreamHandleRead(struct qemud_client *client,
- struct qemud_client_stream *stream);
+daemonStreamHandleRead(virNetServerClientPtr client,
+ daemonClientStream *stream);
static int
-remoteStreamHandleFinish(struct qemud_client *client,
- struct qemud_client_stream *stream,
- struct qemud_client_message *msg);
+daemonStreamHandleFinish(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg);
static int
-remoteStreamHandleAbort(struct qemud_client *client,
- struct qemud_client_stream *stream,
- struct qemud_client_message *msg);
+daemonStreamHandleAbort(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg);
static void
-remoteStreamUpdateEvents(struct qemud_client_stream *stream)
+daemonStreamUpdateEvents(daemonClientStream *stream)
{
int newEvents = 0;
if (stream->rx)
virStreamEventUpdateCallback(stream->st, newEvents);
}
+/*
+ * Invoked when an outgoing data packet message has been fully sent.
+ * This simply re-enables TX of further data.
+ *
+ * The idea is to stop the daemon growing without bound due to
+ * fast stream, but slow client
+ */
+static void
+daemonStreamMessageFinished(virNetMessagePtr msg,
+ void *opaque)
+{
+ daemonClientStream *stream = opaque;
+ VIR_DEBUG("stream=%p proc=%d serial=%d",
+ stream, msg->header.proc, msg->header.serial);
+
+ stream->tx = 1;
+ daemonStreamUpdateEvents(stream);
+}
/*
* Callback that gets invoked when a stream becomes writable/readable
*/
static void
-remoteStreamEvent(virStreamPtr st, int events, void *opaque)
+daemonStreamEvent(virStreamPtr st, int events, void *opaque)
{
- struct qemud_client *client = opaque;
- struct qemud_client_stream *stream;
+ virNetServerClientPtr client = opaque;
+ daemonClientStream *stream;
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
- /* XXX sub-optimal - we really should be taking the server lock
- * first, but we have no handle to the server object
- * We're lucky to get away with it for now, due to this callback
- * executing in the main thread, but this should really be fixed
- */
- virMutexLock(&client->lock);
+ virMutexLock(&priv->lock);
- stream = remoteFindClientStream(client, st);
+ stream = priv->streams;
+ while (stream) {
+ if (stream->st == st)
+ break;
+ stream = stream->next;
+ }
if (!stream) {
VIR_WARN("event for client=%p stream st=%p, but missing stream state", client, st);
goto cleanup;
}
- VIR_DEBUG("st=%p events=%d", st, events);
+ VIR_DEBUG("st=%p events=%d EOF=%d closed=%d", st, events, stream->recvEOF, stream->closed);
if (events & VIR_STREAM_EVENT_WRITABLE) {
- if (remoteStreamHandleWrite(client, stream) < 0) {
- remoteRemoveClientStream(client, stream);
- qemudDispatchClientFailure(client);
+ if (daemonStreamHandleWrite(client, stream) < 0) {
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
goto cleanup;
}
}
if (!stream->recvEOF &&
(events & (VIR_STREAM_EVENT_READABLE | VIR_STREAM_EVENT_HANGUP))) {
events = events & ~(VIR_STREAM_EVENT_READABLE | VIR_STREAM_EVENT_HANGUP);
- if (remoteStreamHandleRead(client, stream) < 0) {
- remoteRemoveClientStream(client, stream);
- qemudDispatchClientFailure(client);
+ if (daemonStreamHandleRead(client, stream) < 0) {
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
goto cleanup;
}
}
+ /* If we have a completion/abort message, always process it */
+ if (stream->rx) {
+ virNetMessagePtr msg = stream->rx;
+ switch (msg->header.status) {
+ case VIR_NET_CONTINUE:
+ /* nada */
+ break;
+ case VIR_NET_OK:
+ virNetMessageQueueServe(&stream->rx);
+ if (daemonStreamHandleFinish(client, stream, msg) < 0) {
+ virNetMessageFree(msg);
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ break;
+ case VIR_NET_ERROR:
+ default:
+ virNetMessageQueueServe(&stream->rx);
+ if (daemonStreamHandleAbort(client, stream, msg) < 0) {
+ virNetMessageFree(msg);
+ daemonRemoveClientStream(client, stream);
+ virNetServerClientClose(client);
+ goto cleanup;
+ }
+ break;
+ }
+ }
+
if (!stream->closed &&
(events & (VIR_STREAM_EVENT_ERROR | VIR_STREAM_EVENT_HANGUP))) {
int ret;
- remote_error rerr;
- memset(&rerr, 0, sizeof rerr);
+ virNetMessagePtr msg;
+ virNetMessageError rerr;
+
+ memset(&rerr, 0, sizeof(rerr));
stream->closed = 1;
virStreamEventRemoveCallback(stream->st);
virStreamAbort(stream->st);
if (events & VIR_STREAM_EVENT_HANGUP)
- remoteDispatchFormatError(&rerr, "%s", _("stream had unexpected termination"));
+ virNetError(VIR_ERR_RPC,
+ "%s", _("stream had unexpected termination"));
else
- remoteDispatchFormatError(&rerr, "%s", _("stream had I/O failure"));
- ret = remoteSerializeStreamError(client, &rerr, stream->procedure, stream->serial);
- remoteRemoveClientStream(client, stream);
+ virNetError(VIR_ERR_RPC,
+ "%s", _("stream had I/O failure"));
+
+ msg = virNetMessageNew();
+ if (!msg) {
+ ret = -1;
+ } else {
+ ret = virNetServerProgramSendStreamError(remoteProgram,
+ client,
+ msg,
+ &rerr,
+ stream->procedure,
+ stream->serial);
+ }
+ daemonRemoveClientStream(client, stream);
if (ret < 0)
- qemudDispatchClientFailure(client);
+ virNetServerClientClose(client);
goto cleanup;
}
if (stream->closed) {
- remoteRemoveClientStream(client, stream);
+ daemonRemoveClientStream(client, stream);
} else {
- remoteStreamUpdateEvents(stream);
+ daemonStreamUpdateEvents(stream);
}
cleanup:
- virMutexUnlock(&client->lock);
+ virMutexUnlock(&priv->lock);
}
* -1 on fatal client error
*/
static int
-remoteStreamFilter(struct qemud_client *client,
- struct qemud_client_message *msg, void *opaque)
+daemonStreamFilter(virNetServerClientPtr client,
+ virNetMessagePtr msg,
+ void *opaque)
{
- struct qemud_client_stream *stream = opaque;
-
- if (msg->hdr.serial == stream->serial &&
- msg->hdr.proc == stream->procedure &&
- msg->hdr.type == REMOTE_STREAM) {
- VIR_DEBUG("Incoming rx=%p serial=%d proc=%d status=%d",
- stream->rx, msg->hdr.proc, msg->hdr.serial, msg->hdr.status);
-
- /* If there are queued packets, we need to queue all further
- * messages, since they must be processed strictly in order.
- * If there are no queued packets, then OK/ERROR messages
- * should be processed immediately. Data packets are still
- * queued to only be processed when the stream is marked as
- * writable.
- */
- if (stream->rx) {
- qemudClientMessageQueuePush(&stream->rx, msg);
- remoteStreamUpdateEvents(stream);
- } else {
- int ret = 0;
- switch (msg->hdr.status) {
- case REMOTE_OK:
- ret = remoteStreamHandleFinish(client, stream, msg);
- if (ret == 0)
- qemudClientMessageRelease(client, msg);
- break;
-
- case REMOTE_CONTINUE:
- qemudClientMessageQueuePush(&stream->rx, msg);
- remoteStreamUpdateEvents(stream);
- break;
-
- case REMOTE_ERROR:
- default:
- ret = remoteStreamHandleAbort(client, stream, msg);
- if (ret == 0)
- qemudClientMessageRelease(client, msg);
- break;
- }
+ daemonClientStream *stream = opaque;
+ int ret = 0;
- if (ret < 0)
- return -1;
- }
- return 1;
- }
- return 0;
+ virMutexLock(&stream->priv->lock);
+
+ if (msg->header.type != VIR_NET_STREAM)
+ goto cleanup;
+
+ if (!virNetServerProgramMatches(stream->prog, msg))
+ goto cleanup;
+
+ if (msg->header.proc != stream->procedure ||
+ msg->header.serial != stream->serial)
+ goto cleanup;
+
+ VIR_DEBUG("Incoming client=%p, rx=%p, serial=%d, proc=%d, status=%d",
+ client, stream->rx, msg->header.proc,
+ msg->header.serial, msg->header.status);
+
+ virNetMessageQueuePush(&stream->rx, msg);
+ daemonStreamUpdateEvents(stream);
+ ret = 1;
+
+cleanup:
+ virMutexUnlock(&stream->priv->lock);
+ return ret;
}
/*
* @conn: a connection object to associate the stream with
- * @hdr: the method call to associate with the stram
+ * @header: the method call to associate with the stream
*
* Creates a new stream for this conn
*
* Returns a new stream object, or NULL upon OOM
*/
-struct qemud_client_stream *
-remoteCreateClientStream(virConnectPtr conn,
- remote_message_header *hdr)
+daemonClientStream *
+daemonCreateClientStream(virNetServerClientPtr client,
+ virStreamPtr st,
+ virNetServerProgramPtr prog,
+ virNetMessageHeaderPtr header)
{
- struct qemud_client_stream *stream;
+ daemonClientStream *stream;
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
- VIR_DEBUG("proc=%d serial=%d", hdr->proc, hdr->serial);
+ VIR_DEBUG("client=%p, proc=%d, serial=%d, st=%p",
+ client, header->proc, header->serial, st);
if (VIR_ALLOC(stream) < 0) {
virReportOOMError();
return NULL;
}
- stream->procedure = hdr->proc;
- stream->serial = hdr->serial;
-
- stream->st = virStreamNew(conn, VIR_STREAM_NONBLOCK);
- if (!stream->st) {
- VIR_FREE(stream);
- return NULL;
- }
+ stream->priv = priv;
+ stream->prog = prog;
+ stream->procedure = header->proc;
+ stream->serial = header->serial;
+ stream->filterID = -1;
+ stream->st = st;
- stream->filter.query = remoteStreamFilter;
- stream->filter.opaque = stream;
+ virNetServerProgramRef(prog);
return stream;
}
* Frees the memory associated with this inactive client
* stream
*/
-void remoteFreeClientStream(struct qemud_client *client,
- struct qemud_client_stream *stream)
+int daemonFreeClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream)
{
- struct qemud_client_message *msg;
+ virNetMessagePtr msg;
+ int ret = 0;
if (!stream)
- return;
+ return 0;
+
+ VIR_DEBUG("client=%p, proc=%d, serial=%d",
+ client, stream->procedure, stream->serial);
- VIR_DEBUG("proc=%d serial=%d", stream->procedure, stream->serial);
+ virNetServerProgramFree(stream->prog);
msg = stream->rx;
while (msg) {
- struct qemud_client_message *tmp = msg->next;
- qemudClientMessageRelease(client, msg);
+ virNetMessagePtr tmp = msg->next;
+ /* Send a dummy reply to free up 'msg' & unblock client rx */
+ memset(msg, 0, sizeof(*msg));
+ if (virNetServerClientSendMessage(client, msg) < 0) {
+ virNetServerClientMarkClose(client);
+ virNetMessageFree(msg);
+ ret = -1;
+ }
msg = tmp;
}
virStreamFree(stream->st);
VIR_FREE(stream);
+
+ return ret;
}
* @client: a locked client to add the stream to
* @stream: a stream to add
*/
-int remoteAddClientStream(struct qemud_client *client,
- struct qemud_client_stream *stream,
- int transmit)
+int daemonAddClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ bool transmit)
{
- struct qemud_client_stream *tmp = client->streams;
+ VIR_DEBUG("client=%p, proc=%d, serial=%d, st=%p, transmit=%d",
+ client, stream->procedure, stream->serial, stream->st, transmit);
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
- VIR_DEBUG("client=%p proc=%d serial=%d", client, stream->procedure, stream->serial);
+ if (stream->filterID != -1) {
+ VIR_WARN("Filter already added to client %p", client);
+ return -1;
+ }
if (virStreamEventAddCallback(stream->st, 0,
- remoteStreamEvent, client, NULL) < 0)
+ daemonStreamEvent, client, NULL) < 0)
return -1;
- if (tmp) {
- while (tmp->next)
- tmp = tmp->next;
- tmp->next = stream;
- } else {
- client->streams = stream;
+ if ((stream->filterID = virNetServerClientAddFilter(client,
+ daemonStreamFilter,
+ stream)) < 0) {
+ virStreamEventRemoveCallback(stream->st);
+ return -1;
}
- stream->filter.next = client->filters;
- client->filters = &stream->filter;
-
if (transmit)
stream->tx = 1;
- remoteStreamUpdateEvents(stream);
+ virMutexLock(&priv->lock);
+ stream->next = priv->streams;
+ priv->streams = stream;
- return 0;
-}
+ daemonStreamUpdateEvents(stream);
+ virMutexUnlock(&priv->lock);
-/*
- * @client: a locked client object
- * @procedure: procedure associated with the stream
- * @serial: serial number associated with the stream
- *
- * Finds a existing active stream
- *
- * Returns a stream object matching the procedure+serial number, or NULL
- */
-struct qemud_client_stream *
-remoteFindClientStream(struct qemud_client *client,
- virStreamPtr st)
-{
- struct qemud_client_stream *stream = client->streams;
-
- while (stream) {
- if (stream->st == st)
- return stream;
- stream = stream->next;
- }
-
- return NULL;
+ return 0;
}
* Returns 0 if the stream was removd, -1 if it doesn't exist
*/
int
-remoteRemoveClientStream(struct qemud_client *client,
- struct qemud_client_stream *stream)
+daemonRemoveClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream)
{
- VIR_DEBUG("client=%p proc=%d serial=%d", client, stream->procedure, stream->serial);
-
- struct qemud_client_stream *curr = client->streams;
- struct qemud_client_stream *prev = NULL;
- struct qemud_client_filter *filter = NULL;
-
- if (client->filters == &stream->filter) {
- client->filters = client->filters->next;
- } else {
- filter = client->filters;
- while (filter) {
- if (filter->next == &stream->filter) {
- filter->next = filter->next->next;
- break;
- }
- filter = filter->next;
- }
+ VIR_DEBUG("client=%p, proc=%d, serial=%d, st=%p",
+ client, stream->procedure, stream->serial, stream->st);
+ daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client);
+ daemonClientStream *curr = priv->streams;
+ daemonClientStream *prev = NULL;
+
+ if (stream->filterID != -1) {
+ virNetServerClientRemoveFilter(client,
+ stream->filterID);
+ stream->filterID = -1;
}
if (!stream->closed) {
if (prev)
prev->next = curr->next;
else
- client->streams = curr->next;
- remoteFreeClientStream(client, stream);
- return 0;
+ priv->streams = curr->next;
+ return daemonFreeClientStream(client, stream);
}
prev = curr;
curr = curr->next;
* 1 if message is still being processed
*/
static int
-remoteStreamHandleWriteData(struct qemud_client *client,
- struct qemud_client_stream *stream,
- struct qemud_client_message *msg)
+daemonStreamHandleWriteData(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg)
{
- remote_error rerr;
int ret;
- VIR_DEBUG("stream=%p proc=%d serial=%d len=%d offset=%d",
- stream, msg->hdr.proc, msg->hdr.serial, msg->bufferLength, msg->bufferOffset);
-
- memset(&rerr, 0, sizeof rerr);
+ VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%d, len=%zu, offset=%zu",
+ client, stream, msg->header.proc, msg->header.serial,
+ msg->bufferLength, msg->bufferOffset);
ret = virStreamSend(stream->st,
msg->buffer + msg->bufferOffset,
/* Partial write, so indicate we have more todo later */
if (msg->bufferOffset < msg->bufferLength)
return 1;
+
+ /* A dummy 'send' just to free up 'msg' object */
+ memset(msg, 0, sizeof(*msg));
+ return virNetServerClientSendMessage(client, msg);
} else if (ret == -2) {
/* Blocking, so indicate we have more todo later */
return 1;
} else {
+ virNetMessageError rerr;
+
+ memset(&rerr, 0, sizeof(rerr));
+
VIR_INFO("Stream send failed");
stream->closed = 1;
- remoteDispatchError(&rerr);
- return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+ return virNetServerProgramSendReplyError(stream->prog,
+ client,
+ msg,
+ &rerr,
+ &msg->header);
}
return 0;
/*
* Process an finish handshake from the client.
*
- * Returns a REMOTE_OK confirmation if successful, or a REMOTE_ERROR
+ * Returns a VIR_NET_OK confirmation if successful, or a VIR_NET_ERROR
* if there was a stream error
*
* Returns 0 if successfully sent RPC reply, -1 upon fatal error
*/
static int
-remoteStreamHandleFinish(struct qemud_client *client,
- struct qemud_client_stream *stream,
- struct qemud_client_message *msg)
+daemonStreamHandleFinish(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg)
{
- remote_error rerr;
int ret;
- VIR_DEBUG("stream=%p proc=%d serial=%d",
- stream, msg->hdr.proc, msg->hdr.serial);
-
- memset(&rerr, 0, sizeof rerr);
+ VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%d",
+ client, stream, msg->header.proc, msg->header.serial);
stream->closed = 1;
virStreamEventRemoveCallback(stream->st);
ret = virStreamFinish(stream->st);
if (ret < 0) {
- remoteDispatchError(&rerr);
- return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+ virNetMessageError rerr;
+ memset(&rerr, 0, sizeof(rerr));
+ return virNetServerProgramSendReplyError(stream->prog,
+ client,
+ msg,
+ &rerr,
+ &msg->header);
} else {
/* Send zero-length confirm */
- if (remoteSendStreamData(client, stream, NULL, 0) < 0)
- return -1;
+ return virNetServerProgramSendStreamData(stream->prog,
+ client,
+ msg,
+ stream->procedure,
+ stream->serial,
+ NULL, 0);
}
-
- return 0;
}
* Returns 0 if successfully aborted, -1 upon error
*/
static int
-remoteStreamHandleAbort(struct qemud_client *client,
- struct qemud_client_stream *stream,
- struct qemud_client_message *msg)
+daemonStreamHandleAbort(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ virNetMessagePtr msg)
{
- remote_error rerr;
-
- VIR_DEBUG("stream=%p proc=%d serial=%d",
- stream, msg->hdr.proc, msg->hdr.serial);
+ VIR_DEBUG("client=%p, stream=%p, proc=%d, serial=%d",
+ client, stream, msg->header.proc, msg->header.serial);
+ virNetMessageError rerr;
- memset(&rerr, 0, sizeof rerr);
+ memset(&rerr, 0, sizeof(rerr));
stream->closed = 1;
virStreamEventRemoveCallback(stream->st);
virStreamAbort(stream->st);
- if (msg->hdr.status == REMOTE_ERROR)
- remoteDispatchFormatError(&rerr, "%s", _("stream aborted at client request"));
+ if (msg->header.status == VIR_NET_ERROR)
+ virNetError(VIR_ERR_RPC,
+ "%s", _("stream aborted at client request"));
else {
- VIR_WARN("unexpected stream status %d", msg->hdr.status);
- remoteDispatchFormatError(&rerr, _("stream aborted with unexpected status %d"),
- msg->hdr.status);
+ VIR_WARN("unexpected stream status %d", msg->header.status);
+ virNetError(VIR_ERR_RPC,
+ _("stream aborted with unexpected status %d"),
+ msg->header.status);
}
- return remoteSerializeReplyError(client, &rerr, &msg->hdr);
+ return virNetServerProgramSendReplyError(remoteProgram,
+ client,
+ msg,
+ &rerr,
+ &msg->header);
}
* Returns 0 on success, or -1 upon fatal error
*/
static int
-remoteStreamHandleWrite(struct qemud_client *client,
- struct qemud_client_stream *stream)
+daemonStreamHandleWrite(virNetServerClientPtr client,
+ daemonClientStream *stream)
{
- struct qemud_client_message *msg, *tmp;
-
- VIR_DEBUG("stream=%p", stream);
+ VIR_DEBUG("client=%p, stream=%p", client, stream);
- msg = stream->rx;
- while (msg && !stream->closed) {
+ while (stream->rx && !stream->closed) {
+ virNetMessagePtr msg = stream->rx;
int ret;
- switch (msg->hdr.status) {
- case REMOTE_OK:
- ret = remoteStreamHandleFinish(client, stream, msg);
+
+ switch (msg->header.status) {
+ case VIR_NET_OK:
+ ret = daemonStreamHandleFinish(client, stream, msg);
break;
- case REMOTE_CONTINUE:
- ret = remoteStreamHandleWriteData(client, stream, msg);
+ case VIR_NET_CONTINUE:
+ ret = daemonStreamHandleWriteData(client, stream, msg);
break;
- case REMOTE_ERROR:
+ case VIR_NET_ERROR:
default:
- ret = remoteStreamHandleAbort(client, stream, msg);
+ ret = daemonStreamHandleAbort(client, stream, msg);
break;
}
- if (ret == 0)
- qemudClientMessageQueueServe(&stream->rx);
- else if (ret < 0)
- return -1;
- else
- break; /* still processing data */
+ if (ret > 0)
+ break; /* still processing data from msg */
- tmp = msg->next;
- qemudClientMessageRelease(client, msg);
- msg = tmp;
+ virNetMessageQueueServe(&stream->rx);
+ if (ret < 0) {
+ virNetMessageFree(msg);
+ virNetServerClientMarkClose(client);
+ return -1;
+ }
}
return 0;
* be killed
*/
static int
-remoteStreamHandleRead(struct qemud_client *client,
- struct qemud_client_stream *stream)
+daemonStreamHandleRead(virNetServerClientPtr client,
+ daemonClientStream *stream)
{
char *buffer;
- size_t bufferLen = REMOTE_MESSAGE_PAYLOAD_MAX;
+ size_t bufferLen = VIR_NET_MESSAGE_PAYLOAD_MAX;
int ret;
- VIR_DEBUG("stream=%p", stream);
+ VIR_DEBUG("client=%p, stream=%p", client, stream);
/* Shouldn't ever be called unless we're marked able to
* transmit, but doesn't hurt to check */
* we're readable, but hey things change... */
ret = 0;
} else if (ret < 0) {
- remote_error rerr;
- memset(&rerr, 0, sizeof rerr);
- remoteDispatchError(&rerr);
+ virNetMessagePtr msg;
+ virNetMessageError rerr;
+
+ memset(&rerr, 0, sizeof(rerr));
- ret = remoteSerializeStreamError(client, &rerr, stream->procedure, stream->serial);
+ if (!(msg = virNetMessageNew()))
+ ret = -1;
+ else
+ ret = virNetServerProgramSendStreamError(remoteProgram,
+ client,
+ msg,
+ &rerr,
+ stream->procedure,
+ stream->serial);
} else {
+ virNetMessagePtr msg;
stream->tx = 0;
if (ret == 0)
stream->recvEOF = 1;
- ret = remoteSendStreamData(client, stream, buffer, ret);
+ if (!(msg = virNetMessageNew()))
+ ret = -1;
+
+ if (msg) {
+ msg->cb = daemonStreamMessageFinished;
+ msg->opaque = stream;
+ virNetServerClientRef(client);
+ ret = virNetServerProgramSendStreamData(remoteProgram,
+ client,
+ msg,
+ stream->procedure,
+ stream->serial,
+ buffer, ret);
+ }
}
VIR_FREE(buffer);
return ret;
}
-
-
-/*
- * Invoked when an outgoing data packet message has been fully sent.
- * This simply re-enables TX of further data.
- *
- * The idea is to stop the daemon growing without bound due to
- * fast stream, but slow client
- */
-void
-remoteStreamMessageFinished(struct qemud_client *client,
- struct qemud_client_message *msg)
-{
- struct qemud_client_stream *stream = client->streams;
-
- while (stream) {
- if (msg->hdr.proc == stream->procedure &&
- msg->hdr.serial == stream->serial)
- break;
- stream = stream->next;
- }
-
- VIR_DEBUG("Message client=%p stream=%p proc=%d serial=%d", client, stream, msg->hdr.proc, msg->hdr.serial);
-
- if (stream) {
- stream->tx = 1;
- remoteStreamUpdateEvents(stream);
- }
-}
-struct qemud_client_stream *
-remoteCreateClientStream(virConnectPtr conn,
- remote_message_header *hdr);
+daemonClientStream *
+daemonCreateClientStream(virNetServerClientPtr client,
+ virStreamPtr st,
+ virNetServerProgramPtr prog,
+ virNetMessageHeaderPtr hdr);
-void remoteFreeClientStream(struct qemud_client *client,
- struct qemud_client_stream *stream);
+int daemonFreeClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream);
-int remoteAddClientStream(struct qemud_client *client,
- struct qemud_client_stream *stream,
- int transmit);
-
-struct qemud_client_stream *
-remoteFindClientStream(struct qemud_client *client,
- virStreamPtr stream);
+int daemonAddClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream,
+ bool transmit);
int
-remoteRemoveClientStream(struct qemud_client *client,
- struct qemud_client_stream *stream);
-
-void
-remoteStreamMessageFinished(struct qemud_client *client,
- struct qemud_client_message *msg);
+daemonRemoveClientStream(virNetServerClientPtr client,
+ daemonClientStream *stream);
#endif /* __LIBVIRTD_STREAM_H__ */
-daemon/dispatch.c
daemon/libvirtd.c
daemon/remote.c
daemon/remote_dispatch_bodies.h
}
}
-# Prototypes for dispatch functions ("remote_dispatch_prototypes.h").
-elsif ($opt_p) {
- my @keys = sort (keys %calls);
- foreach (@keys) {
- # Skip things which are REMOTE_MESSAGE
- next if $calls{$_}->{msg};
-
- print "static int ${structprefix}Dispatch$calls{$_}->{ProcName}(\n";
- print " struct qemud_server *server,\n";
- print " struct qemud_client *client,\n";
- print " virConnectPtr conn,\n";
- print " remote_message_header *hdr,\n";
- print " remote_error *rerr,\n";
- print " $calls{$_}->{args} *args,\n";
- print " $calls{$_}->{ret} *ret);\n";
- }
-}
-
-# Union of all arg types
-# ("remote_dispatch_args.h").
-elsif ($opt_a) {
- for ($id = 0 ; $id <= $#calls ; $id++) {
- if (defined $calls[$id] &&
- !$calls[$id]->{msg} &&
- $calls[$id]->{args} ne "void") {
- print " $calls[$id]->{args} val_$calls[$id]->{args};\n";
- }
- }
-}
-
-# Union of all arg types
-# ("remote_dispatch_ret.h").
-elsif ($opt_r) {
- for ($id = 0 ; $id <= $#calls ; $id++) {
- if (defined $calls[$id] &&
- !$calls[$id]->{msg} &&
- $calls[$id]->{ret} ne "void") {
- print " $calls[$id]->{ret} val_$calls[$id]->{ret};\n";
- }
- }
-}
-
-# Inside the switch statement, prepare the 'fn', 'args_filter', etc
-# ("remote_dispatch_table.h").
-elsif ($opt_t) {
- for ($id = 0 ; $id <= $#calls ; $id++) {
- if (defined $calls[$id] && !$calls[$id]->{msg}) {
- print "{ /* $calls[$id]->{ProcName} => $id */\n";
- print " .fn = (dispatch_fn) ${structprefix}Dispatch$calls[$id]->{ProcName},\n";
- if ($calls[$id]->{args} ne "void") {
- print " .args_filter = (xdrproc_t) xdr_$calls[$id]->{args},\n";
- } else {
- print " .args_filter = (xdrproc_t) xdr_void,\n";
- }
- if ($calls[$id]->{ret} ne "void") {
- print " .ret_filter = (xdrproc_t) xdr_$calls[$id]->{ret},\n";
- } else {
- print " .ret_filter = (xdrproc_t) xdr_void,\n";
- }
- print "},\n";
- } else {
- if ($calls[$id]->{msg}) {
- print "{ /* Async event $calls[$id]->{ProcName} => $id */\n";
- } else {
- print "{ /* (unused) => $id */\n";
- }
- print " .fn = NULL,\n";
- print " .args_filter = (xdrproc_t) xdr_void,\n";
- print " .ret_filter = (xdrproc_t) xdr_void,\n";
- print "},\n";
- }
- }
-}
-
# Bodies for dispatch functions ("remote_dispatch_bodies.h").
elsif ($opt_b) {
my %generate = map { $_ => 1 } @autogen;
# skip things which are REMOTE_MESSAGE
next if $call->{msg};
- # skip procedures not on generate list
- next if ! exists($generate{$call->{ProcName}});
+ my $name = $structprefix . "Dispatch" . $call->{ProcName};
+ my $argtype = $call->{args};
+ my $rettype = $call->{ret};
+
+ my $argann = $argtype ne "void" ? "" : " ATTRIBUTE_UNUSED";
+ my $retann = $rettype ne "void" ? "" : " ATTRIBUTE_UNUSED";
+
+ # First we print out a function declaration for the
+ # real dispatcher body
+ print "static int ${name}(\n";
+ print " virNetServerPtr server,\n";
+ print " virNetServerClientPtr client,\n";
+ print " virNetMessageHeaderPtr hdr,\n";
+ print " virNetMessageErrorPtr rerr";
+ if ($argtype ne "void") {
+ print ",\n $argtype *args";
+ }
+ if ($rettype ne "void") {
+ print ",\n $rettype *ret";
+ }
+ print ");\n";
+
+
+ # Next we print out a generic wrapper method which has
+ # 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 " virNetServerClientPtr client,\n";
+ print " virNetMessageHeaderPtr hdr,\n";
+ print " virNetMessageErrorPtr rerr,\n";
+ print " void *args$argann,\n";
+ print " void *ret$retann)\n";
+ print "{\n";
+ print " VIR_DEBUG(\"server=%p client=%p hdr=%p rerr=%p args=%p ret=%p\", server, client, hdr, rerr, args, ret);\n";
+ print " return $name(server, client, hdr, rerr";
+ if ($argtype ne "void") {
+ print ", args";
+ }
+ if ($rettype ne "void") {
+ print ", ret";
+ }
+ print ");\n";
+ print "}\n";
+
+ # Finally we print out the dispatcher method body impl
+ # (if possible)
+ if (!exists($generate{$call->{ProcName}})) {
+ print "/* ${structprefix}Dispatch$call->{ProcName} body has " .
+ "to be implemented manually */\n\n\n\n";
+ next;
+ }
my $has_node_device = 0;
my @vars_list = ();
my @prepare_ret_list = ();
my @ret_list = ();
my @free_list = ();
- my @free_list_on_error = ("remoteDispatchError(rerr);");
+ my @free_list_on_error = ("virNetMessageSaveError(rerr);");
# handle arguments to the function
- if ($call->{args} ne "void") {
+ if ($argtype ne "void") {
# node device is special, as it's identified by name
- if ($call->{args} =~ m/^remote_node_device_/ and
- !($call->{args} =~ m/^remote_node_device_lookup_by_name_/) and
- !($call->{args} =~ m/^remote_node_device_create_xml_/)) {
+ if ($argtype =~ m/^remote_node_device_/ and
+ !($argtype =~ m/^remote_node_device_lookup_by_name_/) and
+ !($argtype =~ m/^remote_node_device_create_xml_/)) {
$has_node_device = 1;
push(@vars_list, "virNodeDevicePtr dev = NULL");
push(@getters_list,
- " if (!(dev = virNodeDeviceLookupByName(conn, args->name)))\n" .
+ " if (!(dev = virNodeDeviceLookupByName(priv->conn, args->name)))\n" .
" goto cleanup;\n");
push(@args_list, "dev");
push(@free_list,
push(@vars_list, "vir${type_name}Ptr $2 = NULL");
push(@getters_list,
- " if (!($2 = get_nonnull_$1(conn, args->$2)))\n" .
+ " if (!($2 = get_nonnull_$1(priv->conn, args->$2)))\n" .
" goto cleanup;\n");
push(@args_list, "$2");
push(@free_list,
push(@vars_list, "virDomainPtr dom = NULL");
push(@vars_list, "virDomainSnapshotPtr snapshot = NULL");
push(@getters_list,
- " if (!(dom = get_nonnull_domain(conn, args->snap.dom)))\n" .
+ " if (!(dom = get_nonnull_domain(priv->conn, args->snap.dom)))\n" .
" goto cleanup;\n" .
"\n" .
" if (!(snapshot = get_nonnull_domain_snapshot(dom, args->snap)))\n" .
" virDomainFree(dom);");
} elsif ($args_member =~ m/^(?:remote_string|remote_uuid) (\S+)<\S+>;/) {
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
}
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, "conn");
+ push(@args_list, "priv->conn");
}
my $cast = "";
push(@args_list, "args->$arg_name.${arg_name}_len");
} elsif ($args_member =~ m/^(?:unsigned )?int (\S+)<\S+>;/) {
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
}
push(@args_list, "args->$1.$1_val");
die "unhandled type for argument value: $args_member";
} elsif ($args_member =~ m/^remote_uuid (\S+);/) {
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
}
push(@args_list, "(unsigned char *) args->$1");
} elsif ($args_member =~ m/^remote_string (\S+);/) {
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
}
push(@vars_list, "char *$1");
push(@args_list, "$1");
} elsif ($args_member =~ m/^remote_nonnull_string (\S+);/) {
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
}
push(@args_list, "args->$1");
} elsif ($args_member =~ m/^(unsigned )?int (\S+);/) {
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
}
push(@args_list, "args->$2");
} elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) {
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
}
my $arg_name = $2;
my $single_ret_list_max_define = "undefined";
my $multi_ret = 0;
- if ($call->{ret} ne "void" and
+ if ($rettype ne "void" and
scalar(@{$call->{ret_members}}) > 1) {
$multi_ret = 1;
}
- if ($call->{ret} ne "void") {
+ if ($rettype ne "void") {
foreach my $ret_member (@{$call->{ret_members}}) {
if ($multi_ret) {
if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) {
die "multi-return-value without insert@<offset> annotation: $call->{ret}";
}
- if (!@args_list) {
- push(@args_list, "conn");
+ if (! @args_list) {
+ push(@args_list, "priv->conn");
}
my $struct_name = $call->{ProcName};
}
if ($call->{streamflag} ne "none") {
- splice(@args_list, $call->{streamoffset}, 0, ("stream->st"));
+ splice(@args_list, $call->{streamoffset}, 0, ("st"));
push(@free_list_on_error, "if (stream) {");
- push(@free_list_on_error, " virStreamAbort(stream->st);");
- push(@free_list_on_error, " remoteFreeClientStream(client, stream);");
+ push(@free_list_on_error, " virStreamAbort(st);");
+ push(@free_list_on_error, " daemonFreeClientStream(client, stream);");
+ push(@free_list_on_error, "} else {");
+ push(@free_list_on_error, " virStreamFree(st);");
push(@free_list_on_error, "}");
}
# print functions signature
- print "\n";
- print "static int\n";
- print "${structprefix}Dispatch$call->{ProcName}(\n";
- print " struct qemud_server *server ATTRIBUTE_UNUSED,\n";
- print " struct qemud_client *client ATTRIBUTE_UNUSED,\n";
- print " virConnectPtr conn,\n";
- print " remote_message_header *hdr ATTRIBUTE_UNUSED,\n";
- print " remote_error *rerr,\n";
- print " $call->{args} *args";
-
- if ($call->{args} eq "void") {
- print " ATTRIBUTE_UNUSED"
- }
-
- print ",\n";
- print " $call->{ret} *ret";
-
- if ($call->{ret} eq "void") {
- print " ATTRIBUTE_UNUSED"
- }
-
- print ")\n";
+ print "static int $name(\n";
+ print " virNetServerPtr server ATTRIBUTE_UNUSED,\n";
+ print " virNetServerClientPtr client,\n";
+ print " virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,\n";
+ print " virNetMessageErrorPtr rerr";
+ if ($argtype ne "void") {
+ print ",\n $argtype *args";
+ }
+ if ($rettype ne "void") {
+ print ",\n $rettype *ret";
+ }
+ print ")\n";
# print function body
print "{\n";
foreach my $var (@vars_list) {
print " $var;\n";
}
+ print " struct daemonClientPrivate *priv =\n";
+ print " virNetServerClientGetPrivateData(client);\n";
if ($call->{streamflag} ne "none") {
- print " struct qemud_client_stream *stream = NULL;\n";
+ print " virStreamPtr st = NULL;\n";
+ print " daemonClientStreamPtr stream = NULL;\n";
}
print "\n";
- print " if (!conn) {\n";
+ print " if (!priv->conn) {\n";
print " virNetError(VIR_ERR_INTERNAL_ERROR, \"%s\", _(\"connection not open\"));\n";
print " goto cleanup;\n";
print " }\n";
}
if ($call->{streamflag} ne "none") {
- print " if (!(stream = remoteCreateClientStream(conn, hdr)))\n";
+ print " if (!(st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK)))\n";
+ print " goto cleanup;\n";
+ print "\n";
+ print " if (!(stream = daemonCreateClientStream(client, st, remoteProgram, hdr)))\n";
print " goto cleanup;\n";
print "\n";
}
- if ($call->{ret} eq "void") {
+ if ($rettype eq "void") {
print " if (vir$call->{ProcName}(";
print join(', ', @args_list);
print ") < 0)\n";
my $proc_name = $call->{ProcName};
if (! @args_list) {
- push(@args_list, "conn");
+ push(@args_list, "priv->conn");
if ($call->{ProcName} ne "NodeGetFreeMemory") {
$prefix = "Connect"
}
if ($call->{streamflag} ne "none") {
- print " if (remoteAddClientStream(client, stream, ";
+ print " if (daemonAddClientStream(client, stream, ";
if ($call->{streamflag} eq "write") {
- print "0";
+ print "false";
} else {
- print "1";
+ print "true";
}
print ") < 0)\n";
}
print " return rv;\n";
- print "}\n";
+ print "}\n\n\n\n";
+ }
+
+
+ # Finally we write out the huge dispatch table which lists
+ # the dispatch helper method. the XDR proc for processing
+ # args and return values, and the size of the args and
+ # return value structs. All methods are marked as requiring
+ # authentication. Methods are selectively relaxed in the
+ # daemon code which registers the program.
+
+ print "virNetServerProgramProc ${structprefix}Procs[] = {\n";
+ for ($id = 0 ; $id <= $#calls ; $id++) {
+ my ($comment, $name, $argtype, $arglen, $argfilter, $retlen, $retfilter);
+
+ if (defined $calls[$id] && !$calls[$id]->{msg}) {
+ $comment = "/* Method $calls[$id]->{ProcName} => $id */";
+ $name = $structprefix . "Dispatch" . $calls[$id]->{ProcName} . "Helper";
+ my $argtype = $calls[$id]->{args};
+ my $rettype = $calls[$id]->{ret};
+ $arglen = $argtype ne "void" ? "sizeof($argtype)" : "0";
+ $retlen = $rettype ne "void" ? "sizeof($rettype)" : "0";
+ $argfilter = $argtype ne "void" ? "xdr_$argtype" : "xdr_void";
+ $retfilter = $rettype ne "void" ? "xdr_$rettype" : "xdr_void";
+ } else {
+ if ($calls[$id]->{msg}) {
+ $comment = "/* Async event $calls[$id]->{ProcName} => $id */";
+ } else {
+ $comment = "/* Unused $id */";
+ }
+ $name = "NULL";
+ $arglen = $retlen = 0;
+ $argfilter = "xdr_void";
+ $retfilter = "xdr_void";
+ }
+
+ print "{ $comment\n ${name},\n $arglen,\n (xdrproc_t)$argfilter,\n $retlen,\n (xdrproc_t)$retfilter,\n true \n},\n";
}
+ print "};\n";
+ print "size_t ${structprefix}NProcs = ARRAY_CARDINALITY(${structprefix}Procs);\n";
}
# Bodies for client functions ("remote_client_bodies.h").
# skip procedures not on generate list
next if ! exists($generate{$call->{ProcName}});
+ my $argtype = $call->{args};
+ my $rettype = $call->{ret};
+
# handle arguments to the function
my @args_list = ();
my @vars_list = ();
my $priv_name = "privateData";
my $call_args = "&args";
- if ($call->{args} eq "void") {
+ if ($argtype eq "void") {
$call_args = "NULL";
} else {
- push(@vars_list, "$call->{args} args");
+ push(@vars_list, "$argtype args");
my $is_first_arg = 1;
my $has_node_device = 0;
# node device is special
- if ($call->{args} =~ m/^remote_node_/ and
- !($call->{args} =~ m/^remote_node_device_lookup_by_name_/) and
- !($call->{args} =~ m/^remote_node_device_create_xml_/)) {
+ if ($argtype =~ m/^remote_node_/ and
+ !($argtype =~ m/^remote_node_device_lookup_by_name_/) and
+ !($argtype =~ m/^remote_node_device_create_xml_/)) {
$has_node_device = 1;
$priv_name = "devMonPrivateData";
}
my $single_ret_cleanup = 0;
my $multi_ret = 0;
- if ($call->{ret} ne "void" and
+ if ($rettype ne "void" and
scalar(@{$call->{ret_members}}) > 1) {
$multi_ret = 1;
}
- if ($call->{ret} eq "void") {
+ if ($rettype eq "void") {
$call_ret = "NULL";
} else {
- push(@vars_list, "$call->{ret} ret");
+ push(@vars_list, "$rettype ret");
foreach my $ret_member (@{$call->{ret_members}}) {
if ($multi_ret) {
push(@ret_list, "rv = get_nonnull_$name($priv_src, ret.$arg_name);");
}
- push(@ret_list, "xdr_free((xdrproc_t)xdr_$call->{ret}, (char *)&ret);");
+ push(@ret_list, "xdr_free((xdrproc_t)xdr_$rettype, (char *)&ret);");
$single_ret_var = "vir${type_name}Ptr rv = NULL";
$single_ret_type = "vir${type_name}Ptr";
}
print "\n";
}
- if ($call->{ret} ne "void") {
+ if ($rettype ne "void") {
print "\n";
print " memset(&ret, 0, sizeof ret);\n";
}
print "\n";
print " if (call($priv_src, priv, 0, ${procprefix}_PROC_$call->{UC_NAME},\n";
- print " (xdrproc_t)xdr_$call->{args}, (char *)$call_args,\n";
- print " (xdrproc_t)xdr_$call->{ret}, (char *)$call_ret) == -1) {\n";
+ print " (xdrproc_t)xdr_$argtype, (char *)$call_args,\n";
+ print " (xdrproc_t)xdr_$rettype, (char *)$call_ret) == -1) {\n";
if ($call->{streamflag} ne "none") {
print " virNetClientRemoveStream(priv->client, netst);\n";
if (!msg)
return;
+ if (msg->cb)
+ msg->cb(msg, msg->opaque);
+
VIR_DEBUG("msg=%p", msg);
VIR_FREE(msg);
typedef struct _virNetMessage virNetMessage;
typedef virNetMessage *virNetMessagePtr;
+typedef void (*virNetMessageFreeCallback)(virNetMessagePtr msg, void *opaque);
+
/* Never allocate this (huge) buffer on the stack. Always
* use virNetMessageNew() to allocate on the heap
*/
virNetMessageHeader header;
+ virNetMessageFreeCallback cb;
+ void *opaque;
+
virNetMessagePtr next;
};