[libvirt] [00/15] Re-factoring XDR RPC code v2

A followup to http://www.redhat.com/archives/libvir-list/2010-December/msg00051.html Since that time - The SASL/TLS I/O code has been integrated into the virNetSocket class directly to remove duplication between client&servers - libvirtd has been converted to use the new APIs - Error handling has been sanitized across libvirtd to use the normal virReportError APIs - A couple of test cases have been written - Many locking, ref counting & ramdom crash bugs fixed - Some basic interoperability testing against previous code This is still not quite functionally complete, so not ready to apply. The missing pieces are - Make the client side streams code work again - Re-integrate DTrace probes in libvirtd Daniel

This patch defines the basics of a generic RPC protocol in XDR. This is wire ABI compatible with the original remote_protocol.x. It takes everything except for the RPC calls / events from that protocol - The basic header virNetMessageHeader (aka remote_message_header) - The error object virNetMessageError (aka remote_error) - Two dummy objects virNetMessageDomain & virNetMessageNetwork sadly needed to keep virNetMessageError ABI compatible with the old remote_error The RPC protocol supports method calls, async events and bidirectional data streams as before * src/Makefile.am: Add rules for generating RPC code from protocol & define a new libvirt-net-rpc.la helper library * src/rpc/virnetprotocol.x: New generic RPC protocol * src/rpc/virnetprotocol.c, src/rpc/virnetprotocol.h: Generated from virnetprotocol.x --- .x-sc_preprocessor_indentation | 1 + Makefile.am | 1 + src/Makefile.am | 34 ++++++- src/rpc/virnetprotocol.c | 206 ++++++++++++++++++++++++++++++++++++++ src/rpc/virnetprotocol.h | 136 +++++++++++++++++++++++++ src/rpc/virnetprotocol.x | 214 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 591 insertions(+), 1 deletions(-) create mode 100644 .x-sc_preprocessor_indentation create mode 100644 src/rpc/virnetprotocol.c create mode 100644 src/rpc/virnetprotocol.h create mode 100644 src/rpc/virnetprotocol.x diff --git a/.x-sc_preprocessor_indentation b/.x-sc_preprocessor_indentation new file mode 100644 index 0000000..30273f8 --- /dev/null +++ b/.x-sc_preprocessor_indentation @@ -0,0 +1 @@ +src/rpc/virnetprotocol.h \ No newline at end of file diff --git a/Makefile.am b/Makefile.am index c525e65..a400f59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,7 @@ syntax_check_exceptions = \ .x-sc_bindtextdomain \ .x-sc_m4_quote_check \ .x-sc_po_check \ + .x-sc_preprocessor_indentation \ .x-sc_prohibit_always_true_header_tests \ .x-sc_prohibit_asprintf \ .x-sc_prohibit_close \ diff --git a/src/Makefile.am b/src/Makefile.am index 196d8af..8837b43 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -531,6 +531,24 @@ else mv -f rp_qemu.c-t $(srcdir)/remote/qemu_protocol.c endif +rpcgen-net: + rm -f rp_net.c-t rp_net.h-t rp_net.c-t1 rp_net.c-t2 rp_net.h-t1 + $(RPCGEN) -h -o rp_net.h-t $(srcdir)/rpc/virnetprotocol.x + $(RPCGEN) -c -o rp_net.c-t $(srcdir)/rpc/virnetprotocol.x +if HAVE_GLIBC_RPCGEN + perl -w $(srcdir)/remote/rpcgen_fix.pl rp_net.h-t > rp_net.h-t1 + perl -w $(srcdir)/remote/rpcgen_fix.pl rp_net.c-t > rp_net.c-t1 + (echo '#include <config.h>'; cat rp_net.c-t1) > rp_net.c-t2 + chmod 0444 rp_net.c-t2 rp_net.h-t1 + mv -f rp_net.h-t1 $(srcdir)/rpc/virnetprotocol.h + mv -f rp_net.c-t2 $(srcdir)/rpc/virnetprotocol.c + rm -f rp_net.c-t rp_net.h-t rp_net.c-t1 +else + chmod 0444 rp_net.c-t rp_net.h-t + mv -f rp_net.h-t $(srcdir)/rpc/virnetprotocol.h + mv -f rp_net.c-t $(srcdir)/rpc/virnetprotocol.c +endif + # # Maintainer-only target for re-generating the derived .c/.h source # files, which are actually derived from the .x file. @@ -541,7 +559,7 @@ endif # Support for non-GLIB rpcgen is here as a convenience for # non-Linux people needing to test changes during dev. # -rpcgen: rpcgen-normal rpcgen-qemu +rpcgen: rpcgen-normal rpcgen-qemu rpcgen-net endif @@ -1099,6 +1117,20 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS) libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD) EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) + +noinst_LTLIBRARIES += libvirt-net-rpc.la + +libvirt_net_rpc_la_SOURCES = \ + rpc/virnetprotocol.h rpc/virnetprotocol.c +libvirt_net_rpc_la_CFLAGS = \ + $(AM_CFLAGS) +libvirt_net_rpc_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(CYGWIN_EXTRA_LDFLAGS) \ + $(MINGW_EXTRA_LDFLAGS) +libvirt_net_rpc_la_LIBADD = \ + $(CYGWIN_EXTRA_LIBADD) + libexec_PROGRAMS = if WITH_STORAGE_DISK diff --git a/src/rpc/virnetprotocol.c b/src/rpc/virnetprotocol.c new file mode 100644 index 0000000..7fce16d --- /dev/null +++ b/src/rpc/virnetprotocol.c @@ -0,0 +1,206 @@ +#include <config.h> +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "./rpc/virnetprotocol.h" +#include "internal.h" +#ifdef HAVE_XDR_U_INT64_T +# define xdr_uint64_t xdr_u_int64_t +#endif +#ifndef IXDR_PUT_INT32 +# define IXDR_PUT_INT32 IXDR_PUT_LONG +#endif +#ifndef IXDR_GET_INT32 +# define IXDR_GET_INT32 IXDR_GET_LONG +#endif +#ifndef IXDR_PUT_U_INT32 +# define IXDR_PUT_U_INT32 IXDR_PUT_U_LONG +#endif +#ifndef IXDR_GET_U_INT32 +# define IXDR_GET_U_INT32 IXDR_GET_U_LONG +#endif + +bool_t +xdr_virNetMessageType (XDR *xdrs, virNetMessageType *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageStatus (XDR *xdrs, virNetMessageStatus *objp) +{ + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageHeader (XDR *xdrs, virNetMessageHeader *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_int (xdrs, &objp->proc)) + return FALSE; + + } else { + (void)IXDR_PUT_U_INT32(buf, objp->prog); + (void)IXDR_PUT_U_INT32(buf, objp->vers); + (void)IXDR_PUT_INT32(buf, objp->proc); + } + if (!xdr_virNetMessageType (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->serial)) + return FALSE; + if (!xdr_virNetMessageStatus (xdrs, &objp->status)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_int (xdrs, &objp->proc)) + return FALSE; + + } else { + objp->prog = IXDR_GET_U_LONG(buf); + objp->vers = IXDR_GET_U_LONG(buf); + objp->proc = IXDR_GET_INT32(buf); + } + if (!xdr_virNetMessageType (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->serial)) + return FALSE; + if (!xdr_virNetMessageStatus (xdrs, &objp->status)) + return FALSE; + return TRUE; + } + + if (!xdr_u_int (xdrs, &objp->prog)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->vers)) + return FALSE; + if (!xdr_int (xdrs, &objp->proc)) + return FALSE; + if (!xdr_virNetMessageType (xdrs, &objp->type)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->serial)) + return FALSE; + if (!xdr_virNetMessageStatus (xdrs, &objp->status)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageUUID (XDR *xdrs, virNetMessageUUID objp) +{ + + if (!xdr_opaque (xdrs, objp, VIR_UUID_BUFLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageNonnullString (XDR *xdrs, virNetMessageNonnullString *objp) +{ + + if (!xdr_string (xdrs, objp, VIR_NET_MESSAGE_STRING_MAX)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageString (XDR *xdrs, virNetMessageString *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (virNetMessageNonnullString), (xdrproc_t) xdr_virNetMessageNonnullString)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageNonnullDomain (XDR *xdrs, virNetMessageNonnullDomain *objp) +{ + + if (!xdr_virNetMessageNonnullString (xdrs, &objp->name)) + return FALSE; + if (!xdr_virNetMessageUUID (xdrs, objp->uuid)) + return FALSE; + if (!xdr_int (xdrs, &objp->id)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageNonnullNetwork (XDR *xdrs, virNetMessageNonnullNetwork *objp) +{ + + if (!xdr_virNetMessageNonnullString (xdrs, &objp->name)) + return FALSE; + if (!xdr_virNetMessageUUID (xdrs, objp->uuid)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageDomain (XDR *xdrs, virNetMessageDomain *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (virNetMessageNonnullDomain), (xdrproc_t) xdr_virNetMessageNonnullDomain)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageNetwork (XDR *xdrs, virNetMessageNetwork *objp) +{ + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (virNetMessageNonnullNetwork), (xdrproc_t) xdr_virNetMessageNonnullNetwork)) + return FALSE; + return TRUE; +} + +bool_t +xdr_virNetMessageError (XDR *xdrs, virNetMessageError *objp) +{ + + if (!xdr_int (xdrs, &objp->code)) + return FALSE; + if (!xdr_int (xdrs, &objp->domain)) + return FALSE; + if (!xdr_virNetMessageString (xdrs, &objp->message)) + return FALSE; + if (!xdr_int (xdrs, &objp->level)) + return FALSE; + if (!xdr_virNetMessageDomain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_virNetMessageString (xdrs, &objp->str1)) + return FALSE; + if (!xdr_virNetMessageString (xdrs, &objp->str2)) + return FALSE; + if (!xdr_virNetMessageString (xdrs, &objp->str3)) + return FALSE; + if (!xdr_int (xdrs, &objp->int1)) + return FALSE; + if (!xdr_int (xdrs, &objp->int2)) + return FALSE; + if (!xdr_virNetMessageNetwork (xdrs, &objp->net)) + return FALSE; + return TRUE; +} diff --git a/src/rpc/virnetprotocol.h b/src/rpc/virnetprotocol.h new file mode 100644 index 0000000..9f4a79a --- /dev/null +++ b/src/rpc/virnetprotocol.h @@ -0,0 +1,136 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _RP_NET_H_RPCGEN +#define _RP_NET_H_RPCGEN + +#include <rpc/rpc.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "internal.h" +#ifdef HAVE_XDR_U_INT64_T +# define xdr_uint64_t xdr_u_int64_t +#endif +#ifndef IXDR_PUT_INT32 +# define IXDR_PUT_INT32 IXDR_PUT_LONG +#endif +#ifndef IXDR_GET_INT32 +# define IXDR_GET_INT32 IXDR_GET_LONG +#endif +#ifndef IXDR_PUT_U_INT32 +# define IXDR_PUT_U_INT32 IXDR_PUT_U_LONG +#endif +#ifndef IXDR_GET_U_INT32 +# define IXDR_GET_U_INT32 IXDR_GET_U_LONG +#endif +#define VIR_NET_MESSAGE_MAX 262144 +#define VIR_NET_MESSAGE_HEADER_MAX 24 +#define VIR_NET_MESSAGE_PAYLOAD_MAX 262120 +#define VIR_NET_MESSAGE_LEN_MAX 4 +#define VIR_NET_MESSAGE_STRING_MAX 65536 + +enum virNetMessageType { + VIR_NET_CALL = 0, + VIR_NET_REPLY = 1, + VIR_NET_MESSAGE = 2, + VIR_NET_STREAM = 3, +}; +typedef enum virNetMessageType virNetMessageType; + +enum virNetMessageStatus { + VIR_NET_OK = 0, + VIR_NET_ERROR = 1, + VIR_NET_CONTINUE = 2, +}; +typedef enum virNetMessageStatus virNetMessageStatus; +#define VIR_NET_MESSAGE_HEADER_XDR_LEN 4 + +struct virNetMessageHeader { + u_int prog; + u_int vers; + int proc; + virNetMessageType type; + u_int serial; + virNetMessageStatus status; +}; +typedef struct virNetMessageHeader virNetMessageHeader; + +typedef char virNetMessageUUID[VIR_UUID_BUFLEN]; + +typedef char *virNetMessageNonnullString; + +typedef virNetMessageNonnullString *virNetMessageString; + +struct virNetMessageNonnullDomain { + virNetMessageNonnullString name; + virNetMessageUUID uuid; + int id; +}; +typedef struct virNetMessageNonnullDomain virNetMessageNonnullDomain; + +struct virNetMessageNonnullNetwork { + virNetMessageNonnullString name; + virNetMessageUUID uuid; +}; +typedef struct virNetMessageNonnullNetwork virNetMessageNonnullNetwork; + +typedef virNetMessageNonnullDomain *virNetMessageDomain; + +typedef virNetMessageNonnullNetwork *virNetMessageNetwork; + +struct virNetMessageError { + int code; + int domain; + virNetMessageString message; + int level; + virNetMessageDomain dom; + virNetMessageString str1; + virNetMessageString str2; + virNetMessageString str3; + int int1; + int int2; + virNetMessageNetwork net; +}; +typedef struct virNetMessageError virNetMessageError; + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_virNetMessageType (XDR *, virNetMessageType*); +extern bool_t xdr_virNetMessageStatus (XDR *, virNetMessageStatus*); +extern bool_t xdr_virNetMessageHeader (XDR *, virNetMessageHeader*); +extern bool_t xdr_virNetMessageUUID (XDR *, virNetMessageUUID); +extern bool_t xdr_virNetMessageNonnullString (XDR *, virNetMessageNonnullString*); +extern bool_t xdr_virNetMessageString (XDR *, virNetMessageString*); +extern bool_t xdr_virNetMessageNonnullDomain (XDR *, virNetMessageNonnullDomain*); +extern bool_t xdr_virNetMessageNonnullNetwork (XDR *, virNetMessageNonnullNetwork*); +extern bool_t xdr_virNetMessageDomain (XDR *, virNetMessageDomain*); +extern bool_t xdr_virNetMessageNetwork (XDR *, virNetMessageNetwork*); +extern bool_t xdr_virNetMessageError (XDR *, virNetMessageError*); + +#else /* K&R C */ +extern bool_t xdr_virNetMessageType (); +extern bool_t xdr_virNetMessageStatus (); +extern bool_t xdr_virNetMessageHeader (); +extern bool_t xdr_virNetMessageUUID (); +extern bool_t xdr_virNetMessageNonnullString (); +extern bool_t xdr_virNetMessageString (); +extern bool_t xdr_virNetMessageNonnullDomain (); +extern bool_t xdr_virNetMessageNonnullNetwork (); +extern bool_t xdr_virNetMessageDomain (); +extern bool_t xdr_virNetMessageNetwork (); +extern bool_t xdr_virNetMessageError (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_RP_NET_H_RPCGEN */ diff --git a/src/rpc/virnetprotocol.x b/src/rpc/virnetprotocol.x new file mode 100644 index 0000000..10ece6f --- /dev/null +++ b/src/rpc/virnetprotocol.x @@ -0,0 +1,214 @@ +/* -*- c -*- + * virnetprotocol.x: basic protocol for all RPC services. + * + * Copyright (C) 2006-2010 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 Jones <rjones@redhat.com> + */ + +%#include "internal.h" + +/* cygwin's xdr implementation defines xdr_u_int64_t instead of xdr_uint64_t + * and lacks IXDR_PUT_INT32 and IXDR_GET_INT32 + */ +%#ifdef HAVE_XDR_U_INT64_T +%# define xdr_uint64_t xdr_u_int64_t +%#endif +%#ifndef IXDR_PUT_INT32 +%# define IXDR_PUT_INT32 IXDR_PUT_LONG +%#endif +%#ifndef IXDR_GET_INT32 +%# define IXDR_GET_INT32 IXDR_GET_LONG +%#endif +%#ifndef IXDR_PUT_U_INT32 +%# define IXDR_PUT_U_INT32 IXDR_PUT_U_LONG +%#endif +%#ifndef IXDR_GET_U_INT32 +%# define IXDR_GET_U_INT32 IXDR_GET_U_LONG +%#endif + +/*----- Data types. -----*/ + +/* Maximum total message size (serialised). */ +const VIR_NET_MESSAGE_MAX = 262144; + +/* Size of struct virNetMessageHeader (serialized)*/ +const VIR_NET_MESSAGE_HEADER_MAX = 24; + +/* Size of message payload */ +const VIR_NET_MESSAGE_PAYLOAD_MAX = 262120; + +/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX */ +const VIR_NET_MESSAGE_LEN_MAX = 4; + +const VIR_NET_MESSAGE_STRING_MAX = 65536; + +/* + * RPC wire format + * + * Each message consists of: + * + * Name | Type | Description + * -----------+-----------------------+------------------ + * Length | int | Total number of bytes in message _including_ length. + * Header | virNetMessageHeader | Control information about procedure call + * Payload | - | Variable payload data per procedure + * + * In header, the 'serial' field varies according to: + * + * - type == VIR_NET_CALL + * * serial is set by client, incrementing by 1 each time + * + * - type == VIR_NET_REPLY + * * serial matches that from the corresponding VIR_NET_CALL + * + * - type == VIR_NET_MESSAGE + * * serial is always zero + * + * - type == VIR_NET_STREAM + * * serial matches that from the corresponding VIR_NET_CALL + * + * and the 'status' field varies according to: + * + * - type == VIR_NET_CALL + * * VIR_NET_OK always + * + * - type == VIR_NET_REPLY + * * VIR_NET_OK if RPC finished successfully + * * VIR_NET_ERROR if something failed + * + * - type == VIR_NET_MESSAGE + * * VIR_NET_OK always + * + * - type == VIR_NET_STREAM + * * VIR_NET_CONTINUE if more data is following + * * VIR_NET_OK if stream is complete + * * VIR_NET_ERROR if stream had an error + * + * Payload varies according to type and status: + * + * - type == VIR_NET_CALL + * XXX_args for procedure + * + * - type == VIR_NET_REPLY + * * status == VIR_NET_OK + * XXX_ret for procedure + * * status == VIR_NET_ERROR + * remote_error Error information + * + * - type == VIR_NET_MESSAGE + * * status == VIR_NET_OK + * XXX_args for procedure + * * status == VIR_NET_ERROR + * remote_error Error information + * + * - type == VIR_NET_STREAM + * * status == VIR_NET_CONTINUE + * byte[] raw stream data + * * status == VIR_NET_ERROR + * remote_error error information + * * status == VIR_NET_OK + * <empty> + */ +enum virNetMessageType { + /* client -> server. args from a method call */ + VIR_NET_CALL = 0, + /* server -> client. reply/error from a method call */ + VIR_NET_REPLY = 1, + /* either direction. async notification */ + VIR_NET_MESSAGE = 2, + /* either direction. stream data packet */ + VIR_NET_STREAM = 3 +}; + +enum virNetMessageStatus { + /* Status is always VIR_NET_OK for calls. + * For replies, indicates no error. + */ + VIR_NET_OK = 0, + + /* For replies, indicates that an error happened, and a struct + * remote_error follows. + */ + VIR_NET_ERROR = 1, + + /* For streams, indicates that more data is still expected + */ + VIR_NET_CONTINUE = 2 +}; + +/* 4 byte length word per header */ +const VIR_NET_MESSAGE_HEADER_XDR_LEN = 4; + +struct virNetMessageHeader { + unsigned prog; /* Unique ID for the program */ + unsigned vers; /* Program version number */ + int proc; /* Unique ID for the procedure within the program */ + virNetMessageType type; /* Type of message */ + unsigned serial; /* Serial number of message. */ + virNetMessageStatus status; +}; + +/* Error message. See <virterror.h> for explanation of fields. */ + +/* Most of these don't really belong here. There are sadly needed + * for wire ABI backwards compatibility with the rather crazy + * error struct we previously defined :-( + */ + +typedef opaque virNetMessageUUID[VIR_UUID_BUFLEN]; +typedef string virNetMessageNonnullString<VIR_NET_MESSAGE_STRING_MAX>; + +/* A long string, which may be NULL. */ +typedef virNetMessageNonnullString *virNetMessageString; + +/* A domain which may not be NULL. */ +struct virNetMessageNonnullDomain { + virNetMessageNonnullString name; + virNetMessageUUID uuid; + int id; +}; + +/* A network which may not be NULL. */ +struct virNetMessageNonnullNetwork { + virNetMessageNonnullString name; + virNetMessageUUID uuid; +}; + + +typedef virNetMessageNonnullDomain *virNetMessageDomain; +typedef virNetMessageNonnullNetwork *virNetMessageNetwork; + +/* NB. Fields "code", "domain" and "level" are really enums. The + * numeric value should remain compatible between libvirt and + * libvirtd. This means, no changing or reordering the enums as + * defined in <virterror.h> (but we don't do that anyway, for separate + * ABI reasons). + */ +struct virNetMessageError { + int code; + int domain; + virNetMessageString message; + int level; + virNetMessageDomain dom; /* unused */ + virNetMessageString str1; + virNetMessageString str2; + virNetMessageString str3; + int int1; + int int2; + virNetMessageNetwork net; /* unused */ +}; -- 1.7.2.3

On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
This patch defines the basics of a generic RPC protocol in XDR. This is wire ABI compatible with the original remote_protocol.x. diff --git a/.x-sc_preprocessor_indentation b/.x-sc_preprocessor_indentation new file mode 100644 index 0000000..30273f8 --- /dev/null +++ b/.x-sc_preprocessor_indentation @@ -0,0 +1 @@ +src/rpc/virnetprotocol.h \ No newline at end of file
This file should have had a newline, if it is even needed. However, I think that you are better off changing preprocessor_exempt in cfg.mk instead of adding this file.
diff --git a/Makefile.am b/Makefile.am index c525e65..a400f59 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,7 @@ syntax_check_exceptions = \ .x-sc_bindtextdomain \ .x-sc_m4_quote_check \ .x-sc_po_check \ + .x-sc_preprocessor_indentation \
Which means you also don't need this change.
diff --git a/src/rpc/virnetprotocol.x b/src/rpc/virnetprotocol.x new file mode 100644 index 0000000..10ece6f --- /dev/null +++ b/src/rpc/virnetprotocol.x + +/*----- Data types. -----*/ + +/* Maximum total message size (serialised). */ +const VIR_NET_MESSAGE_MAX = 262144; + +/* Size of struct virNetMessageHeader (serialized)*/
Love the comment copy-and-paste inconsistency from remote_protocol.x (-sed vs. -zed).
+const VIR_NET_MESSAGE_HEADER_MAX = 24; + +/* Size of message payload */ +const VIR_NET_MESSAGE_PAYLOAD_MAX = 262120;
Would it be better to write VIR_NET_MESSAGE_PAYLOAD_MAX = VIR_NET_MESSAGE_MAX - VIR_NET_MESSAGE_HEADER_MAX? But that's just cosmetic.
+ +/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX */ +const VIR_NET_MESSAGE_LEN_MAX = 4; + +const VIR_NET_MESSAGE_STRING_MAX = 65536;
You lost a useful comment from remote_protocol.h: /* Length of long, but not unbounded, strings. * This is an arbitrary limit designed to stop the decoder from trying * to allocate unbounded amounts of memory when fed with a bad message. */
+ * and the 'status' field varies according to: + * + * - type == VIR_NET_CALL + * * VIR_NET_OK always + * + * - type == VIR_NET_REPLY + * * VIR_NET_OK if RPC finished successfully + * * VIR_NET_ERROR if something failed + * + * - type == VIR_NET_MESSAGE + * * VIR_NET_OK always + * + * - type == VIR_NET_STREAM + * * VIR_NET_CONTINUE if more data is following + * * VIR_NET_OK if stream is complete + * * VIR_NET_ERROR if stream had an error + * + * Payload varies according to type and status: + * + * - type == VIR_NET_CALL + * XXX_args for procedure + * + * - type == VIR_NET_REPLY + * * status == VIR_NET_OK + * XXX_ret for procedure + * * status == VIR_NET_ERROR + * remote_error Error information + * + * - type == VIR_NET_MESSAGE + * * status == VIR_NET_OK + * XXX_args for procedure + * * status == VIR_NET_ERROR + * remote_error Error information
This is pure copy-and-paste from remote_protocol.x, but it doesnt' make sense to me. Earlier, you said that VIR_NET_MESSAGE implies status is VIR_NET_OK always, and that messages are asynchronous, rather than in reply to a message. Either this should be: - type == VIR_NET_MESSAGE XXX_msg according to proc or you need to allow for VIR_NET_MESSAGE to pass status==VIR_NET_ERROR. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Thu, Dec 16, 2010 at 08:27:23AM -0700, Eric Blake wrote:
On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
+const VIR_NET_MESSAGE_HEADER_MAX = 24; + +/* Size of message payload */ +const VIR_NET_MESSAGE_PAYLOAD_MAX = 262120;
Would it be better to write VIR_NET_MESSAGE_PAYLOAD_MAX = VIR_NET_MESSAGE_MAX - VIR_NET_MESSAGE_HEADER_MAX? But that's just cosmetic.
Unfortunately you can use expressions when defining XDR constants.
+ +/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX */ +const VIR_NET_MESSAGE_LEN_MAX = 4; + +const VIR_NET_MESSAGE_STRING_MAX = 65536;
You lost a useful comment from remote_protocol.h:
/* Length of long, but not unbounded, strings. * This is an arbitrary limit designed to stop the decoder from trying * to allocate unbounded amounts of memory when fed with a bad message. */
Yeah, I didn't even really want these bits of the protocol, but backcompat for the error struct forced me to copy them in.
+ * and the 'status' field varies according to: + * + * - type == VIR_NET_CALL + * * VIR_NET_OK always + * + * - type == VIR_NET_REPLY + * * VIR_NET_OK if RPC finished successfully + * * VIR_NET_ERROR if something failed + * + * - type == VIR_NET_MESSAGE + * * VIR_NET_OK always + * + * - type == VIR_NET_STREAM + * * VIR_NET_CONTINUE if more data is following + * * VIR_NET_OK if stream is complete + * * VIR_NET_ERROR if stream had an error + * + * Payload varies according to type and status: + * + * - type == VIR_NET_CALL + * XXX_args for procedure + * + * - type == VIR_NET_REPLY + * * status == VIR_NET_OK + * XXX_ret for procedure + * * status == VIR_NET_ERROR + * remote_error Error information + * + * - type == VIR_NET_MESSAGE + * * status == VIR_NET_OK + * XXX_args for procedure + * * status == VIR_NET_ERROR + * remote_error Error information
This is pure copy-and-paste from remote_protocol.x, but it doesnt' make sense to me. Earlier, you said that VIR_NET_MESSAGE implies status is VIR_NET_OK always, and that messages are asynchronous, rather than in reply to a message. Either this should be:
- type == VIR_NET_MESSAGE XXX_msg according to proc
Yeah that's the correct one. There are no errors associated with async events.
or you need to allow for VIR_NET_MESSAGE to pass status==VIR_NET_ERROR.
Daniel

This provides a new struct that contains a buffer for the RPC message header+payload, as well as a decoded copy of the message header. There is an API for applying a XDR encoding & decoding of the message headers and payloads. There are also APIs for maintaining a simple FIFO queue of message instances. Expected usage scenarios are: To send a message msg = virNetMessageNew() ...fill in msg->header fields.. virNetMessageEncodeHeader(msg) ...loook at msg->header fields to determine payload filter virNetMessageEncodePayload(msg, xdrfilter, data) ...send msg->bufferLength worth of data from buffer To receive a message msg = virNetMessageNew() ...read VIR_NET_MESSAGE_LEN_MAX of data into buffer virNetMessageDecodeLength(msg) ...read msg->bufferLength-msg->bufferOffset of data into buffer virNetMessageDecodeHeader(msg) ...look at msg->header fields to determine payload filter virNetMessageDecodePayload(msg, xdrfilter, data) ...run payload processor * src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetmessage.c, src/rpc/virnetmessage.h: Internal message handling API. --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/rpc/virnetmessage.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetmessage.h | 68 ++++++++++ 4 files changed, 395 insertions(+), 0 deletions(-) create mode 100644 src/rpc/virnetmessage.c create mode 100644 src/rpc/virnetmessage.h diff --git a/po/POTFILES.in b/po/POTFILES.in index e7be0d3..c79234a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -58,6 +58,7 @@ src/qemu/qemu_monitor_json.c src/qemu/qemu_monitor_text.c src/qemu/qemu_security_dac.c src/remote/remote_driver.c +src/rpc/virnetmessage.c src/secret/secret_driver.c src/security/security_apparmor.c src/security/security_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index 8837b43..daf7643 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1121,6 +1121,7 @@ EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt_net_rpc_la_SOURCES = \ + rpc/virnetmessage.h rpc/virnetmessage.c \ rpc/virnetprotocol.h rpc/virnetprotocol.c libvirt_net_rpc_la_CFLAGS = \ $(AM_CFLAGS) diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c new file mode 100644 index 0000000..c675cfa --- /dev/null +++ b/src/rpc/virnetmessage.c @@ -0,0 +1,325 @@ +/* + * virnetmessage.h: basic RPC message encoding/decoding + * + * Copyright (C) 2010 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 + */ + +#include <config.h> + +#include "virnetmessage.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" + +#define VIR_FROM_THIS VIR_FROM_RPC +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +virNetMessagePtr virNetMessageNew(void) +{ + virNetMessagePtr msg; + + if (VIR_ALLOC(msg) < 0) { + virReportOOMError(); + return NULL; + } + + VIR_DEBUG("msg=%p", msg); + + return msg; +} + +void virNetMessageFree(virNetMessagePtr msg) +{ + if (!msg) + return; + + VIR_DEBUG("msg=%p", msg); + + VIR_FREE(msg); +} + +void virNetMessageQueuePush(virNetMessagePtr *queue, virNetMessagePtr msg) +{ + virNetMessagePtr tmp = *queue; + + if (tmp) { + while (tmp->next) + tmp = tmp->next; + tmp->next = msg; + } else { + *queue = msg; + } +} + + +virNetMessagePtr virNetMessageQueueServe(virNetMessagePtr *queue) +{ + virNetMessagePtr tmp = *queue; + + if (tmp) { + *queue = tmp->next; + tmp->next = NULL; + } + + return tmp; +} + + +int virNetMessageDecodeLength(virNetMessagePtr msg) +{ + XDR xdr; + unsigned int len; + int ret = -1; + + xdrmem_create(&xdr, msg->buffer, + msg->bufferLength, XDR_DECODE); + if (!xdr_u_int(&xdr, &len)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to decode message length")); + goto cleanup; + } + msg->bufferOffset = xdr_getpos(&xdr); + + if (len < VIR_NET_MESSAGE_LEN_MAX) { + virNetError(VIR_ERR_RPC, "%s", + _("packet received from server too small")); + goto cleanup; + } + + /* Length includes length word - adjust to real length to read. */ + len -= VIR_NET_MESSAGE_LEN_MAX; + + if (len > VIR_NET_MESSAGE_MAX) { + virNetError(VIR_ERR_RPC, "%s", + _("packet received from server too large")); + goto cleanup; + } + + /* Extend our declared buffer length and carry + on reading the header + payload */ + msg->bufferLength += len; + + VIR_DEBUG("Got length, now need %zu total (%u more)", + msg->bufferLength, len); + + ret = 0; + +cleanup: + xdr_destroy(&xdr); + return ret; +} + + +/* + * @msg: the complete incoming message, whose header to decode + * + * Decodes the header part of the 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 virNetMessageDecodeHeader(virNetMessagePtr msg) +{ + XDR xdr; + int ret = -1; + + msg->bufferOffset = VIR_NET_MESSAGE_LEN_MAX; + + /* Parse the header. */ + xdrmem_create(&xdr, + msg->buffer + msg->bufferOffset, + msg->bufferLength - msg->bufferOffset, + XDR_DECODE); + + if (!xdr_virNetMessageHeader(&xdr, &msg->header)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to decode message header")); + 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 length word and header of the 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 virNetMessageEncodeHeader(virNetMessagePtr 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)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message length")); + goto cleanup; + } + + if (!xdr_virNetMessageHeader(&xdr, &msg->header)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message header")); + 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)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to re-encode message length")); + goto cleanup; + } + + msg->bufferOffset += len; + + ret = 0; + +cleanup: + xdr_destroy(&xdr); + return ret; +} + + +int virNetMessageEncodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data) +{ + XDR xdr; + unsigned int msglen; + + /* Serialise header followed by args. */ + xdrmem_create(&xdr, msg->buffer + msg->bufferOffset, + msg->bufferLength - msg->bufferOffset, XDR_ENCODE); + + if (!(*filter)(&xdr, data)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message payload")); + goto error; + } + + /* Get the length stored in buffer. */ + msg->bufferOffset += xdr_getpos(&xdr); + xdr_destroy(&xdr); + + /* Re-encode the length word. */ + VIR_DEBUG("Encode length as %zu", msg->bufferOffset); + xdrmem_create(&xdr, msg->buffer, VIR_NET_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE); + msglen = msg->bufferOffset; + if (!xdr_u_int(&xdr, &msglen)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message length")); + goto error; + } + xdr_destroy(&xdr); + + msg->bufferLength = msg->bufferOffset; + msg->bufferOffset = 0; + return 0; + +error: + xdr_destroy(&xdr); + return -1; +} + + +int virNetMessageDecodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data) +{ + XDR xdr; + + /* Serialise header followed by args. */ + xdrmem_create(&xdr, msg->buffer + msg->bufferOffset, + msg->bufferLength - msg->bufferOffset, XDR_DECODE); + + if (!(*filter)(&xdr, data)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to decode message payload")); + goto error; + } + + /* Get the length stored in buffer. */ + msg->bufferLength += xdr_getpos(&xdr); + xdr_destroy(&xdr); + return 0; + +error: + xdr_destroy(&xdr); + return -1; +} + + +int virNetMessageEncodePayloadRaw(virNetMessagePtr msg, + const char *data, + size_t len) +{ + XDR xdr; + unsigned int msglen; + + if ((msg->bufferLength - msg->bufferOffset) < len) { + virNetError(VIR_ERR_RPC, + _("Stream data too long to send (%zu bytes needed, %zu bytes available)"), + len, (msg->bufferLength - msg->bufferOffset)); + return -1; + } + + memcpy(msg->buffer + msg->bufferOffset, data, len); + msg->bufferOffset += len; + + /* Re-encode the length word. */ + VIR_DEBUG("Encode length as %zu", msg->bufferOffset); + xdrmem_create(&xdr, msg->buffer, VIR_NET_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE); + msglen = msg->bufferOffset; + if (!xdr_u_int(&xdr, &msglen)) { + virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message length")); + goto error; + } + xdr_destroy(&xdr); + + msg->bufferLength = msg->bufferOffset; + msg->bufferOffset = 0; + return 0; + +error: + xdr_destroy(&xdr); + return -1; +} diff --git a/src/rpc/virnetmessage.h b/src/rpc/virnetmessage.h new file mode 100644 index 0000000..a36c618 --- /dev/null +++ b/src/rpc/virnetmessage.h @@ -0,0 +1,68 @@ +/* + * virnetmessage.h: basic RPC message encoding/decoding + * + * Copyright (C) 2010 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 + */ + +#ifndef __VIR_NET_MESSAGE_H__ +# define __VIR_NET_MESSAGE_H__ + +# include <stdbool.h> + +# include "virnetprotocol.h" + +typedef struct virNetMessageHeader *virNetMessageHeaderPtr; +typedef struct virNetMessageError *virNetMessageErrorPtr; + +typedef struct _virNetMessage virNetMessage; +typedef virNetMessage *virNetMessagePtr; + +struct _virNetMessage { + char buffer[VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX]; + size_t bufferLength; + size_t bufferOffset; + + virNetMessageHeader header; + + virNetMessagePtr next; +}; + + +virNetMessagePtr virNetMessageNew(void); + +void virNetMessageFree(virNetMessagePtr msg); + +virNetMessagePtr virNetMessageQueueServe(virNetMessagePtr *queue); +void virNetMessageQueuePush(virNetMessagePtr *queue, + virNetMessagePtr msg); + +int virNetMessageEncodeHeader(virNetMessagePtr msg); +int virNetMessageDecodeLength(virNetMessagePtr msg); +int virNetMessageDecodeHeader(virNetMessagePtr msg); + +int virNetMessageEncodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data); +int virNetMessageDecodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data); + +int virNetMessageEncodePayloadRaw(virNetMessagePtr msg, + const char *buf, + size_t len); + +#endif /* __VIR_NET_MESSAGE_H__ */ -- 1.7.2.3

On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
This provides a new struct that contains a buffer for the RPC message header+payload, as well as a decoded copy of the message header. There is an API for applying a XDR encoding & decoding of the message headers and payloads. There are also APIs for maintaining a simple FIFO queue of message instances.
+ +/* + * @msg: the outgoing message, whose header to encode + * + * Encodes the length word and header of the message, setting the
spacing: s/ / /
+ +int virNetMessageEncodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data) +{ + XDR xdr; + unsigned int msglen; + + /* Serialise header followed by args. */
This comment is out of place, since the header should already have been serialized prior to this function.
+ + +int virNetMessageDecodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data) +{ + XDR xdr; + + /* Serialise header followed by args. */
Likewise.
+ +int virNetMessageEncodePayloadRaw(virNetMessagePtr msg, + const char *data, + size_t len) +{ + XDR xdr; + unsigned int msglen; + + if ((msg->bufferLength - msg->bufferOffset) < len) { + virNetError(VIR_ERR_RPC, + _("Stream data too long to send (%zu bytes needed, %zu bytes available)"), + len, (msg->bufferLength - msg->bufferOffset)); + return -1; + } + + memcpy(msg->buffer + msg->bufferOffset, data, len); + msg->bufferOffset += len;
Should this round up to a multiple of 4, per the rules of XDR encoding? But in general, this looks okay. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Thu, Dec 16, 2010 at 10:49:16AM -0700, Eric Blake wrote:
On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
This provides a new struct that contains a buffer for the RPC message header+payload, as well as a decoded copy of the message header. There is an API for applying a XDR encoding & decoding of the message headers and payloads. There are also APIs for maintaining a simple FIFO queue of message instances.
+ +/* + * @msg: the outgoing message, whose header to encode + * + * Encodes the length word and header of the message, setting the
spacing: s/ / /
+ +int virNetMessageEncodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data) +{ + XDR xdr; + unsigned int msglen; + + /* Serialise header followed by args. */
This comment is out of place, since the header should already have been serialized prior to this function.
+ + +int virNetMessageDecodePayload(virNetMessagePtr msg, + xdrproc_t filter, + void *data) +{ + XDR xdr; + + /* Serialise header followed by args. */
Likewise.
+ +int virNetMessageEncodePayloadRaw(virNetMessagePtr msg, + const char *data, + size_t len) +{ + XDR xdr; + unsigned int msglen; + + if ((msg->bufferLength - msg->bufferOffset) < len) { + virNetError(VIR_ERR_RPC, + _("Stream data too long to send (%zu bytes needed, %zu bytes available)"), + len, (msg->bufferLength - msg->bufferOffset)); + return -1; + } + + memcpy(msg->buffer + msg->bufferOffset, data, len); + msg->bufferOffset += len;
Should this round up to a multiple of 4, per the rules of XDR encoding?
If this had been raised when we first added the stream support I'd have said yes, but adding padding would cause backcompatibility issues now with new vs old client and server combos. In any case there's nothing in our RPC code in this stream context which makes use of 4 byte boundaries more or less efficient than non-aligned data Regards, Daniel

Introduces a simple wrapper around the raw POSIX sockets APIs and name resolution APIs. Allows for easy creation of client and server sockets with correct usage of name resolution APIs for protocol agnostic socket setup. It can listen for UNIX and TCP stream sockets. It can connect to UNIX, TCP streams directly, or indirectly to UNIX sockets via an SSH tunnel or external command * src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Generic sockets APIs --- .x-sc_avoid_write | 1 + po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/rpc/virnetsocket.c | 723 ++++++++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetsocket.h | 100 +++++++ 5 files changed, 827 insertions(+), 1 deletions(-) create mode 100644 src/rpc/virnetsocket.c create mode 100644 src/rpc/virnetsocket.h diff --git a/.x-sc_avoid_write b/.x-sc_avoid_write index f6fc1b2..3d43ddb 100644 --- a/.x-sc_avoid_write +++ b/.x-sc_avoid_write @@ -1,6 +1,7 @@ ^src/libvirt\.c$ ^src/fdstream\.c$ ^src/qemu/qemu_monitor\.c$ +^src/rpc/virnetsocket.c$ ^src/util/command\.c$ ^src/util/util\.c$ ^src/xen/xend_internal\.c$ diff --git a/po/POTFILES.in b/po/POTFILES.in index c79234a..bc45b3d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -59,6 +59,7 @@ src/qemu/qemu_monitor_text.c src/qemu/qemu_security_dac.c src/remote/remote_driver.c src/rpc/virnetmessage.c +src/rpc/virnetsocket.c src/secret/secret_driver.c src/security/security_apparmor.c src/security/security_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index daf7643..a19b304 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1122,7 +1122,8 @@ noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt_net_rpc_la_SOURCES = \ rpc/virnetmessage.h rpc/virnetmessage.c \ - rpc/virnetprotocol.h rpc/virnetprotocol.c + rpc/virnetprotocol.h rpc/virnetprotocol.c \ + rpc/virnetsocket.h rpc/virnetsocket.c libvirt_net_rpc_la_CFLAGS = \ $(AM_CFLAGS) libvirt_net_rpc_la_LDFLAGS = \ diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c new file mode 100644 index 0000000..2bcb8fa --- /dev/null +++ b/src/rpc/virnetsocket.c @@ -0,0 +1,723 @@ +/* + * virnetsocket.h: generic network socket handling + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <sys/stat.h> +#include <unistd.h> +#include <netinet/tcp.h> +#include <sys/wait.h> + +#include "virnetsocket.h" +#include "util.h" +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" +#include "files.h" +#include "event.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + + +struct _virNetSocket { + int fd; + int watch; + pid_t pid; + int errfd; + bool client; + virNetSocketIOFunc func; + void *opaque; + virSocketAddr localAddr; + virSocketAddr remoteAddr; + char *localAddrStr; + char *remoteAddrStr; +}; + + +static int virNetSocketForkDaemon(const char *binary) +{ + const char *const daemonargs[] = { binary, "--timeout=30", NULL }; + pid_t pid; + + if (virExecDaemonize(daemonargs, NULL, NULL, + &pid, -1, NULL, NULL, + VIR_EXEC_CLEAR_CAPS, + NULL, NULL, NULL) < 0) + return -1; + + return 0; +} + + +static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, + virSocketAddrPtr remoteAddr, + int fd, int errfd, pid_t pid) +{ + virNetSocketPtr sock; + int no_slow_start = 1; + + VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%d", + localAddr, remoteAddr, + fd, errfd, pid); + + if (virSetCloseExec(fd) < 0 || + virSetNonBlock(fd) < 0) + return NULL; + + if (VIR_ALLOC(sock) < 0) { + virReportOOMError(); + return NULL; + } + + sock->localAddr = *localAddr; + if (remoteAddr) + sock->remoteAddr = *remoteAddr; + sock->fd = fd; + sock->errfd = errfd; + sock->pid = pid; + + /* Disable nagle */ + if (sock->localAddr.data.sa.sa_family != AF_UNIX) + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, + (void *)&no_slow_start, + sizeof(no_slow_start)); + + + DEBUG("local family = %d remote family = %d", + localAddr->data.sa.sa_family, + remoteAddr ? remoteAddr->data.sa.sa_family : 0); + if (!(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";"))) + goto error; + + if (remoteAddr && + !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";"))) + goto error; + + sock->client = localAddr && !remoteAddr ? false : true; + + VIR_DEBUG("sock=%p localAddrStr=%s remoteAddrStr=%s", + sock, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); + + return sock; + +error: + virNetSocketFree(sock); + return NULL; +} + + +int virNetSocketNewListenTCP(const char *nodename, + const char *service, + virNetSocketPtr **retsocks, + size_t *nretsocks) +{ + virNetSocketPtr *socks = NULL; + size_t nsocks = 0; + struct addrinfo *ai; + struct addrinfo hints; + int fd = -1; + + *retsocks = NULL; + *nretsocks = 0; + + memset (&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + + int e = getaddrinfo (nodename, service, &hints, &ai); + if (e != 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to resolve address '%s' service '%s': %s"), + nodename, service, gai_strerror (e)); + goto error; + } + + struct addrinfo *runp = ai; + while (runp) { + virSocketAddr addr; + + memset(&addr, 0, sizeof(addr)); + + if ((fd = socket(runp->ai_family, runp->ai_socktype, + runp->ai_protocol)) < 0) { + virReportSystemError(errno, "%s", _("Unable to create socket")); + goto error; + } + + int opt = 1; + setsockopt(fd, 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(fd, IPPROTO_IPV6,IPV6_V6ONLY, + (void*)&on, sizeof on); + } +#endif + + if (bind(fd, runp->ai_addr, runp->ai_addrlen) < 0) { + if (errno != EADDRINUSE) { + virReportSystemError(errno, "%s", _("Unable to bind to port")); + goto error; + } + VIR_FORCE_CLOSE(fd); + continue; + } + + addr.len = sizeof(addr.data); + if (getsockname(fd, &addr.data.sa, &addr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get local socket name")); + goto error; + } + + VIR_DEBUG("%p f=%d f=%d", &addr, runp->ai_family, addr.data.sa.sa_family); + + if (VIR_EXPAND_N(socks, nsocks, 1) < 0) { + virReportOOMError(); + goto error; + } + + if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, fd, -1, 0))) + goto error; + runp = runp->ai_next; + } + + freeaddrinfo (ai); + + *retsocks = socks; + *nretsocks = nsocks; + return 0; + +error: + VIR_FORCE_CLOSE(fd); + return -1; +} + +int virNetSocketNewListenUNIX(const char *path, + mode_t mask, + gid_t grp, + virNetSocketPtr *retsock) +{ + virSocketAddr addr; + mode_t oldmask; + gid_t oldgrp; + int fd; + + *retsock = NULL; + + memset(&addr, 0, sizeof(addr)); + + addr.len = sizeof(addr.data.un); + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + virReportSystemError(errno, "%s", _("Failed to create socket")); + goto error; + } + + addr.data.un.sun_family = AF_UNIX; + if (virStrcpyStatic(addr.data.un.sun_path, path) == NULL) { + virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path); + goto error; + } + if (addr.data.un.sun_path[0] == '@') + addr.data.un.sun_path[0] = '\0'; + else + unlink(addr.data.un.sun_path); + + oldgrp = getgid(); + oldmask = umask(~mask); + if (grp != 0 && setgid(grp) < 0) { + virReportSystemError(errno, + _("Failed to set group ID to %d"), grp); + goto error; + } + + if (bind(fd, &addr.data.sa, addr.len) < 0) { + virReportSystemError(errno, + _("Failed to bind socket to '%s'"), + path); + goto error; + } + umask(oldmask); + if (grp != 0 && setgid(oldgrp)) { + virReportSystemError(errno, + _("Failed to restore group ID to %d"), oldgrp); + goto error; + } + + if (!(*retsock = virNetSocketNew(&addr, NULL, fd, -1, 0))) + goto error; + + return 0; + +error: + VIR_FORCE_CLOSE(fd); + return -1; +} + + +int virNetSocketNewConnectTCP(const char *nodename, + const char *service, + virNetSocketPtr *retsock) +{ + virNetSocketPtr *socks = NULL; + size_t nsocks = 0; + struct addrinfo *ai; + struct addrinfo hints; + int fd = -1; + virSocketAddr localAddr; + virSocketAddr remoteAddr; + struct addrinfo *runp; + int savedErrno = ENOENT; + + *retsock = NULL; + + memset(&localAddr, 0, sizeof(localAddr)); + memset(&remoteAddr, 0, sizeof(remoteAddr)); + + memset (&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + + int e = getaddrinfo (nodename, service, &hints, &ai); + if (e != 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to resolve address '%s' service '%s': %s"), + nodename, service, gai_strerror (e)); + goto error; + } + + runp = ai; + while (runp) { + int opt = 1; + + if ((fd = socket(runp->ai_family, runp->ai_socktype, + runp->ai_protocol)) < 0) { + virReportSystemError(errno, "%s", _("Unable to create socket")); + goto error; + } + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt); + + if (connect(fd, runp->ai_addr, runp->ai_addrlen) >= 0) + break; + + savedErrno = errno; + VIR_FORCE_CLOSE(fd); + runp = runp->ai_next; + } + + if (fd == -1) { + virReportSystemError(savedErrno, + _("unable to connect to server at '%s:%s'"), + nodename, service); + return -1; + } + + freeaddrinfo (ai); + + localAddr.len = sizeof(localAddr.data); + if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get local socket name")); + goto error; + } + + remoteAddr.len = sizeof(remoteAddr.data); + if (getpeername(fd, &remoteAddr.data.sa, &remoteAddr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get remote socket name")); + goto error; + } + + if (VIR_EXPAND_N(socks, nsocks, 1) < 0) { + virReportOOMError(); + goto error; + } + + if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, fd, -1, 0))) + goto error; + + return 0; + +error: + VIR_FORCE_CLOSE(fd); + return -1; +} + + +int virNetSocketNewConnectUNIX(const char *path, + bool spawnDaemon, + const char *binary, + virNetSocketPtr *retsock) +{ + virSocketAddr localAddr; + virSocketAddr remoteAddr; + int fd; + int retries = 0; + + memset(&localAddr, 0, sizeof(localAddr)); + memset(&remoteAddr, 0, sizeof(remoteAddr)); + + remoteAddr.len = sizeof(remoteAddr.data.un); + + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + virReportSystemError(errno, "%s", _("Failed to create socket")); + goto error; + } + + remoteAddr.data.un.sun_family = AF_UNIX; + if (virStrcpyStatic(remoteAddr.data.un.sun_path, path) == NULL) { + virReportSystemError(ENOMEM, _("Path %s too long for unix socket"), path); + goto error; + } + if (remoteAddr.data.un.sun_path[0] == '@') + remoteAddr.data.un.sun_path[0] = '\0'; + +retry: + if (connect(fd, &remoteAddr.data.sa, remoteAddr.len) < 0) { + if (errno == ECONNREFUSED && spawnDaemon && retries < 20) { + if (retries == 0 && + virNetSocketForkDaemon(binary) < 0) + goto error; + + retries++; + usleep(1000 * 100 * retries); + goto retry; + } + + virReportSystemError(errno, + _("Failed to connect socket to '%s'"), + path); + goto error; + } + + localAddr.len = sizeof(localAddr.data); + if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get local socket name")); + goto error; + } + + if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, fd, -1, 0))) + goto error; + + return 0; + +error: + VIR_FORCE_CLOSE(fd); + return -1; +} + + +int virNetSocketNewConnectCommand(virCommandPtr cmd, + virNetSocketPtr *retsock) +{ + pid_t pid = 0; + int sv[2]; + int errfd[2]; + + *retsock = NULL; + + /* Fork off the external process. Use socketpair to create a private + * (unnamed) Unix domain socket to the child process so we don't have + * to faff around with two file descriptors (a la 'pipe(2)'). + */ + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) { + virReportSystemError(errno, "%s", + _("unable to create socket pair")); + goto error; + } + + if (pipe(errfd) < 0) { + virReportSystemError(errno, "%s", + _("unable to create socket pair")); + goto error; + } + + virCommandSetInputFD(cmd, sv[1]); + virCommandSetOutputFD(cmd, &sv[1]); + virCommandSetOutputFD(cmd, &errfd[1]); + + if (virCommandRunAsync(cmd, &pid) < 0) + goto error; + + /* Parent continues here. */ + VIR_FORCE_CLOSE(sv[1]); + VIR_FORCE_CLOSE(errfd[1]); + + if (!(*retsock = virNetSocketNew(NULL, NULL, sv[0], errfd[0], pid))) + goto error; + + virCommandFree(cmd); + + return 0; + +error: + VIR_FORCE_CLOSE(sv[0]); + VIR_FORCE_CLOSE(sv[1]); + VIR_FORCE_CLOSE(errfd[0]); + VIR_FORCE_CLOSE(errfd[1]); + + if (pid > 0 && + virCommandWait(cmd, NULL) < 0) + VIR_WARN("Unable to wait for command %d", pid); + + virCommandFree(cmd); + + return -1; +} + + +int virNetSocketNewConnectSSH(const char *nodename, + const char *service, + const char *binary, + const char *username, + bool noTTY, + const char *netcat, + const char *path, + virNetSocketPtr *retsock) +{ + virCommandPtr cmd; + *retsock = NULL; + + cmd = virCommandNew(binary); + virCommandAddEnvPassCommon(cmd); + virCommandClearCaps(cmd); + + if (service) + virCommandAddArgList(cmd, "-p", service, NULL); + if (username) + virCommandAddArgList(cmd, "-l", username, NULL); + if (noTTY) + virCommandAddArgList(cmd, "-T", "-o", "BatchMode=yes", + "-e", "none", NULL); + virCommandAddArgList(cmd, nodename, + netcat ? netcat : "nc", + "-U", path, NULL); + + return virNetSocketNewConnectCommand(cmd, retsock); +} + + +int virNetSocketNewConnectExternal(const char **cmdargv, + virNetSocketPtr *retsock) +{ + virCommandPtr cmd; + int i; + + *retsock = NULL; + + cmd = virCommandNew(cmdargv[0]); + virCommandAddEnvPassCommon(cmd); + virCommandClearCaps(cmd); + + for (i = 1 ; cmdargv[i] != NULL ; i++) + virCommandAddArg(cmd, cmdargv[i]); + + return virNetSocketNewConnectCommand(cmd, retsock); +} + + +void virNetSocketFree(virNetSocketPtr sock) +{ + if (!sock) + return; + + VIR_DEBUG("sock=%p fd=%d", sock, sock->fd); + if (sock->watch > 0) { + virEventRemoveHandle(sock->watch); + sock->watch = -1; + } + + /* If a server socket, then unlink UNIX path */ + if (!sock->client && + sock->localAddr.data.sa.sa_family == AF_UNIX && + sock->localAddr.data.un.sun_path[0] != '\0') + unlink(sock->localAddr.data.un.sun_path); + + VIR_FORCE_CLOSE(sock->fd); + VIR_FORCE_CLOSE(sock->errfd); + + if (sock->pid > 0) { + pid_t reap; + kill(sock->pid, SIGTERM); + do { +retry: + reap = waitpid(sock->pid, NULL, 0); + if (reap == -1 && errno == EINTR) + goto retry; + } while (reap != -1 && reap != sock->pid); + } + + VIR_FREE(sock->localAddrStr); + VIR_FREE(sock->remoteAddrStr); + + VIR_FREE(sock); +} + + +int virNetSocketGetFD(virNetSocketPtr sock) +{ + return sock->fd; +} + + +bool virNetSocketIsLocal(virNetSocketPtr sock) +{ + if (sock->localAddr.data.sa.sa_family == AF_UNIX) + return true; + return false; +} + + +const char *virNetSocketLocalAddrString(virNetSocketPtr sock) +{ + return sock->localAddrStr; +} + +const char *virNetSocketRemoteAddrString(virNetSocketPtr sock) +{ + return sock->remoteAddrStr; +} + +ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len) +{ + return read(sock->fd, buf, len); +} + +ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len) +{ + return write(sock->fd, buf, len); +} + + +int virNetSocketListen(virNetSocketPtr sock) +{ + if (listen(sock->fd, 30) < 0) { + virReportSystemError(errno, "%s", _("Unable to listen on socket")); + return -1; + } + return 0; +} + +int virNetSocketAccept(virNetSocketPtr sock, virNetSocketPtr *clientsock) +{ + int fd; + virSocketAddr localAddr; + virSocketAddr remoteAddr; + + *clientsock = NULL; + + memset(&localAddr, 0, sizeof(localAddr)); + memset(&remoteAddr, 0, sizeof(remoteAddr)); + + remoteAddr.len = sizeof(remoteAddr.data.stor); + if ((fd = accept(sock->fd, &remoteAddr.data.sa, &remoteAddr.len)) < 0) { + if (errno == ECONNABORTED || + errno == EAGAIN) + return 0; + + virReportSystemError(errno, "%s", + _("Unable to accept client")); + return -1; + } + + localAddr.len = sizeof(localAddr.data); + if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get local socket name")); + VIR_FORCE_CLOSE(fd); + return -1; + } + + if (!(*clientsock = virNetSocketNew(&localAddr, + &remoteAddr, + fd, -1, 0))) + return -1; + + return 0; +} + + +static void virNetSocketEventHandle(int fd ATTRIBUTE_UNUSED, + int watch ATTRIBUTE_UNUSED, + int events, + void *opaque) +{ + virNetSocketPtr sock = opaque; + + sock->func(sock, events, sock->opaque); +} + +int virNetSocketAddIOCallback(virNetSocketPtr sock, + int events, + virNetSocketIOFunc func, + void *opaque) +{ + if (sock->watch > 0) { + VIR_DEBUG("Watch already registered on socket %p", sock); + return -1; + } + + if ((sock->watch = virEventAddHandle(sock->fd, + events, + virNetSocketEventHandle, + sock, + NULL)) < 0) { + VIR_WARN("Failed to register watch on socket %p", sock); + return -1; + } + sock->func = func; + sock->opaque = opaque; + + return 0; +} + +void virNetSocketUpdateIOCallback(virNetSocketPtr sock, + int events) +{ + if (sock->watch <= 0) { + VIR_DEBUG("Watch not registered on socket %p", sock); + return; + } + + virEventUpdateHandle(sock->watch, events); +} + +void virNetSocketRemoveIOCallback(virNetSocketPtr sock) +{ + if (sock->watch <= 0) { + VIR_DEBUG("Watch not registered on socket %p", sock); + return; + } + + virEventRemoveHandle(sock->watch); +} diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h new file mode 100644 index 0000000..4441848 --- /dev/null +++ b/src/rpc/virnetsocket.h @@ -0,0 +1,100 @@ +/* + * virnetsocket.h: generic network socket handling + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_NET_SOCKET_H__ +# define __VIR_NET_SOCKET_H__ + +# include "network.h" +# include "command.h" + +typedef struct _virNetSocket virNetSocket; +typedef virNetSocket *virNetSocketPtr; + + +typedef void (*virNetSocketIOFunc)(virNetSocketPtr sock, + int events, + void *opaque); + + +int virNetSocketNewListenTCP(const char *nodename, + const char *service, + virNetSocketPtr **addrs, + size_t *naddrs); + +int virNetSocketNewListenUNIX(const char *path, + mode_t mask, + gid_t grp, + virNetSocketPtr *addr); + +int virNetSocketNewConnectTCP(const char *nodename, + const char *service, + virNetSocketPtr *addr); + +int virNetSocketNewConnectUNIX(const char *path, + bool spawnDaemon, + const char *binary, + virNetSocketPtr *addr); + +int virNetSocketNewConnectCommand(virCommandPtr cmd, + virNetSocketPtr *retsock); + +int virNetSocketNewConnectSSH(const char *nodename, + const char *service, + const char *binary, + const char *username, + bool noTTY, + const char *netcat, + const char *path, + virNetSocketPtr *addr); + +int virNetSocketNewConnectExternal(const char **cmdargv, + virNetSocketPtr *addr); + +int virNetSocketGetFD(virNetSocketPtr sock); +bool virNetSocketIsLocal(virNetSocketPtr sock); + +ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len); +ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len); + +void virNetSocketFree(virNetSocketPtr sock); + +const char *virNetSocketLocalAddrString(virNetSocketPtr sock); +const char *virNetSocketRemoteAddrString(virNetSocketPtr sock); + +int virNetSocketListen(virNetSocketPtr sock); +int virNetSocketAccept(virNetSocketPtr sock, + virNetSocketPtr *clientsock); + +int virNetSocketAddIOCallback(virNetSocketPtr sock, + int events, + virNetSocketIOFunc func, + void *opaque); + +void virNetSocketUpdateIOCallback(virNetSocketPtr sock, + int events); + +void virNetSocketRemoveIOCallback(virNetSocketPtr sock); + + + +#endif /* __VIR_NET_SOCKET_H__ */ -- 1.7.2.3

On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
Introduces a simple wrapper around the raw POSIX sockets APIs and name resolution APIs. Allows for easy creation of client and server sockets with correct usage of name resolution APIs for protocol agnostic socket setup.
It can listen for UNIX and TCP stream sockets.
It can connect to UNIX, TCP streams directly, or indirectly to UNIX sockets via an SSH tunnel or external command
* src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Generic sockets APIs +++ b/.x-sc_avoid_write @@ -1,6 +1,7 @@ ^src/libvirt\.c$ ^src/fdstream\.c$ ^src/qemu/qemu_monitor\.c$ +^src/rpc/virnetsocket.c$
Technically, and for consistency, that should be \. rather than . in the regex.
+ +static int virNetSocketForkDaemon(const char *binary) +{ + const char *const daemonargs[] = { binary, "--timeout=30", NULL }; + pid_t pid; + + if (virExecDaemonize(daemonargs, NULL, NULL, + &pid, -1, NULL, NULL, + VIR_EXEC_CLEAR_CAPS, + NULL, NULL, NULL) < 0)
virCommand?
+static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr,
+ sock->localAddr = *localAddr;
This line requires that localAddr be non-NULL...
+ if (!(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";"))) + goto error; + + if (remoteAddr && + !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";"))) + goto error; + + sock->client = localAddr && !remoteAddr ? false : true;
therefore, this line could be simplified to: sock->client = !!remoteAddr;
+ + VIR_DEBUG("sock=%p localAddrStr=%s remoteAddrStr=%s", + sock, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr));
and here, you only need the NULLSTR() for remoteAddrStr.
+ + return sock; + +error: + virNetSocketFree(sock);
Double close() problem. Right now, the semantics appear to be that on success, sock owns fd, and fd will be closed later during virNetSocketFree(); but on failure, the caller is responsible for closing fd (well, the majority of callers followed this rule; more on this later). But if this function fails during virSocketFormatAddrFull, then both this error path and the caller will close fd. You need to explicitly set sock->fd = sock->errfd = -1 prior to calling virNetSocketFree() on this error path, or else change the semantics so that this function takes ownership of fd and the caller must not close fd after calling this function. (Of the two choices, I'd go with the first).
+int virNetSocketNewListenTCP(const char *nodename, + + memset (&hints, 0, sizeof hints); + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + + int e = getaddrinfo (nodename, service, &hints, &ai);
Why the spaces before (? The entire file has several inconsistencies between function() and function ().
+ struct addrinfo *runp = ai; + while (runp) { + virSocketAddr addr; + + memset(&addr, 0, sizeof(addr)); + + if ((fd = socket(runp->ai_family, runp->ai_socktype, + runp->ai_protocol)) < 0) {
Still on my gnulib TODO list - support SOCK_CLOEXEC and SOCK_NONBLOCK Linux extensions on all platforms (on newer Linux and cygwin, it gives us the benefit of race-free cloexec and fewer syscalls; elsewhere the cloexec race is still present but libvirt code can be simplified). Doesn't affect the quality of this patch, though. By the way, on today's POSIX teleconference, the issue was raised that blindly close()ing all fd's after fork() is technically non-compliant, since it risks accidentally closing out any implementation fd's such as used in posix_trace_* functions (but seldom an issue in real life, since posix_trace_* is seldom used); so the POSIX folks agreed that the POSIX standard needs to add in dup3, pipe2, accept4, and SOCK_CLOEXEC to parallel the POSIX 2008 addition of O_CLOEXEC and F_DUPFD_CLOEXEC, in order to provide a reliable counterpart to avoid the cloexec race without mistakenly closing too many fds in the child.
+ */ + setsockopt(fd, IPPROTO_IPV6,IPV6_V6ONLY, + (void*)&on, sizeof on);
The cast to void* shouldn't be necessary.
+ if (!(socks[nsocks-1] = virNetSocketNew(&addr, NULL, fd, -1, 0))) + goto error; + runp = runp->ai_next; + } + + freeaddrinfo (ai); + + *retsocks = socks; + *nretsocks = nsocks; + return 0; + +error: + VIR_FORCE_CLOSE(fd); + return -1;
Resource leak. You need to iterate over socks with virNetSocketFree() followed by VIR_FREE(socks). Also, conditionally call freeaddrinfo(ai), depending on whether getaddrinfo succeeded.
+static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr,
+ if (bind(fd, &addr.data.sa, addr.len) < 0) { + virReportSystemError(errno, + _("Failed to bind socket to '%s'"), + path); + goto error; + } + umask(oldmask); + if (grp != 0 && setgid(oldgrp)) { + virReportSystemError(errno, + _("Failed to restore group ID to %d"), oldgrp); + goto error; + } + + if (!(*retsock = virNetSocketNew(&addr, NULL, fd, -1, 0))) + goto error; + + return 0; + +error: + VIR_FORCE_CLOSE(fd); + return -1;
Should this error path attempt to unlink any file created by bind() but discarded when setgid() failed, if path did not start with '@'?
+int virNetSocketNewConnectTCP(const char *nodename, + runp = ai; + while (runp) {
+ if (connect(fd, runp->ai_addr, runp->ai_addrlen) >= 0) + break; + + savedErrno = errno; + VIR_FORCE_CLOSE(fd);
Do we want to save the first failure, rather than the last failure?
+ if (fd == -1) { + virReportSystemError(savedErrno, + _("unable to connect to server at '%s:%s'"), + nodename, service); + return -1; + } + + freeaddrinfo (ai);
Resource leak. Move this line to occur before the fd == -1 check.
+ + if (VIR_EXPAND_N(socks, nsocks, 1) < 0) {
Huh? socks and nsocks have no use in this function.
+error: + VIR_FORCE_CLOSE(fd); + return -1;
Again, conditionally call freeaddrinfo(ai).
+int virNetSocketNewConnectCommand(virCommandPtr cmd,
+ + if (pid > 0 && + virCommandWait(cmd, NULL) < 0) + VIR_WARN("Unable to wait for command %d", pid);
Should you attempt to kill(pid, SIGTERM) prior to virCommandWait() to give the child process heads up that it must exit early? Should virCommand be taught a new interface to make it easy to send SIGTERM, and if that doesn't work within a given timeout, to follow it up with SIGKILL, to make it easy to abort a child due to external reasons like this?
+int virNetSocketNewConnectSSH(const char *nodename,
+ if (noTTY) + virCommandAddArgList(cmd, "-T", "-o", "BatchMode=yes", + "-e", "none", NULL); + virCommandAddArgList(cmd, nodename, + netcat ? netcat : "nc", + "-U", path, NULL); + + return virNetSocketNewConnectCommand(cmd, retsock);
This is just awesome how compact virCommand makes things :)
+int virNetSocketNewConnectExternal(const char **cmdargv, + virNetSocketPtr *retsock) +{ + virCommandPtr cmd; + int i;
s/int/size_t/, if you keep a loop, but...
+ + *retsock = NULL; + + cmd = virCommandNew(cmdargv[0]);
cmd = virCommandNewArgs(cmdargv); (although you might have to add in a cast)...
+ virCommandAddEnvPassCommon(cmd); + virCommandClearCaps(cmd); + + for (i = 1 ; cmdargv[i] != NULL ; i++) + virCommandAddArg(cmd, cmdargv[i]);
...and then you don't need a loop.
+int virNetSocketAccept(virNetSocketPtr sock, virNetSocketPtr *clientsock) + if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get local socket name")); + VIR_FORCE_CLOSE(fd); + return -1; + } + + if (!(*clientsock = virNetSocketNew(&localAddr, + &remoteAddr, + fd, -1, 0))) + return -1;
Resource leak - close fd on failure (this was the one I hinted at earlier).
+void virNetSocketRemoveIOCallback(virNetSocketPtr sock) +{ + if (sock->watch <= 0) { + VIR_DEBUG("Watch not registered on socket %p", sock); + return; + } + + virEventRemoveHandle(sock->watch);
Shouldn't this be: sock->watch = virEventRemoveHandle(sock->watch); -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

At 12/16/2010 07:21 PM, Daniel P. Berrange Write:
Introduces a simple wrapper around the raw POSIX sockets APIs and name resolution APIs. Allows for easy creation of client and server sockets with correct usage of name resolution APIs for protocol agnostic socket setup.
It can listen for UNIX and TCP stream sockets.
It can connect to UNIX, TCP streams directly, or indirectly to UNIX sockets via an SSH tunnel or external command
* src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Generic sockets APIs --- .x-sc_avoid_write | 1 + po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/rpc/virnetsocket.c | 723 ++++++++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetsocket.h | 100 +++++++ 5 files changed, 827 insertions(+), 1 deletions(-) create mode 100644 src/rpc/virnetsocket.c create mode 100644 src/rpc/virnetsocket.h
<snip>
+static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, + virSocketAddrPtr remoteAddr, + int fd, int errfd, pid_t pid) +{ + virNetSocketPtr sock; + int no_slow_start = 1; + + VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%d", + localAddr, remoteAddr, + fd, errfd, pid); + + if (virSetCloseExec(fd) < 0 || + virSetNonBlock(fd) < 0) + return NULL; + + if (VIR_ALLOC(sock) < 0) { + virReportOOMError(); + return NULL; + } + + sock->localAddr = *localAddr;
In the function virNetSocketNewConnectCommand(): if (!(*retsock = virNetSocketNew(NULL, NULL, sv[0], errfd[0], pid))) goto error; So we should check whether localAddr is NULL before dereferencing it.
+ if (remoteAddr) + sock->remoteAddr = *remoteAddr; + sock->fd = fd; + sock->errfd = errfd; + sock->pid = pid; + + /* Disable nagle */ + if (sock->localAddr.data.sa.sa_family != AF_UNIX) + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, + (void *)&no_slow_start, + sizeof(no_slow_start)); + + + DEBUG("local family = %d remote family = %d", + localAddr->data.sa.sa_family, + remoteAddr ? remoteAddr->data.sa.sa_family : 0); we should check localAddr
+ if (!(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";"))) + goto error; we should check localAddr + + if (remoteAddr && + !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";"))) + goto error; + + sock->client = localAddr && !remoteAddr ? false : true; + + VIR_DEBUG("sock=%p localAddrStr=%s remoteAddrStr=%s", + sock, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); + + return sock; + +error: + virNetSocketFree(sock); + return NULL; +} + +
<snip>
+ virCommandSetInputFD(cmd, sv[1]); + virCommandSetOutputFD(cmd, &sv[1]); + virCommandSetOutputFD(cmd, &errfd[1]); s/virCommandSetOutputFD/virCommandSetErrorFD/

On Thu, Dec 23, 2010 at 11:53:41AM +0800, Wen Congyang wrote:
At 12/16/2010 07:21 PM, Daniel P. Berrange Write:
Introduces a simple wrapper around the raw POSIX sockets APIs and name resolution APIs. Allows for easy creation of client and server sockets with correct usage of name resolution APIs for protocol agnostic socket setup.
It can listen for UNIX and TCP stream sockets.
It can connect to UNIX, TCP streams directly, or indirectly to UNIX sockets via an SSH tunnel or external command
* src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Generic sockets APIs --- .x-sc_avoid_write | 1 + po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/rpc/virnetsocket.c | 723 ++++++++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetsocket.h | 100 +++++++ 5 files changed, 827 insertions(+), 1 deletions(-) create mode 100644 src/rpc/virnetsocket.c create mode 100644 src/rpc/virnetsocket.h
<snip>
+static virNetSocketPtr virNetSocketNew(virSocketAddrPtr localAddr, + virSocketAddrPtr remoteAddr, + int fd, int errfd, pid_t pid) +{ + virNetSocketPtr sock; + int no_slow_start = 1; + + VIR_DEBUG("localAddr=%p remoteAddr=%p fd=%d errfd=%d pid=%d", + localAddr, remoteAddr, + fd, errfd, pid); + + if (virSetCloseExec(fd) < 0 || + virSetNonBlock(fd) < 0) + return NULL; + + if (VIR_ALLOC(sock) < 0) { + virReportOOMError(); + return NULL; + } + + sock->localAddr = *localAddr;
In the function virNetSocketNewConnectCommand(): if (!(*retsock = virNetSocketNew(NULL, NULL, sv[0], errfd[0], pid))) goto error; So we should check whether localAddr is NULL before dereferencing it.
Yep, I've just noticed that too.
+ if (remoteAddr) + sock->remoteAddr = *remoteAddr; + sock->fd = fd; + sock->errfd = errfd; + sock->pid = pid; + + /* Disable nagle */ + if (sock->localAddr.data.sa.sa_family != AF_UNIX) + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, + (void *)&no_slow_start, + sizeof(no_slow_start)); + + + DEBUG("local family = %d remote family = %d", + localAddr->data.sa.sa_family, + remoteAddr ? remoteAddr->data.sa.sa_family : 0); we should check localAddr
+ if (!(sock->localAddrStr = virSocketFormatAddrFull(localAddr, true, ";"))) + goto error; we should check localAddr + + if (remoteAddr && + !(sock->remoteAddrStr = virSocketFormatAddrFull(remoteAddr, true, ";"))) + goto error; + + sock->client = localAddr && !remoteAddr ? false : true;
Instead of this bogus logic, I'm going to pass an expliciti 'bool isClient' param into this method.
+ + VIR_DEBUG("sock=%p localAddrStr=%s remoteAddrStr=%s", + sock, NULLSTR(sock->localAddrStr), NULLSTR(sock->remoteAddrStr)); + + return sock; + +error: + virNetSocketFree(sock); + return NULL; +} + +
<snip>
+ virCommandSetInputFD(cmd, sv[1]); + virCommandSetOutputFD(cmd, &sv[1]); + virCommandSetOutputFD(cmd, &errfd[1]); s/virCommandSetOutputFD/virCommandSetErrorFD/
Thanks, Daniel

This provides two modules for handling TLS * virNetTLSContext provides the process-wide state, in particular all the x509 credentials, DH params and x509 whitelists * virNetTLSSession provides the per-connection state, ie the TLS session itself. The virNetTLSContext provides APIs for validating a TLS session's x509 credentials. The virNetTLSSession includes APIs for performing the initial TLS handshake and sending/recving encrypted data * src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnettlscontext.c, src/rpc/virnettlscontext.h: Generic TLS handling code --- po/POTFILES.in | 1 + src/Makefile.am | 6 +- src/rpc/virnettlscontext.c | 664 ++++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnettlscontext.h | 90 ++++++ 4 files changed, 760 insertions(+), 1 deletions(-) create mode 100644 src/rpc/virnettlscontext.c create mode 100644 src/rpc/virnettlscontext.h diff --git a/po/POTFILES.in b/po/POTFILES.in index bc45b3d..39cecdd 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -60,6 +60,7 @@ src/qemu/qemu_security_dac.c src/remote/remote_driver.c src/rpc/virnetmessage.c src/rpc/virnetsocket.c +src/rpc/virnettlscontext.c src/secret/secret_driver.c src/security/security_apparmor.c src/security/security_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index a19b304..10fce7d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1121,12 +1121,16 @@ EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt_net_rpc_la_SOURCES = \ + ../daemon/event.c \ rpc/virnetmessage.h rpc/virnetmessage.c \ rpc/virnetprotocol.h rpc/virnetprotocol.c \ - rpc/virnetsocket.h rpc/virnetsocket.c + rpc/virnetsocket.h rpc/virnetsocket.c \ + rpc/virnettlscontext.h rpc/virnettlscontext.c libvirt_net_rpc_la_CFLAGS = \ + $(GNUTLS_CFLAGS) \ $(AM_CFLAGS) libvirt_net_rpc_la_LDFLAGS = \ + $(GNUTLS_LIBS) \ $(AM_LDFLAGS) \ $(CYGWIN_EXTRA_LDFLAGS) \ $(MINGW_EXTRA_LDFLAGS) diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c new file mode 100644 index 0000000..02da41a --- /dev/null +++ b/src/rpc/virnettlscontext.c @@ -0,0 +1,664 @@ +/* + * virnettlscontext.c: TLS encryption/x509 handling + * + * Copyright (C) 2010 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 + */ + +#include <config.h> + +#include <unistd.h> +#include <fnmatch.h> +#include <stdlib.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include "gnutls_1_0_compat.h" + +#include "virnettlscontext.h" + +#include "memory.h" +#include "virterror_internal.h" +#include "util.h" +#include "logging.h" + +#define DH_BITS 1024 + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +struct _virNetTLSContext { + int refs; + + gnutls_certificate_credentials_t x509cred; + gnutls_dh_params_t dhParams; + + bool isServer; + bool requireValidCert; + const char *const*x509dnWhitelist; +}; + +struct _virNetTLSSession { + int refs; + + bool handshakeComplete; + + char *hostname; + gnutls_session_t session; + virNetTLSSessionWriteFunc writeFunc; + virNetTLSSessionReadFunc readFunc; + void *opaque; +}; + + +static int +virNetTLSContextCheckCertFile(const char *type, const char *file) +{ + if (access(file, R_OK) < 0) { + virReportSystemError(errno, + _("Cannot read %s '%s'"), + type, file); + return -1; + } + return 0; +} + + +static void virNetTLSLog(int level, const char *str) { + VIR_DEBUG("%d %s", level, str); +} + +static virNetTLSContextPtr virNetTLSContextNew(const char *ca_file, + const char *crl_file, + const char *cert_file, + const char *key_file, + const char *const*x509dnWhitelist, + bool requireValidCert, + bool isServer) +{ + virNetTLSContextPtr ctxt; + char *gnutlsdebug; + int err; + + if (VIR_ALLOC(ctxt) < 0) { + virReportOOMError(); + return NULL; + } + + ctxt->refs = 1; + + /* Initialise GnuTLS. */ + gnutls_global_init(); + + if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) { + int val; + if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0) + val = 10; + gnutls_global_set_log_level(val); + gnutls_global_set_log_function(virNetTLSLog); + VIR_DEBUG0("Enabled GNUTLS debug"); + } + + + err = gnutls_certificate_allocate_credentials(&ctxt->x509cred); + if (err) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to allocate x509 credentials: %s"), + gnutls_strerror (err)); + goto error; + } + + if (ca_file && ca_file[0] != '\0') { + if (virNetTLSContextCheckCertFile("CA certificate", ca_file) < 0) + goto error; + + VIR_DEBUG("loading CA cert from %s", ca_file); + err = gnutls_certificate_set_x509_trust_file(ctxt->x509cred, + ca_file, + GNUTLS_X509_FMT_PEM); + if (err < 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to set x509 CA certificate: %s"), + gnutls_strerror (err)); + goto error; + } + } + + if (crl_file && crl_file[0] != '\0') { + if (virNetTLSContextCheckCertFile("CA revocation list", crl_file) < 0) + goto error; + + VIR_DEBUG("loading CRL from %s", crl_file); + err = gnutls_certificate_set_x509_crl_file(ctxt->x509cred, + crl_file, + GNUTLS_X509_FMT_PEM); + if (err < 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to set x509 certificate revocation list: %s"), + gnutls_strerror (err)); + goto error; + } + } + + if (cert_file && cert_file[0] != '\0' && key_file && key_file[0] != '\0') { + if (virNetTLSContextCheckCertFile("server certificate", cert_file) < 0) + goto error; + if (virNetTLSContextCheckCertFile("server key", key_file) < 0) + goto error; + VIR_DEBUG("loading cert and key from %s and %s", cert_file, key_file); + err = + gnutls_certificate_set_x509_key_file(ctxt->x509cred, + cert_file, key_file, + GNUTLS_X509_FMT_PEM); + if (err < 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to set x509 key and certificate: %s"), + gnutls_strerror (err)); + goto error; + } + } + + /* 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. + */ + if (isServer) { + err = gnutls_dh_params_init(&ctxt->dhParams); + if (err < 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to initialize diffie-hellman parameters: %s"), + gnutls_strerror (err)); + goto error; + } + err = gnutls_dh_params_generate2(ctxt->dhParams, DH_BITS); + if (err < 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to generate diffie-hellman parameters: %s"), + gnutls_strerror (err)); + goto error; + } + + gnutls_certificate_set_dh_params(ctxt->x509cred, + ctxt->dhParams); + } + + ctxt->requireValidCert = requireValidCert; + ctxt->x509dnWhitelist = x509dnWhitelist; + ctxt->isServer = isServer; + + return ctxt; + +error: + if (isServer) + gnutls_dh_params_deinit(ctxt->dhParams); + gnutls_certificate_free_credentials(ctxt->x509cred); + VIR_FREE(ctxt); + return NULL; +} + + +virNetTLSContextPtr virNetTLSContextNewServer(const char *ca_file, + const char *crl_file, + const char *cert_file, + const char *key_file, + const char *const*x509dnWhitelist, + bool requireValidCert) +{ + return virNetTLSContextNew(ca_file, crl_file, cert_file, key_file, + x509dnWhitelist, requireValidCert, true); +} + +virNetTLSContextPtr virNetTLSContextNewClient(const char *ca_file, + const char *cert_file, + const char *key_file, + bool requireValidCert) +{ + return virNetTLSContextNew(ca_file, NULL, cert_file, key_file, + NULL, requireValidCert, false); +} + + +void virNetTLSContextRef(virNetTLSContextPtr ctxt) +{ + ctxt->refs++; +} + + +/* Check DN is on tls_allowed_dn_list. */ +static int +virNetTLSContextCheckDN(virNetTLSContextPtr ctxt, + const char *dname) +{ + const char *const*wildcards; + + /* If the list is not set, allow any DN. */ + wildcards = ctxt->x509dnWhitelist; + if (!wildcards) + return 1; + + while (*wildcards) { + if (fnmatch (*wildcards, dname, 0) == 0) + return 1; + wildcards++; + } + + /* Print the client's DN. */ + DEBUG(_("Failed whitelist check for client DN '%s'"), dname); + + return 0; // Not found. +} + +static int virNetTLSContextValidCertificate(virNetTLSContextPtr ctxt, + virNetTLSSessionPtr sess) +{ + 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(sess->session, &status)) < 0){ + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Unable to verify TLS peer: %s"), + gnutls_strerror(ret)); + goto authdeny; + } + + if ((now = time(NULL)) == ((time_t)-1)) { + virReportSystemError(errno, "%s", + _("cannot get current time")); + goto authfail; + } + + if (status != 0) { + const char *reason = _("Invalid certificate"); + + if (status & GNUTLS_CERT_INVALID) + reason = _("The certificate is not trusted."); + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + reason = _("The certificate hasn't got a known issuer."); + + if (status & GNUTLS_CERT_REVOKED) + reason = _("The certificate has been revoked."); + +#ifndef GNUTLS_1_0_COMPAT + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) + reason = _("The certificate uses an insecure algorithm"); +#endif + + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Certificate failed validation: %s"), + reason); + goto authdeny; + } + + if (gnutls_certificate_type_get(sess->session) != GNUTLS_CRT_X509) { + virNetError(VIR_ERR_SYSTEM_ERROR, "%s", + _("Only x509 certificates are supported")); + goto authdeny; + } + + if (!(certs = gnutls_certificate_get_peers(sess->session, &nCerts))) { + virNetError(VIR_ERR_SYSTEM_ERROR, "%s", + _("The certificate has no peers")); + goto authdeny; + } + + for (i = 0; i < nCerts; i++) { + gnutls_x509_crt_t cert; + + if (gnutls_x509_crt_init (&cert) < 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, "%s", + _("Unable to initialize certificate")); + goto authfail; + } + + if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, "%s", + _("Unable to load certificate")); + gnutls_x509_crt_deinit(cert); + goto authfail; + } + + if (gnutls_x509_crt_get_expiration_time(cert) < now) { + virNetError(VIR_ERR_SYSTEM_ERROR, "%s", + _("The client certificate has expired")); + gnutls_x509_crt_deinit(cert); + goto authdeny; + } + + if (gnutls_x509_crt_get_activation_time(cert) > now) { + virNetError(VIR_ERR_SYSTEM_ERROR, "%s", + _("The client certificate is not yet active")); + gnutls_x509_crt_deinit(cert); + goto authdeny; + } + + if (i == 0) { + ret = gnutls_x509_crt_get_dn(cert, name, &namesize); + if (ret != 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Failed to get certificate distinguished name: %s"), + gnutls_strerror(ret)); + gnutls_x509_crt_deinit(cert); + goto authfail; + } + + if (!virNetTLSContextCheckDN(ctxt, name)) { + /* This is the most common error: make it informative. */ + virNetError(VIR_ERR_SYSTEM_ERROR, "%s", + _("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 (sess->hostname && + !gnutls_x509_crt_check_hostname(cert, sess->hostname)) { + virNetError(VIR_ERR_RPC, + _("Certificate's owner does not match the hostname (%s)"), + sess->hostname); + gnutls_x509_crt_deinit(cert); + goto authdeny; + } + } + } + +#if 0 + PROBE(CLIENT_TLS_ALLOW, "fd=%d, name=%s", + virNetServerClientGetFD(client), name); +#endif + return 0; + +authdeny: +#if 0 + PROBE(CLIENT_TLS_DENY, "fd=%d, name=%s", + virNetServerClientGetFD(client), name); +#endif + return -1; + +authfail: +#if 0 + PROBE(CLIENT_TLS_FAIL, "fd=%d", + virNetServerClientGetFD(client)); +#endif + return -1; +} + +int virNetTLSContextCheckCertificate(virNetTLSContextPtr ctxt, + virNetTLSSessionPtr sess) { + if (virNetTLSContextValidCertificate(ctxt, sess) < 0) { + if (ctxt->requireValidCert) { + virNetError(VIR_ERR_AUTH_FAILED, "%s", + _("Failed to verify peer's certificate")); + return -1; + } + VIR_INFO0(_("Ignoring bad certificate at user request")); + } + return 0; +} + +void virNetTLSContextFree(virNetTLSContextPtr ctxt) +{ + if (!ctxt) + return; + + ctxt->refs--; + if (ctxt->refs > 0) + return; + + gnutls_dh_params_deinit(ctxt->dhParams); + gnutls_certificate_free_credentials(ctxt->x509cred); + VIR_FREE(ctxt); +} + + + +static ssize_t +virNetTLSSessionPush(void *opaque, const void *buf, size_t len) +{ + virNetTLSSessionPtr sess = opaque; + if (!sess->writeFunc) { + VIR_WARN0("TLS session push with missing read function"); + errno = EIO; + return -1; + }; + + return sess->writeFunc(buf, len, sess->opaque); +} + + +static ssize_t +virNetTLSSessionPull(void *opaque, void *buf, size_t len) +{ + virNetTLSSessionPtr sess = opaque; + if (!sess->readFunc) { + VIR_WARN0("TLS session pull with missing read function"); + errno = EIO; + return -1; + }; + + return sess->readFunc(buf, len, sess->opaque); +} + + +virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt, + const char *hostname) +{ + virNetTLSSessionPtr sess; + int err; + static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; + + if (VIR_ALLOC(sess) < 0) { + virReportOOMError(); + return NULL; + } + + sess->refs = 1; + if (hostname && + !(sess->hostname = strdup(hostname))) { + virReportOOMError(); + goto error; + } + + if ((err = gnutls_init(&sess->session, + ctxt->isServer ? GNUTLS_SERVER : GNUTLS_CLIENT)) != 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Failed to initialize TLS session: %s"), + gnutls_strerror(err)); + goto error; + } + + /* avoid calling all the priority functions, since the defaults + * are adequate. + */ + if ((err = gnutls_set_default_priority(sess->session)) != 0 || + (err = gnutls_certificate_type_set_priority(sess->session, + cert_type_priority))) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Failed to set TLS session priority %s"), + gnutls_strerror(err)); + goto error; + } + + if ((err = gnutls_credentials_set(sess->session, + GNUTLS_CRD_CERTIFICATE, + ctxt->x509cred)) != 0) { + virNetError(VIR_ERR_SYSTEM_ERROR, + _("Failed set TLS x509 credentials: %s"), + gnutls_strerror(err)); + goto error; + } + + /* request client certificate if any. + */ + if (ctxt->isServer) { + gnutls_certificate_server_set_request(sess->session, GNUTLS_CERT_REQUEST); + + gnutls_dh_set_prime_bits(sess->session, DH_BITS); + } + + gnutls_transport_set_ptr(sess->session, sess); + gnutls_transport_set_push_function(sess->session, + virNetTLSSessionPush); + gnutls_transport_set_pull_function(sess->session, + virNetTLSSessionPull); + + return sess; + +error: + virNetTLSSessionFree(sess); + return NULL; +} + + +void virNetTLSSessionRef(virNetTLSSessionPtr sess) +{ + sess->refs++; +} + +void virNetTLSSessionSetIOCallbacks(virNetTLSSessionPtr sess, + virNetTLSSessionWriteFunc writeFunc, + virNetTLSSessionReadFunc readFunc, + void *opaque) +{ + sess->writeFunc = writeFunc; + sess->readFunc = readFunc; + sess->opaque = opaque; +} + + +ssize_t virNetTLSSessionWrite(virNetTLSSessionPtr sess, + const char *buf, size_t len) +{ + int ret; + ret = gnutls_record_send(sess->session, buf, len); + + switch (ret) { + case GNUTLS_E_AGAIN: + errno = EAGAIN; + break; + case GNUTLS_E_INTERRUPTED: + errno = EINTR; + break; + case 0: + break; + default: + errno = EIO; + } + + return ret >= 0 ? ret : -1; +} + +ssize_t virNetTLSSessionRead(virNetTLSSessionPtr sess, + char *buf, size_t len) +{ + int ret; + + ret = gnutls_record_recv(sess->session, buf, len); + + switch (ret) { + case GNUTLS_E_AGAIN: + errno = EAGAIN; + break; + case GNUTLS_E_INTERRUPTED: + errno = EINTR; + break; + case 0: + break; + default: + errno = EIO; + } + + return ret >= 0 ? ret : -1; +} + +int virNetTLSSessionHandshake(virNetTLSSessionPtr sess) +{ + VIR_DEBUG("sess=%p", sess); + int ret = gnutls_handshake(sess->session); + + if (ret == 0) { + sess->handshakeComplete = true; + VIR_DEBUG0("Handshake is complete"); + return 0; + } + if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) + return 1; + +#if 0 + PROBE(CLIENT_TLS_FAIL, "fd=%d", + virNetServerClientGetFD(client)); +#endif + + virNetError(VIR_ERR_AUTH_FAILED, + _("TLS handshake failed %s"), + gnutls_strerror (ret)); + return -1; +} + +virNetTLSSessionHandshakeStatus +virNetTLSSessionGetHandshakeStatus(virNetTLSSessionPtr sess) +{ + if (sess->handshakeComplete) + return VIR_NET_TLS_HANDSHAKE_COMPLETE; + else if (gnutls_record_get_direction (sess->session) == 0) + return VIR_NET_TLS_HANDSHAKE_RECVING; + else + return VIR_NET_TLS_HANDSHAKE_SENDING; +} + +int virNetTLSSessionGetKeySize(virNetTLSSessionPtr sess) +{ + gnutls_cipher_algorithm_t cipher; + int ssf; + + cipher = gnutls_cipher_get(sess->session); + if (!(ssf = gnutls_cipher_get_key_size(cipher))) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("invalid cipher size for TLS session")); + return -1; + } + + return ssf; +} + + +void virNetTLSSessionFree(virNetTLSSessionPtr sess) +{ + if (!sess) + return; + + sess->refs--; + if (sess->refs > 0) + return; + + VIR_FREE(sess->hostname); + gnutls_deinit(sess->session); + VIR_FREE(sess); +} diff --git a/src/rpc/virnettlscontext.h b/src/rpc/virnettlscontext.h new file mode 100644 index 0000000..88db141 --- /dev/null +++ b/src/rpc/virnettlscontext.h @@ -0,0 +1,90 @@ +/* + * virnettlscontext.h: TLS encryption/x509 handling + * + * Copyright (C) 2010 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 + */ + +#ifndef __VIR_NET_TLS_CONTEXT_H__ +# define __VIR_NET_TLS_CONTEXT_H__ + +# include <stdbool.h> +# include <sys/types.h> + +typedef struct _virNetTLSContext virNetTLSContext; +typedef virNetTLSContext *virNetTLSContextPtr; + +typedef struct _virNetTLSSession virNetTLSSession; +typedef virNetTLSSession *virNetTLSSessionPtr; + + +virNetTLSContextPtr virNetTLSContextNewServer(const char *ca_file, + const char *crl_file, + const char *cert_file, + const char *key_file, + const char *const*x509dnWhitelist, + bool requireValidCert); + +virNetTLSContextPtr virNetTLSContextNewClient(const char *ca_file, + const char *cert_file, + const char *key_file, + bool requireValidCert); + +void virNetTLSContextRef(virNetTLSContextPtr ctxt); + +int virNetTLSContextCheckCertificate(virNetTLSContextPtr ctxt, + virNetTLSSessionPtr sess); + +void virNetTLSContextFree(virNetTLSContextPtr ctxt); + + +typedef ssize_t (*virNetTLSSessionWriteFunc)(const char *buf, size_t len, + void *opaque); +typedef ssize_t (*virNetTLSSessionReadFunc)(char *buf, size_t len, + void *opaque); + +virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt, + const char *hostname); + +void virNetTLSSessionSetIOCallbacks(virNetTLSSessionPtr sess, + virNetTLSSessionWriteFunc writeFunc, + virNetTLSSessionReadFunc readFunc, + void *opaque); + +void virNetTLSSessionRef(virNetTLSSessionPtr sess); + +ssize_t virNetTLSSessionWrite(virNetTLSSessionPtr sess, + const char *buf, size_t len); +ssize_t virNetTLSSessionRead(virNetTLSSessionPtr sess, + char *buf, size_t len); + +int virNetTLSSessionHandshake(virNetTLSSessionPtr sess); + +typedef enum { + VIR_NET_TLS_HANDSHAKE_COMPLETE, + VIR_NET_TLS_HANDSHAKE_SENDING, + VIR_NET_TLS_HANDSHAKE_RECVING, +} virNetTLSSessionHandshakeStatus; + +virNetTLSSessionHandshakeStatus +virNetTLSSessionGetHandshakeStatus(virNetTLSSessionPtr sess); + +int virNetTLSSessionGetKeySize(virNetTLSSessionPtr sess); + +void virNetTLSSessionFree(virNetTLSSessionPtr sess); + + +#endif -- 1.7.2.3

On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
This provides two modules for handling TLS
* virNetTLSContext provides the process-wide state, in particular all the x509 credentials, DH params and x509 whitelists * virNetTLSSession provides the per-connection state, ie the TLS session itself.
The virNetTLSContext provides APIs for validating a TLS session's x509 credentials. The virNetTLSSession includes APIs for performing the initial TLS handshake and sending/recving encrypted data
* src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnettlscontext.c, src/rpc/virnettlscontext.h: Generic TLS handling code
+/* Check DN is on tls_allowed_dn_list. */ +static int +virNetTLSContextCheckDN(virNetTLSContextPtr ctxt, + const char *dname) +{ + const char *const*wildcards; + + /* If the list is not set, allow any DN. */ + wildcards = ctxt->x509dnWhitelist; + if (!wildcards) + return 1; + + while (*wildcards) { + if (fnmatch (*wildcards, dname, 0) == 0) + return 1; + wildcards++; + }
Should this function return -1 if fnmatch returns nonzero other than FNM_NOMATCH (for example, if wildcards contained an ill-formed entry)?
+static int virNetTLSContextValidCertificate(virNetTLSContextPtr ctxt, + if (status != 0) { + const char *reason = _("Invalid certificate"); + + if (status & GNUTLS_CERT_INVALID) + reason = _("The certificate is not trusted."); + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + reason = _("The certificate hasn't got a known issuer.");
Can status return multiple simultaneous errors, and if so, is this ordering the desired precedence where the last setting of reason is the best to present to the user?
+ssize_t virNetTLSSessionWrite(virNetTLSSessionPtr sess, + const char *buf, size_t len) +{ + int ret;
s/int/ssize_t/
+ssize_t virNetTLSSessionRead(virNetTLSSessionPtr sess, + char *buf, size_t len) +{ + int ret;
s/int/ssize_t/
+ + ret = gnutls_record_recv(sess->session, buf, len); + + switch (ret) { + case GNUTLS_E_AGAIN: + errno = EAGAIN; + break; + case GNUTLS_E_INTERRUPTED: + errno = EINTR; + break; + case 0: + break; + default: + errno = EIO;
Rather than pollute errno on success, this style of switch statement (for both Write and Read) should be written: case GNUTLS_E_AGAIN:... case GNUTLS_E_INTERRUPTED:... default: if (ret < 0) errno = EIO; break; That is, a return of 0 should not be the only value that leaves errno untouched. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

This provides two modules for handling SASL * virNetSASLContext provides the process-wide state, currently just a whitelist of usernames on the server and a one time library init call * virNetTLSSession provides the per-connection state, ie the SASL session itself. This also include APIs for providing data encryption/decryption once the session is established * src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetsaslcontext.c, src/rpc/virnetsaslcontext.h: Generic SASL handling code --- po/POTFILES.in | 1 + src/Makefile.am | 3 + src/rpc/virnetsaslcontext.c | 525 +++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetsaslcontext.h | 125 ++++++++++ 4 files changed, 654 insertions(+), 0 deletions(-) create mode 100644 src/rpc/virnetsaslcontext.c create mode 100644 src/rpc/virnetsaslcontext.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 39cecdd..bb8c0b2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -59,6 +59,7 @@ src/qemu/qemu_monitor_text.c src/qemu/qemu_security_dac.c src/remote/remote_driver.c src/rpc/virnetmessage.c +src/rpc/virnetsaslcontext.c src/rpc/virnetsocket.c src/rpc/virnettlscontext.c src/secret/secret_driver.c diff --git a/src/Makefile.am b/src/Makefile.am index 10fce7d..def7e0a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1124,13 +1124,16 @@ libvirt_net_rpc_la_SOURCES = \ ../daemon/event.c \ rpc/virnetmessage.h rpc/virnetmessage.c \ rpc/virnetprotocol.h rpc/virnetprotocol.c \ + rpc/virnetsaslcontext.h rpc/virnetsaslcontext.c \ rpc/virnetsocket.h rpc/virnetsocket.c \ rpc/virnettlscontext.h rpc/virnettlscontext.c libvirt_net_rpc_la_CFLAGS = \ $(GNUTLS_CFLAGS) \ + $(SASL_CFLAGS) \ $(AM_CFLAGS) libvirt_net_rpc_la_LDFLAGS = \ $(GNUTLS_LIBS) \ + $(SASL_LIBS) \ $(AM_LDFLAGS) \ $(CYGWIN_EXTRA_LDFLAGS) \ $(MINGW_EXTRA_LDFLAGS) diff --git a/src/rpc/virnetsaslcontext.c b/src/rpc/virnetsaslcontext.c new file mode 100644 index 0000000..8e72d2c --- /dev/null +++ b/src/rpc/virnetsaslcontext.c @@ -0,0 +1,525 @@ +/* + * virnetsaslcontext.c: SASL encryption/auth handling + * + * Copyright (C) 2010 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 + */ + +#include <config.h> + +#include <fnmatch.h> + +#include "virnetsaslcontext.h" + +#include "virterror_internal.h" +#include "memory.h" +#include "logging.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + + +struct _virNetSASLContext { + const char *const*usernameWhitelist; + int refs; +}; + +struct _virNetSASLSession { + sasl_conn_t *conn; + int refs; +}; + + +virNetSASLContextPtr virNetSASLContextNewClient(void) +{ + virNetSASLContextPtr ctxt; + int err; + + err = sasl_client_init(NULL); + if (err != SASL_OK) { + virNetError(VIR_ERR_AUTH_FAILED, + _("failed to initialize SASL library: %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return NULL; + } + + if (VIR_ALLOC(ctxt) < 0) { + virReportOOMError(); + return NULL; + } + + ctxt->refs = 1; + + return ctxt; +} + +virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitelist) +{ + virNetSASLContextPtr ctxt; + int err; + + err = sasl_server_init(NULL, "libvirt"); + if (err != SASL_OK) { + virNetError(VIR_ERR_AUTH_FAILED, + _("failed to initialize SASL library: %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return NULL; + } + + if (VIR_ALLOC(ctxt) < 0) { + virReportOOMError(); + return NULL; + } + + ctxt->usernameWhitelist = usernameWhitelist; + ctxt->refs = 1; + + return ctxt; +} + +int virNetSASLContextCheckIdentity(virNetSASLContextPtr ctxt, + const char *identity) +{ + const char *const*wildcards; + + /* If the list is not set, allow any DN. */ + wildcards = ctxt->usernameWhitelist; + if (!wildcards) + return 1; /* No ACL, allow all */ + + while (*wildcards) { + if (fnmatch (*wildcards, identity, 0) == 0) + return 1; /* Allowed */ + wildcards++; + } + + /* Denied */ + VIR_ERROR(_("SASL client %s not allowed in whitelist"), identity); + return 0; +} + + +void virNetSASLContextRef(virNetSASLContextPtr ctxt) +{ + ctxt->refs++; +} + +void virNetSASLContextFree(virNetSASLContextPtr ctxt) +{ + if (!ctxt) + return; + + ctxt->refs--; + if (ctxt->refs > 0) + return; + + VIR_FREE(ctxt); +} + +virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt ATTRIBUTE_UNUSED, + const char *service, + const char *hostname, + const char *localAddr, + const char *remoteAddr, + const sasl_callback_t *cbs) +{ + virNetSASLSessionPtr sasl = NULL; + int err; + + if (VIR_ALLOC(sasl) < 0) { + virReportOOMError(); + goto cleanup; + } + + sasl->refs = 1; + + err = sasl_client_new(service, + hostname, + localAddr, + remoteAddr, + cbs, + SASL_SUCCESS_DATA, + &sasl->conn); + if (err != SASL_OK) { + virNetError(VIR_ERR_AUTH_FAILED, + _("Failed to create SASL client context: %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + goto cleanup; + } + + return sasl; + +cleanup: + virNetSASLSessionFree(sasl); + return NULL; +} + +virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt ATTRIBUTE_UNUSED, + const char *service, + const char *localAddr, + const char *remoteAddr) +{ + virNetSASLSessionPtr sasl = NULL; + int err; + + if (VIR_ALLOC(sasl) < 0) { + virReportOOMError(); + goto cleanup; + } + + sasl->refs = 1; + + err = sasl_server_new(service, + NULL, + NULL, + localAddr, + remoteAddr, + NULL, + SASL_SUCCESS_DATA, + &sasl->conn); + if (err != SASL_OK) { + virNetError(VIR_ERR_AUTH_FAILED, + _("Failed to create SASL client context: %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + goto cleanup; + } + + return sasl; + +cleanup: + virNetSASLSessionFree(sasl); + return NULL; +} + +void virNetSASLSessionRef(virNetSASLSessionPtr sasl) +{ + sasl->refs++; +} + +int virNetSASLSessionExtKeySize(virNetSASLSessionPtr sasl, + int ssf) +{ + int err; + + err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf); + if (err != SASL_OK) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("cannot set external SSF %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return -1; + } + return 0; +} + +const char *virNetSASLSessionGetIdentity(virNetSASLSessionPtr sasl) +{ + const void *val; + int err; + + err = sasl_getprop(sasl->conn, SASL_USERNAME, &val); + if (err != SASL_OK) { + virNetError(VIR_ERR_AUTH_FAILED, + _("cannot query SASL username on connection %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return NULL; + } + if (val == NULL) { + virNetError(VIR_ERR_AUTH_FAILED, + _("no client username was found")); + return NULL; + } + VIR_DEBUG("SASL client username %s", (const char *)val); + + return (const char*)val; +} + + +int virNetSASLSessionGetKeySize(virNetSASLSessionPtr sasl) +{ + int err; + int ssf; + const void *val; + err = sasl_getprop(sasl->conn, SASL_SSF, &val); + if (err != SASL_OK) { + virNetError(VIR_ERR_AUTH_FAILED, + _("cannot query SASL ssf on connection %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return -1; + } + ssf = *(const int *)val; + return ssf; +} + +int virNetSASLSessionSecProps(virNetSASLSessionPtr sasl, + int minSSF, + int maxSSF, + bool allowAnonymous) +{ + sasl_security_properties_t secprops; + int err; + + memset (&secprops, 0, sizeof secprops); + + secprops.min_ssf = minSSF; + secprops.max_ssf = maxSSF; + secprops.maxbufsize = 100000; + secprops.security_flags = allowAnonymous ? 0 : + SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; + + err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops); + if (err != SASL_OK) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("cannot set security props %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return -1; + } + + return 0; +} + + +char *virNetSASLSessionListMechanisms(virNetSASLSessionPtr sasl) +{ + const char *mechlist; + char *ret; + int err; + + err = sasl_listmech(sasl->conn, + NULL, /* Don't need to set user */ + "", /* Prefix */ + ",", /* Separator */ + "", /* Suffix */ + &mechlist, + NULL, + NULL); + if (err != SASL_OK) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("cannot list SASL mechanisms %d (%s)"), + err, sasl_errdetail(sasl->conn)); + return NULL; + } + if (!(ret = strdup(mechlist))) { + virReportOOMError(); + return NULL; + } + return ret; +} + + +int virNetSASLSessionClientStart(virNetSASLSessionPtr sasl, + const char *mechlist, + sasl_interact_t **prompt_need, + const char **clientout, + size_t *clientoutlen, + const char **mech) +{ + unsigned outlen = 0; + + int err = sasl_client_start(sasl->conn, + mechlist, + prompt_need, + clientout, + &outlen, + mech); + + *clientoutlen = outlen; + + switch (err) { + case SASL_OK: + return VIR_NET_SASL_COMPLETE; + case SASL_CONTINUE: + return VIR_NET_SASL_CONTINUE; + case SASL_INTERACT: + return VIR_NET_SASL_INTERACT; + + default: + virNetError(VIR_ERR_AUTH_FAILED, + _("Failed to start SASL negotiation: %d (%s)"), + err, sasl_errdetail(sasl->conn)); + return -1; + } +} + + +int virNetSASLSessionClientStep(virNetSASLSessionPtr sasl, + const char *serverin, + size_t serverinlen, + sasl_interact_t **prompt_need, + const char **clientout, + size_t *clientoutlen) +{ + unsigned inlen = serverinlen; + unsigned outlen = 0; + + int err = sasl_client_step(sasl->conn, + serverin, + inlen, + prompt_need, + clientout, + &outlen); + *clientoutlen = outlen; + + switch (err) { + case SASL_OK: + return VIR_NET_SASL_COMPLETE; + case SASL_CONTINUE: + return VIR_NET_SASL_CONTINUE; + case SASL_INTERACT: + return VIR_NET_SASL_INTERACT; + + default: + virNetError(VIR_ERR_AUTH_FAILED, + _("Failed to start SASL negotiation: %d (%s)"), + err, sasl_errdetail(sasl->conn)); + return -1; + } +} + +int virNetSASLSessionServerStart(virNetSASLSessionPtr sasl, + const char *mechname, + const char *clientin, + size_t clientinlen, + const char **serverout, + size_t *serveroutlen) +{ + unsigned inlen = clientinlen; + unsigned outlen = 0; + int err = sasl_server_start(sasl->conn, + mechname, + clientin, + inlen, + serverout, + &outlen); + + *serveroutlen = outlen; + + switch (err) { + case SASL_OK: + return VIR_NET_SASL_COMPLETE; + case SASL_CONTINUE: + return VIR_NET_SASL_CONTINUE; + case SASL_INTERACT: + return VIR_NET_SASL_INTERACT; + + default: + virNetError(VIR_ERR_AUTH_FAILED, + _("Failed to start SASL negotiation: %d (%s)"), + err, sasl_errdetail(sasl->conn)); + return -1; + } +} + + +int virNetSASLSessionServerStep(virNetSASLSessionPtr sasl, + const char *clientin, + size_t clientinlen, + const char **serverout, + size_t *serveroutlen) +{ + unsigned inlen = clientinlen; + unsigned outlen = 0; + + int err = sasl_server_step(sasl->conn, + clientin, + inlen, + serverout, + &outlen); + + *serveroutlen = outlen; + + switch (err) { + case SASL_OK: + return VIR_NET_SASL_COMPLETE; + case SASL_CONTINUE: + return VIR_NET_SASL_CONTINUE; + case SASL_INTERACT: + return VIR_NET_SASL_INTERACT; + + default: + VIR_DEBUG("Foo %s", sasl_errdetail(sasl->conn)); + virNetError(VIR_ERR_AUTH_FAILED, + _("Failed to start SASL negotiation: %d (%s)"), + err, sasl_errdetail(sasl->conn)); + return -1; + } +} + +ssize_t virNetSASLSessionEncode(virNetSASLSessionPtr sasl, + const char *input, + size_t inputLen, + const char **output, + size_t *outputlen) +{ + unsigned inlen = inputLen; + unsigned outlen = 0; + int err; + err = sasl_encode(sasl->conn, + input, + inlen, + output, + &outlen); + *outputlen = outlen; + + if (err != SASL_OK) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("failed to encode SASL data: %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return -1; + } + return 0; +} + +ssize_t virNetSASLSessionDecode(virNetSASLSessionPtr sasl, + const char *input, + size_t inputLen, + const char **output, + size_t *outputlen) +{ + unsigned inlen = inputLen; + unsigned outlen = 0; + int err; + err = sasl_decode(sasl->conn, + input, + inlen, + output, + &outlen); + *outputlen = outlen; + if (err != SASL_OK) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("failed to decode SASL data: %d (%s)"), + err, sasl_errstring(err, NULL, NULL)); + return -1; + } + return 0; +} + +void virNetSASLSessionFree(virNetSASLSessionPtr sasl) +{ + if (!sasl) + return; + + sasl->refs--; + if (sasl->refs > 0) + return; + + if (sasl->conn) + sasl_dispose(&sasl->conn); + + VIR_FREE(sasl); +} diff --git a/src/rpc/virnetsaslcontext.h b/src/rpc/virnetsaslcontext.h new file mode 100644 index 0000000..9efa2cc --- /dev/null +++ b/src/rpc/virnetsaslcontext.h @@ -0,0 +1,125 @@ +/* + * virnetsaslcontext.h: SASL encryption/auth handling + * + * Copyright (C) 2010 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 + */ + +#ifndef __VIR_NET_CLIENT_SASL_CONTEXT_H__ +# define __VIR_NET_CLIENT_SASL_CONTEXT_H__ + +# ifdef HAVE_SASL +/* Only needed for sasl_callback_t :-( */ +# include <sasl/sasl.h> +# endif + +# include <stdbool.h> +# include <sys/types.h> + +# ifndef HAVE_SASL +typedef sasl_callback_t void *; +# endif + +typedef struct _virNetSASLContext virNetSASLContext; +typedef virNetSASLContext *virNetSASLContextPtr; + +typedef struct _virNetSASLSession virNetSASLSession; +typedef virNetSASLSession *virNetSASLSessionPtr; + +enum { + VIR_NET_SASL_COMPLETE, + VIR_NET_SASL_CONTINUE, + VIR_NET_SASL_INTERACT, +}; + +virNetSASLContextPtr virNetSASLContextNewClient(void); +virNetSASLContextPtr virNetSASLContextNewServer(const char *const*usernameWhitelist); + +int virNetSASLContextCheckIdentity(virNetSASLContextPtr ctxt, + const char *identity); + +void virNetSASLContextRef(virNetSASLContextPtr sasl); +void virNetSASLContextFree(virNetSASLContextPtr sasl); + +virNetSASLSessionPtr virNetSASLSessionNewClient(virNetSASLContextPtr ctxt, + const char *service, + const char *hostname, + const char *localAddr, + const char *remoteAddr, + const sasl_callback_t *cbs); +virNetSASLSessionPtr virNetSASLSessionNewServer(virNetSASLContextPtr ctxt, + const char *service, + const char *localAddr, + const char *remoteAddr); + +char *virNetSASLSessionListMechanisms(virNetSASLSessionPtr sasl); + +void virNetSASLSessionRef(virNetSASLSessionPtr sasl); + +int virNetSASLSessionExtKeySize(virNetSASLSessionPtr sasl, + int ssf); + +int virNetSASLSessionGetKeySize(virNetSASLSessionPtr sasl); + +const char *virNetSASLSessionGetIdentity(virNetSASLSessionPtr sasl); + +int virNetSASLSessionSecProps(virNetSASLSessionPtr sasl, + int minSSF, + int maxSSF, + bool allowAnonymous); + +int virNetSASLSessionClientStart(virNetSASLSessionPtr sasl, + const char *mechlist, + sasl_interact_t **prompt_need, + const char **clientout, + size_t *clientoutlen, + const char **mech); + +int virNetSASLSessionClientStep(virNetSASLSessionPtr sasl, + const char *serverin, + size_t serverinlen, + sasl_interact_t **prompt_need, + const char **clientout, + size_t *clientoutlen); + +int virNetSASLSessionServerStart(virNetSASLSessionPtr sasl, + const char *mechname, + const char *clientin, + size_t clientinlen, + const char **serverout, + size_t *serveroutlen); + +int virNetSASLSessionServerStep(virNetSASLSessionPtr sasl, + const char *clientin, + size_t clientinlen, + const char **serverout, + size_t *serveroutlen); + +ssize_t virNetSASLSessionEncode(virNetSASLSessionPtr sasl, + const char *input, + size_t inputLen, + const char **output, + size_t *outputlen); + +ssize_t virNetSASLSessionDecode(virNetSASLSessionPtr sasl, + const char *input, + size_t inputLen, + const char **output, + size_t *outputlen); + +void virNetSASLSessionFree(virNetSASLSessionPtr sasl); + +#endif /* __VIR_NET_CLIENT_SASL_CONTEXT_H__ */ -- 1.7.2.3

On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
This provides two modules for handling SASL
* virNetSASLContext provides the process-wide state, currently just a whitelist of usernames on the server and a one time library init call
* virNetTLSSession provides the per-connection state, ie the SASL session itself. This also include APIs for providing data encryption/decryption once the session is established
* src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetsaslcontext.c, src/rpc/virnetsaslcontext.h: Generic SASL handling code --- po/POTFILES.in | 1 + src/Makefile.am | 3 + src/rpc/virnetsaslcontext.c | 525 +++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetsaslcontext.h | 125 ++++++++++ 4 files changed, 654 insertions(+), 0 deletions(-) create mode 100644 src/rpc/virnetsaslcontext.c create mode 100644 src/rpc/virnetsaslcontext.h
Several patches need to modify the cfg.mk lists of free-like functions and/or message functions that require translated parameters. For example 2/15 - virNetMessageFree, virNetError 3/15 - virNetSocketFree 4/15 - virNetTLSContextFree, virNetTLSSessionFree 5/15 - virNetSASLContextFree, virNetSASLSessionFree and probably others later in the series as well (I just noticed the issue, so I won't report it in the other patches).
+int virNetSASLContextCheckIdentity(virNetSASLContextPtr ctxt, + const char *identity) +{ + const char *const*wildcards; + + /* If the list is not set, allow any DN. */ + wildcards = ctxt->usernameWhitelist; + if (!wildcards) + return 1; /* No ACL, allow all */ + + while (*wildcards) { + if (fnmatch (*wildcards, identity, 0) == 0) + return 1; /* Allowed */
Same comment about returning -1 as in 4/15 if fnmatch returns failure rather than no match, such as for ill-formed wildcard.
+int virNetSASLSessionExtKeySize(virNetSASLSessionPtr sasl, + int ssf)
Wonky indentation.
+ +int virNetSASLSessionSecProps(virNetSASLSessionPtr sasl, + int minSSF, + int maxSSF, + bool allowAnonymous) +{ + sasl_security_properties_t secprops; + int err; + + memset (&secprops, 0, sizeof secprops); + + secprops.min_ssf = minSSF; + secprops.max_ssf = maxSSF; + secprops.maxbufsize = 100000;
How was this arbitrary number picked? Should it be larger, to accommodate REMOTE_MESSAGE_MAX (262144)?
+int virNetSASLSessionServerStep(virNetSASLSessionPtr sasl,
+ default: + VIR_DEBUG("Foo %s", sasl_errdetail(sasl->conn));
Interesting debug message; should "Foo" have been something more legible?
+ssize_t virNetSASLSessionEncode(virNetSASLSessionPtr sasl, + const char *input, + size_t inputLen, + const char **output, + size_t *outputlen) +{ + unsigned inlen = inputLen;
Should you check and fail if ((unsigned)inputLen != inputLen), since sasl_* (unlike gnutls_*) used int rather than size_t as the maximum transaction size? Or are we assuming that libvirt will never try to exceed a transaction size of REMOTE_MESSAGE_MAX in the first place, so we don't have to worry about the 2GB limit being abused?
+ssize_t virNetSASLSessionDecode(virNetSASLSessionPtr sasl, + const char *input, + size_t inputLen, + const char **output, + size_t *outputlen) +{ + unsigned inlen = inputLen;
Likewise. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Thu, Dec 16, 2010 at 04:36:34PM -0700, Eric Blake wrote:
On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
This provides two modules for handling SASL
* virNetSASLContext provides the process-wide state, currently just a whitelist of usernames on the server and a one time library init call
* virNetTLSSession provides the per-connection state, ie the SASL session itself. This also include APIs for providing data encryption/decryption once the session is established
* src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetsaslcontext.c, src/rpc/virnetsaslcontext.h: Generic SASL handling code --- po/POTFILES.in | 1 + src/Makefile.am | 3 + src/rpc/virnetsaslcontext.c | 525 +++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetsaslcontext.h | 125 ++++++++++ 4 files changed, 654 insertions(+), 0 deletions(-) create mode 100644 src/rpc/virnetsaslcontext.c create mode 100644 src/rpc/virnetsaslcontext.h
+ +int virNetSASLSessionSecProps(virNetSASLSessionPtr sasl, + int minSSF, + int maxSSF, + bool allowAnonymous) +{ + sasl_security_properties_t secprops; + int err; + + memset (&secprops, 0, sizeof secprops); + + secprops.min_ssf = minSSF; + secprops.max_ssf = maxSSF; + secprops.maxbufsize = 100000;
How was this arbitrary number picked? Should it be larger, to accommodate REMOTE_MESSAGE_MAX (262144)?
Well it was just copied from existing code, but looking at the detailed SASL library API docs, it seems maxbufsize sets the maximum len that can be passed to sasl_encode/decode. SASL may give you back a smaller maxbufsize, so we need to check it after negotiating the session. Then we need to make sure we don't call sasl_encode/decode with too large a value. This shouldn't be too difficult we can just limit the number of bytes and the code should already do the right thing to encode the rest later.
+int virNetSASLSessionServerStep(virNetSASLSessionPtr sasl,
+ default: + VIR_DEBUG("Foo %s", sasl_errdetail(sasl->conn));
Interesting debug message; should "Foo" have been something more legible?
+ssize_t virNetSASLSessionEncode(virNetSASLSessionPtr sasl, + const char *input, + size_t inputLen, + const char **output, + size_t *outputlen) +{ + unsigned inlen = inputLen;
Should you check and fail if ((unsigned)inputLen != inputLen), since sasl_* (unlike gnutls_*) used int rather than size_t as the maximum transaction size? Or are we assuming that libvirt will never try to exceed a transaction size of REMOTE_MESSAGE_MAX in the first place, so we don't have to worry about the 2GB limit being abused?
It is worth adding a check there, even though we don't ever send more than a few hundred KB. Daniel

This extends the basic virNetSocket APIs to allow them to have a handle to the TLS/SASL session objects, once established. This ensures that any data reads/writes are automagically passed through the TLS/SASL encryption layers if required. * src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Wire up SASL/TLS encryption --- src/rpc/virnetsocket.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++- src/rpc/virnetsocket.h | 7 ++ 2 files changed, 216 insertions(+), 2 deletions(-) diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 2bcb8fa..08f4f88 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -55,6 +55,17 @@ struct _virNetSocket { virSocketAddr remoteAddr; char *localAddrStr; char *remoteAddrStr; + + virNetTLSSessionPtr tlsSession; + virNetSASLSessionPtr saslSession; + + const char *saslDecoded; + size_t saslDecodedLength; + size_t saslDecodedOffset; + + const char *saslEncoded; + size_t saslEncodedLength; + size_t saslEncodedOffset; }; @@ -564,6 +575,12 @@ void virNetSocketFree(virNetSocketPtr sock) sock->localAddr.data.un.sun_path[0] != '\0') unlink(sock->localAddr.data.un.sun_path); + /* Make sure it can't send any more I/O during shutdown */ + if (sock->tlsSession) + virNetTLSSessionSetIOCallbacks(sock->tlsSession, NULL, NULL, NULL); + virNetTLSSessionFree(sock->tlsSession); + virNetSASLSessionFree(sock->saslSession); + VIR_FORCE_CLOSE(sock->fd); VIR_FORCE_CLOSE(sock->errfd); @@ -609,14 +626,204 @@ const char *virNetSocketRemoteAddrString(virNetSocketPtr sock) return sock->remoteAddrStr; } -ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len) + +static ssize_t virNetSocketTLSSessionWrite(const char *buf, + size_t len, + void *opaque) { + virNetSocketPtr sock = opaque; + return write(sock->fd, buf, len); +} + + +static ssize_t virNetSocketTLSSessionRead(char *buf, + size_t len, + void *opaque) +{ + virNetSocketPtr sock = opaque; return read(sock->fd, buf, len); } + +void virNetSocketSetTLSSession(virNetSocketPtr sock, + virNetTLSSessionPtr sess) +{ + if (sock->tlsSession) + virNetTLSSessionFree(sock->tlsSession); + sock->tlsSession = sess; + virNetTLSSessionSetIOCallbacks(sess, + virNetSocketTLSSessionWrite, + virNetSocketTLSSessionRead, + sock); + virNetTLSSessionRef(sess); +} + +void virNetSocketSetSASLSession(virNetSocketPtr sock, + virNetSASLSessionPtr sess) +{ + if (sock->saslSession) + virNetSASLSessionFree(sock->saslSession); + sock->saslSession = sess; + virNetSASLSessionRef(sess); +} + +static ssize_t virNetSocketReadWire(virNetSocketPtr sock, char *buf, size_t len) +{ + ssize_t ret; +reread: + if (sock->tlsSession && + virNetTLSSessionGetHandshakeStatus(sock->tlsSession) == + VIR_NET_TLS_HANDSHAKE_COMPLETE) { + ret = virNetTLSSessionRead(sock->tlsSession, buf, len); + } else { + ret = read(sock->fd, buf, len); + } + + if (ret < 0) { + if (errno == EINTR) + goto reread; + if (errno == EAGAIN) + return 0; + + virReportSystemError(errno, "%s", + _("Cannot recv data")); + return -1; + } + if (ret == 0) { + virReportSystemError(EIO, "%s", + _("End of file while reading data")); + return -1; + } + + return ret; +} + +static ssize_t virNetSocketWriteWire(virNetSocketPtr sock, const char *buf, size_t len) +{ + ssize_t ret; +rewrite: + if (sock->tlsSession && + virNetTLSSessionGetHandshakeStatus(sock->tlsSession) == + VIR_NET_TLS_HANDSHAKE_COMPLETE) { + ret = virNetTLSSessionWrite(sock->tlsSession, buf, len); + } else { + ret = write(sock->fd, buf, len); + } + + if (ret < 0) { + if (errno == EINTR) + goto rewrite; + if (errno == EAGAIN) + return 0; + + virReportSystemError(errno, "%s", + _("Cannot write data")); + return -1; + } + if (ret == 0) { + virReportSystemError(EIO, "%s", + _("End of file while writing data")); + return -1; + } + + return ret; +} + +static ssize_t virNetSocketReadSASL(virNetSocketPtr sock, char *buf, size_t len) +{ + ssize_t got; + + /* Need to read some more data off the wire */ + if (sock->saslDecoded == NULL) { + char encoded[8192]; + ssize_t encodedLen = sizeof(encoded); + encodedLen = virNetSocketReadWire(sock, encoded, encodedLen); + + if (encodedLen <= 0) + return encodedLen; + + if (virNetSASLSessionDecode(sock->saslSession, + encoded, encodedLen, + &sock->saslDecoded, &sock->saslDecodedLength) < 0) + return -1; + + sock->saslDecodedOffset = 0; + } + + /* Some buffered decoded data to return now */ + got = sock->saslDecodedLength - sock->saslDecodedOffset; + + if (len > got) + len = got; + + memcpy(buf, sock->saslDecoded + sock->saslDecodedOffset, len); + sock->saslDecodedOffset += len; + + if (sock->saslDecodedOffset == sock->saslDecodedLength) { + sock->saslDecoded = NULL; + sock->saslDecodedOffset = sock->saslDecodedLength = 0; + } + + return len; +} + +static ssize_t virNetSocketWriteSASL(virNetSocketPtr sock, const char *buf, size_t len) +{ + int ret; + + /* Not got any pending encoded data, so we need to encode raw stuff */ + if (sock->saslEncoded == NULL) { + if (virNetSASLSessionEncode(sock->saslSession, + buf, len, + &sock->saslEncoded, + &sock->saslEncodedLength) < 0) + return -1; + + sock->saslEncodedOffset = 0; + } + + /* Send some of the encoded stuff out on the wire */ + ret = virNetSocketWriteWire(sock, + sock->saslEncoded + sock->saslEncodedOffset, + sock->saslEncodedLength - sock->saslEncodedOffset); + + if (ret <= 0) + return ret; /* -1 error, 0 == egain */ + + /* Note how much we sent */ + sock->saslEncodedOffset += ret; + + /* Sent all encoded, so update raw buffer to indicate completion */ + if (sock->saslEncodedOffset == sock->saslEncodedLength) { + sock->saslEncoded = NULL; + sock->saslEncodedOffset = sock->saslEncodedLength = 0; + + /* Mark as complete, so caller detects completion */ + return len; + } else { + /* Still have stuff pending in saslEncoded buffer. + * Pretend to caller that we didn't send any yet. + * The caller will then retry with same buffer + * shortly, which lets us finish saslEncoded. + */ + return 0; + } +} + +ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len) +{ + if (sock->saslSession) + return virNetSocketReadSASL(sock, buf, len); + else + return virNetSocketReadWire(sock, buf, len); +} + ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len) { - return write(sock->fd, buf, len); + if (sock->saslSession) + return virNetSocketWriteSASL(sock, buf, len); + else + return virNetSocketWriteWire(sock, buf, len); } diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h index 4441848..94a5f30 100644 --- a/src/rpc/virnetsocket.h +++ b/src/rpc/virnetsocket.h @@ -26,6 +26,8 @@ # include "network.h" # include "command.h" +# include "virnettlscontext.h" +# include "virnetsaslcontext.h" typedef struct _virNetSocket virNetSocket; typedef virNetSocket *virNetSocketPtr; @@ -76,6 +78,11 @@ bool virNetSocketIsLocal(virNetSocketPtr sock); ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len); ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len); +void virNetSocketSetTLSSession(virNetSocketPtr sock, + virNetTLSSessionPtr sess); +void virNetSocketSetSASLSession(virNetSocketPtr sock, + virNetSASLSessionPtr sess); + void virNetSocketFree(virNetSocketPtr sock); const char *virNetSocketLocalAddrString(virNetSocketPtr sock); -- 1.7.2.3

On 12/16/2010 04:21 AM, Daniel P. Berrange wrote:
This extends the basic virNetSocket APIs to allow them to have a handle to the TLS/SASL session objects, once established. This ensures that any data reads/writes are automagically passed through the TLS/SASL encryption layers if required.
* src/rpc/virnetsocket.c, src/rpc/virnetsocket.h: Wire up SASL/TLS encryption --- src/rpc/virnetsocket.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++- src/rpc/virnetsocket.h | 7 ++ 2 files changed, 216 insertions(+), 2 deletions(-)
Cool! We have to resolve the parent commits before this can be pushed, but I didn't spot any obvious flaws. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

To facilitate creation of new daemons providing XDR RPC services, pull alot of the libvirtd daemon code into a set of reusable objects. * virNetServer: A server contains one or more services which accept incoming clients. It maintains the list of active clients. It has a list of RPC programs which can be used by clients. When clients produce a complete RPC message, the server passes this onto the corresponding program for handling, and queues any response back with the client. * virNetServerClient: Encapsulates a single client connection. All I/O for the client is handled, reading & writing RPC messages. * virNetServerProgram: Handles processing and dispatch of RPC method calls for a single RPC (program,version). Multiple programs can be registered with the server. * virNetServerService: Encapsulates socket(s) listening for new connections. Each service listens on a single host/port, but may have multiple sockets if on a dual IPv4/6 host. Each new daemon now merely has to define the list of RPC procedures & their handlers. It does not need to deal with any network related functionality at all. --- po/POTFILES.in | 3 + src/Makefile.am | 17 +- src/rpc/virnetserver.c | 684 ++++++++++++++++++++++++++++++ src/rpc/virnetserver.h | 80 ++++ src/rpc/virnetserverclient.c | 917 +++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetserverclient.h | 101 +++++ src/rpc/virnetserverprogram.c | 477 +++++++++++++++++++++ src/rpc/virnetserverprogram.h | 104 +++++ src/rpc/virnetserverservice.c | 247 +++++++++++ src/rpc/virnetserverservice.h | 65 +++ 10 files changed, 2694 insertions(+), 1 deletions(-) create mode 100644 src/rpc/virnetserver.c create mode 100644 src/rpc/virnetserver.h create mode 100644 src/rpc/virnetserverclient.c create mode 100644 src/rpc/virnetserverclient.h create mode 100644 src/rpc/virnetserverprogram.c create mode 100644 src/rpc/virnetserverprogram.h create mode 100644 src/rpc/virnetserverservice.c create mode 100644 src/rpc/virnetserverservice.h diff --git a/po/POTFILES.in b/po/POTFILES.in index bb8c0b2..bb84ea3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -61,6 +61,9 @@ src/remote/remote_driver.c src/rpc/virnetmessage.c src/rpc/virnetsaslcontext.c src/rpc/virnetsocket.c +src/rpc/virnetserver.c +src/rpc/virnetserverclient.c +src/rpc/virnetserverprogram.c src/rpc/virnettlscontext.c src/secret/secret_driver.c src/security/security_apparmor.c diff --git a/src/Makefile.am b/src/Makefile.am index def7e0a..15a70d6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1118,7 +1118,7 @@ libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD) EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) -noinst_LTLIBRARIES += libvirt-net-rpc.la +noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt-net-rpc-server.la libvirt_net_rpc_la_SOURCES = \ ../daemon/event.c \ @@ -1140,6 +1140,21 @@ libvirt_net_rpc_la_LDFLAGS = \ libvirt_net_rpc_la_LIBADD = \ $(CYGWIN_EXTRA_LIBADD) +libvirt_net_rpc_server_la_SOURCES = \ + rpc/virnetserverprogram.h rpc/virnetserverprogram.c \ + rpc/virnetserverservice.h rpc/virnetserverservice.c \ + rpc/virnetserverclient.h rpc/virnetserverclient.c \ + rpc/virnetserver.h rpc/virnetserver.c +libvirt_net_rpc_server_la_CFLAGS = \ + $(AM_CFLAGS) +libvirt_net_rpc_server_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(CYGWIN_EXTRA_LDFLAGS) \ + $(MINGW_EXTRA_LDFLAGS)l +libvirt_net_rpc_server_la_LIBADD = \ + $(CYGWIN_EXTRA_LIBADD) + + libexec_PROGRAMS = if WITH_STORAGE_DISK diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c new file mode 100644 index 0000000..ff365d7 --- /dev/null +++ b/src/rpc/virnetserver.c @@ -0,0 +1,684 @@ +/* + * virnetserver.c: generic network RPC server + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <unistd.h> +#include <string.h> + +#include "virnetserver.h" +#include "logging.h" +#include "memory.h" +#include "virterror_internal.h" +#include "threads.h" +#include "threadpool.h" +#include "util.h" +#include "files.h" +#include "event.h" +#include "../daemon/event.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +typedef struct _virNetServerSignal virNetServerSignal; +typedef virNetServerSignal *virNetServerSignalPtr; + +struct _virNetServerSignal { + struct sigaction oldaction; + int signum; + virNetServerSignalFunc func; + void *opaque; +}; + +typedef struct _virNetServerJob virNetServerJob; +typedef virNetServerJob *virNetServerJobPtr; + +struct _virNetServerJob { + virNetServerClientPtr client; + virNetMessagePtr msg; +}; + +struct _virNetServer { + int refs; + + virMutex lock; + + virThreadPoolPtr workers; + + bool privileged; + + size_t nsignals; + virNetServerSignalPtr *signals; + int sigread; + int sigwrite; + int sigwatch; + + size_t nservices; + virNetServerServicePtr *services; + + size_t nprograms; + virNetServerProgramPtr *programs; + + size_t nclients; + size_t nclients_max; + virNetServerClientPtr *clients; + + unsigned int quit :1; + + virNetTLSContextPtr tls; + + unsigned int autoShutdownTimeout; + virNetServerAutoShutdownFunc autoShutdownFunc; + void *autoShutdownOpaque; + + virNetServerClientInitHook clientInitHook; +}; + + +static void virNetServerLock(virNetServerPtr srv) +{ + virMutexLock(&srv->lock); +} + +static void virNetServerUnlock(virNetServerPtr srv) +{ + virMutexUnlock(&srv->lock); +} + + +static void virNetServerHandleJob(void *jobOpaque, void *opaque) +{ + virNetServerPtr srv = opaque; + virNetServerJobPtr job = jobOpaque; + virNetServerProgramPtr prog = NULL; + size_t i; + + virNetServerClientRef(job->client); + + virNetServerLock(srv); + VIR_DEBUG("server=%p client=%p message=%p", + srv, job->client, job->msg); + + for (i = 0 ; i < srv->nprograms ; i++) { + if (virNetServerProgramMatches(srv->programs[i], job->msg)) { + prog = srv->programs[i]; + break; + } + } + + if (!prog) { + VIR_DEBUG("Cannot find program %d version %d", + job->msg->header.prog, + job->msg->header.vers); + goto error; + } + + virNetServerProgramRef(prog); + virNetServerUnlock(srv); + + if (virNetServerProgramDispatch(prog, + srv, + job->client, + job->msg) < 0) + goto error; + + virNetServerLock(srv); + virNetServerProgramFree(prog); + virNetServerUnlock(srv); + virNetServerClientFree(job->client); + + VIR_FREE(job); + return; + +error: + virNetServerUnlock(srv); + if (prog) + virNetServerProgramFree(prog); + virNetMessageFree(job->msg); + virNetServerClientClose(job->client); + virNetServerClientFree(job->client); + VIR_FREE(job); +} + + +static int virNetServerDispatchNewMessage(virNetServerClientPtr client, + virNetMessagePtr msg, + void *opaque) +{ + virNetServerPtr srv = opaque; + virNetServerJobPtr job; + int ret; + + VIR_DEBUG("server=%p client=%p message=%p", + srv, client, msg); + + if (VIR_ALLOC(job) < 0) { + virReportOOMError(); + return -1; + } + + job->client = client; + job->msg = msg; + + virNetServerLock(srv); + if ((ret = virThreadPoolSendJob(srv->workers, job)) < 0) + VIR_FREE(job); + virNetServerUnlock(srv); + + return ret; +} + + +static int virNetServerDispatchNewClient(virNetServerServicePtr svc ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + void *opaque) +{ + virNetServerPtr srv = opaque; + + virNetServerLock(srv); + + if (srv->nclients >= srv->nclients_max) { + virNetError(VIR_ERR_RPC, + _("Too many active clients (%zu), dropping connection from %s"), + srv->nclients_max, virNetServerClientRemoteAddrString(client)); + goto error; + } + + if (virNetServerClientInit(client) < 0) + goto error; + + if (srv->clientInitHook && + srv->clientInitHook(srv, client) < 0) + goto error; + + if (VIR_EXPAND_N(srv->clients, srv->nclients, 1) < 0) { + virReportOOMError(); + goto error; + } + srv->clients[srv->nclients-1] = client; + virNetServerClientRef(client); + + virNetServerClientSetDispatcher(client, + virNetServerDispatchNewMessage, + srv); + + virNetServerUnlock(srv); + return 0; + +error: + virNetServerUnlock(srv); + return -1; +} + + +virNetServerPtr virNetServerNew(size_t min_workers, + size_t max_workers, + size_t max_clients, + virNetServerClientInitHook clientInitHook) +{ + virNetServerPtr srv; + struct sigaction sig_action; + + if (VIR_ALLOC(srv) < 0) { + virReportOOMError(); + return NULL; + } + + srv->refs = 1; + + if (!(srv->workers = virThreadPoolNew(min_workers, max_workers, + virNetServerHandleJob, + srv))) + goto error; + + srv->nclients_max = max_clients; + srv->sigwrite = srv->sigread = -1; + srv->clientInitHook = clientInitHook; + srv->privileged = geteuid() == 0 ? true : false; + + if (virMutexInit(&srv->lock) < 0) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize mutex")); + goto error; + } + + if (virEventInit() < 0) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to initialize event system")); + goto error; + } + + virEventRegisterImpl(virEventAddHandleImpl, + virEventUpdateHandleImpl, + virEventRemoveHandleImpl, + virEventAddTimeoutImpl, + virEventUpdateTimeoutImpl, + virEventRemoveTimeoutImpl); + + memset(&sig_action, 0, sizeof(sig_action)); + sig_action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sig_action, NULL); + + VIR_DEBUG("srv=%p refs=%d", srv, srv->refs); + return srv; + +error: + virNetServerFree(srv); + return NULL; +} + + +void virNetServerRef(virNetServerPtr srv) +{ + virNetServerLock(srv); + srv->refs++; + VIR_DEBUG("srv=%p refs=%d", srv, srv->refs); + virNetServerUnlock(srv); +} + + +bool virNetServerIsPrivileged(virNetServerPtr srv) +{ + bool priv; + virNetServerLock(srv); + priv = srv->privileged; + virNetServerUnlock(srv); + return priv; +} + + +void virNetServerAutoShutdown(virNetServerPtr srv, + unsigned int timeout, + virNetServerAutoShutdownFunc func, + void *opaque) +{ + virNetServerLock(srv); + + srv->autoShutdownTimeout = timeout; + srv->autoShutdownFunc = func; + srv->autoShutdownOpaque = opaque; + + virNetServerUnlock(srv); +} + + +static sig_atomic_t sigErrors = 0; +static int sigLastErrno = 0; +static int sigWrite = -1; + +static void virNetServerSignalHandler(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) { + sigErrors++; + sigLastErrno = errno; + } + errno = origerrno; +} + +static void +virNetServerSignalEvent(int watch, + int fd ATTRIBUTE_UNUSED, + int events ATTRIBUTE_UNUSED, + void *opaque) { + virNetServerPtr srv = opaque; + siginfo_t siginfo; + int i; + + virNetServerLock(srv); + + if (saferead(srv->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) { + virReportSystemError(errno, "%s", + _("Failed to read from signal pipe")); + virEventRemoveHandle(watch); + srv->sigwatch = -1; + goto cleanup; + } + + for (i = 0 ; i < srv->nsignals ; i++) { + if (siginfo.si_signo == srv->signals[i]->signum) { + virNetServerSignalFunc func = srv->signals[i]->func; + void *funcopaque = srv->signals[i]->opaque; + virNetServerUnlock(srv); + func(srv, &siginfo, funcopaque); + return; + } + } + + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected signal received: %d"), siginfo.si_signo); + +cleanup: + virNetServerUnlock(srv); +} + +static int virNetServerSignalSetup(virNetServerPtr srv) +{ + int fds[2]; + + if (srv->sigwrite != -1) + return 0; + + if (pipe(fds) < 0) { + virReportSystemError(errno, "%s", + _("Unable to create signal pipe")); + return -1; + } + + if (virSetNonBlock(fds[0]) < 0 || + virSetNonBlock(fds[1]) < 0 || + virSetCloseExec(fds[0]) < 0 || + virSetCloseExec(fds[1]) < 0) { + virReportSystemError(errno, "%s", + _("Failed to setup pipe flags")); + goto error; + } + + if ((srv->sigwatch = virEventAddHandle(fds[0], + VIR_EVENT_HANDLE_READABLE, + virNetServerSignalEvent, + srv, NULL)) < 0) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to add signal handle watch")); + goto error; + } + + srv->sigread = fds[0]; + srv->sigwrite = fds[1]; + sigWrite = fds[1]; + + return 0; + +error: + VIR_FORCE_CLOSE(fds[0]); + VIR_FORCE_CLOSE(fds[1]); + return -1; +} + +int virNetServerAddSignalHandler(virNetServerPtr srv, + int signum, + virNetServerSignalFunc func, + void *opaque) +{ + virNetServerSignalPtr sigdata; + struct sigaction sig_action; + + virNetServerLock(srv); + + if (virNetServerSignalSetup(srv) < 0) + goto error; + + if (VIR_EXPAND_N(srv->signals, srv->nsignals, 1) < 0) + goto no_memory; + + if (VIR_ALLOC(sigdata) < 0) + goto no_memory; + + sigdata->signum = signum; + sigdata->func = func; + sigdata->opaque = opaque; + + memset(&sig_action, 0, sizeof(sig_action)); + sig_action.sa_sigaction = virNetServerSignalHandler; + sig_action.sa_flags = SA_SIGINFO; + sigemptyset(&sig_action.sa_mask); + + sigaction(signum, &sig_action, &sigdata->oldaction); + + srv->signals[srv->nsignals-1] = sigdata; + + virNetServerUnlock(srv); + return 0; + +no_memory: + virReportOOMError(); +error: + VIR_FREE(sigdata); + virNetServerUnlock(srv); + return -1; +} + + + +int virNetServerAddService(virNetServerPtr srv, + virNetServerServicePtr svc) +{ + virNetServerLock(srv); + + if (VIR_EXPAND_N(srv->services, srv->nservices, 1) < 0) + goto no_memory; + + srv->services[srv->nservices-1] = svc; + virNetServerServiceRef(svc); + + virNetServerServiceSetDispatcher(svc, + virNetServerDispatchNewClient, + srv); + + virNetServerUnlock(srv); + return 0; + +no_memory: + virReportOOMError(); + virNetServerUnlock(srv); + return -1; +} + +int virNetServerAddProgram(virNetServerPtr srv, + virNetServerProgramPtr prog) +{ + virNetServerLock(srv); + + if (VIR_EXPAND_N(srv->programs, srv->nprograms, 1) < 0) + goto no_memory; + + srv->programs[srv->nprograms-1] = prog; + virNetServerProgramRef(prog); + + virNetServerUnlock(srv); + return 0; + +no_memory: + virReportOOMError(); + virNetServerUnlock(srv); + return -1; +} + +int virNetServerSetTLSContext(virNetServerPtr srv, + virNetTLSContextPtr tls) +{ + srv->tls = tls; + virNetTLSContextRef(tls); + return 0; +} + + +static void virNetServerAutoShutdownTimer(int timerid ATTRIBUTE_UNUSED, + void *opaque) { + virNetServerPtr srv = opaque; + + virNetServerLock(srv); + + if (srv->autoShutdownFunc(srv, srv->autoShutdownOpaque)) { + VIR_DEBUG0("Automatic shutdown triggered"); + srv->quit = 1; + } + + virNetServerUnlock(srv); +} + + +void virNetServerUpdateServices(virNetServerPtr srv, + bool enabled) +{ + int i; + + virNetServerLock(srv); + for (i = 0 ; i < srv->nservices ; i++) + virNetServerServiceToggle(srv->services[i], enabled); + + virNetServerUnlock(srv); +} + + +void virNetServerRun(virNetServerPtr srv) +{ + int timerid = -1; + int timerActive = 0; + int i; + + virNetServerLock(srv); + + if (srv->autoShutdownTimeout && + (timerid = virEventAddTimeout(-1, + virNetServerAutoShutdownTimer, + srv, NULL)) < 0) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Failed to register shutdown timeout")); + goto cleanup; + } + + while (!srv->quit) { + /* A shutdown timeout is specified, so check + * if any drivers have active state, if not + * shutdown after timeout seconds + */ + if (srv->autoShutdownTimeout) { + if (timerActive) { + if (srv->clients) { + DEBUG("Deactivating shutdown timer %d", timerid); + virEventUpdateTimeout(timerid, -1); + timerActive = 0; + } + } else { + if (!srv->clients) { + DEBUG("Activating shutdown timer %d", timerid); + virEventUpdateTimeout(timerid, + srv->autoShutdownTimeout * 1000); + timerActive = 1; + } + } + } + + virNetServerUnlock(srv); + if (virEventRunOnce() < 0) { + virNetServerLock(srv); + DEBUG0("Loop iteration error, exiting"); + break; + } + virNetServerLock(srv); + + reprocess: + for (i = 0 ; i < srv->nclients ; i++) { + if (virNetServerClientWantClose(srv->clients[i])) + virNetServerClientClose(srv->clients[i]); + if (virNetServerClientIsClosed(srv->clients[i])) { + virNetServerClientFree(srv->clients[i]); + if (srv->nclients > 1) { + memmove(srv->clients + i, + srv->clients + i + 1, + sizeof(*srv->clients) * (srv->nclients - (i + 1))); + VIR_SHRINK_N(srv->clients, srv->nclients, 1); + } else { + VIR_FREE(srv->clients); + srv->nclients = 0; + } + + goto reprocess; + } + } + } + +cleanup: + virNetServerUnlock(srv); +} + + +void virNetServerQuit(virNetServerPtr srv) +{ + virNetServerLock(srv); + + srv->quit = 1; + + virNetServerUnlock(srv); +} + +void virNetServerFree(virNetServerPtr srv) +{ + int i; + + if (!srv) + return; + + virNetServerLock(srv); + VIR_DEBUG("srv=%p refs=%d", srv, srv->refs); + srv->refs--; + if (srv->refs > 0) { + virNetServerUnlock(srv); + return; + } + + for (i = 0 ; i < srv->nservices ; i++) + virNetServerServiceToggle(srv->services[i], false); + + virThreadPoolFree(srv->workers); + + for (i = 0 ; i < srv->nsignals ; i++) { + sigaction(srv->signals[i]->signum, &srv->signals[i]->oldaction, NULL); + VIR_FREE(srv->signals[i]); + } + VIR_FREE(srv->signals); + VIR_FORCE_CLOSE(srv->sigread); + VIR_FORCE_CLOSE(srv->sigwrite); + if (srv->sigwatch > 0) + virEventRemoveHandle(srv->sigwatch); + + for (i = 0 ; i < srv->nservices ; i++) + virNetServerServiceFree(srv->services[i]); + VIR_FREE(srv->services); + + for (i = 0 ; i < srv->nprograms ; i++) + virNetServerProgramFree(srv->programs[i]); + VIR_FREE(srv->programs); + + for (i = 0 ; i < srv->nclients ; i++) { + virNetServerClientClose(srv->clients[i]); + virNetServerClientFree(srv->clients[i]); + } + VIR_FREE(srv->clients); + + virNetServerUnlock(srv); + virMutexDestroy(&srv->lock); + VIR_FREE(srv); +} diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h new file mode 100644 index 0000000..8b8b6a9 --- /dev/null +++ b/src/rpc/virnetserver.h @@ -0,0 +1,80 @@ +/* + * virnetserver.h: generic network RPC server + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_NET_SERVER_H__ +# define __VIR_NET_SERVER_H__ + +# include <stdbool.h> +# include <signal.h> + +# include "virnettlscontext.h" +# include "virnetserverprogram.h" +# include "virnetserverclient.h" +# include "virnetserverservice.h" + +typedef int (*virNetServerClientInitHook)(virNetServerPtr srv, + virNetServerClientPtr client); + +virNetServerPtr virNetServerNew(size_t min_workers, + size_t max_workers, + size_t max_clients, + virNetServerClientInitHook clientInitHook); + +typedef int (*virNetServerAutoShutdownFunc)(virNetServerPtr srv, void *opaque); + +void virNetServerRef(virNetServerPtr srv); + +bool virNetServerIsPrivileged(virNetServerPtr srv); + +void virNetServerAutoShutdown(virNetServerPtr srv, + unsigned int timeout, + virNetServerAutoShutdownFunc func, + void *opaque); + +typedef void (*virNetServerSignalFunc)(virNetServerPtr srv, siginfo_t *info, void *opaque); + +int virNetServerAddSignalHandler(virNetServerPtr srv, + int signum, + virNetServerSignalFunc func, + void *opaque); + +int virNetServerAddService(virNetServerPtr srv, + virNetServerServicePtr svc); + +int virNetServerAddProgram(virNetServerPtr srv, + virNetServerProgramPtr prog); + +int virNetServerSetTLSContext(virNetServerPtr srv, + virNetTLSContextPtr tls); + +void virNetServerUpdateServices(virNetServerPtr srv, + bool enabled); + +void virNetServerRun(virNetServerPtr srv); + +void virNetServerQuit(virNetServerPtr srv); + +void virNetServerFree(virNetServerPtr srv); + + +#endif diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c new file mode 100644 index 0000000..226849e --- /dev/null +++ b/src/rpc/virnetserverclient.c @@ -0,0 +1,917 @@ +/* + * virnetserverclient.c: generic network RPC server client + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#if HAVE_SASL +# include <sasl/sasl.h> +#endif + +#include "virnetserverclient.h" + +#include "logging.h" +#include "virterror_internal.h" +#include "memory.h" +#include "threads.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +/* Allow for filtering of incoming messages to a custom + * dispatch processing queue, instead of the workers. + * This allows for certain types of messages to be handled + * strictly "in order" + */ + +typedef struct _virNetServerClientFilter virNetServerClientFilter; +typedef virNetServerClientFilter *virNetServerClientFilterPtr; + +struct _virNetServerClientFilter { + int id; + virNetServerClientFilterFunc func; + void *opaque; + + virNetServerClientFilterPtr next; +}; + + +struct _virNetServerClient +{ + int refs; + bool wantClose; + virMutex lock; + virNetSocketPtr sock; + int auth; + bool readonly; + char *identity; + virNetTLSContextPtr tlsCtxt; + virNetTLSSessionPtr tls; + virNetSASLSessionPtr sasl; + + /* Count of messages in the 'tx' queue, + * and the server worker pool queue + * ie RPC calls in progress. Does not count + * async events which are not used for + * throttling calculations */ + size_t nrequests; + size_t nrequests_max; + /* Zero or one messages being received. Zero if + * nrequests >= max_clients and throttling */ + virNetMessagePtr rx; + /* Zero or many messages waiting for transmit + * back to client, including async events */ + virNetMessagePtr tx; + + /* Filters to capture messages that would otherwise + * end up on the 'dx' queue */ + virNetServerClientFilterPtr filters; + int nextFilterID; + + virNetServerClientDispatchFunc dispatchFunc; + void *dispatchOpaque; + + void *privateData; + virNetServerClientFreeFunc privateDataFreeFunc; +}; + + +static void virNetServerClientDispatchEvent(virNetSocketPtr sock, int events, void *opaque); +static void virNetServerClientUpdateEvent(virNetServerClientPtr client); + +static void virNetServerClientLock(virNetServerClientPtr client) +{ + virMutexLock(&client->lock); +} + +static void virNetServerClientUnlock(virNetServerClientPtr client) +{ + virMutexUnlock(&client->lock); +} + + +/* + * @client: a locked client object + */ +static int +virNetServerClientCalculateHandleMode(virNetServerClientPtr client) { + int mode = 0; + + + VIR_DEBUG("tls=%p hs=%d, rx=%p tx=%p", + client->tls, + client->tls ? virNetTLSSessionGetHandshakeStatus(client->tls) : -1, + client->rx, + client->tx); + if (!client->sock || client->wantClose) + return 0; + + if (client->tls) { + switch (virNetTLSSessionGetHandshakeStatus(client->tls)) { + case VIR_NET_TLS_HANDSHAKE_RECVING: + mode |= VIR_EVENT_HANDLE_READABLE; + break; + case VIR_NET_TLS_HANDSHAKE_SENDING: + mode |= VIR_EVENT_HANDLE_WRITABLE; + break; + default: + case VIR_NET_TLS_HANDSHAKE_COMPLETE: + if (client->rx) + mode |= VIR_EVENT_HANDLE_READABLE; + if (client->tx) + 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; + } + VIR_DEBUG("mode=%d", mode); + return mode; +} + +/* + * @server: a locked or unlocked server object + * @client: a locked client object + */ +static int virNetServerClientRegisterEvent(virNetServerClientPtr client) +{ + int mode = virNetServerClientCalculateHandleMode(client); + + VIR_DEBUG("Registering client event callback %d", mode); + if (virNetSocketAddIOCallback(client->sock, + mode, + virNetServerClientDispatchEvent, + client) < 0) + return -1; + + return 0; +} + +/* + * @client: a locked client object + */ +static void virNetServerClientUpdateEvent(virNetServerClientPtr client) +{ + int mode; + + if (!client->sock) + return; + + mode = virNetServerClientCalculateHandleMode(client); + + virNetSocketUpdateIOCallback(client->sock, mode); +} + + +int virNetServerClientAddFilter(virNetServerClientPtr client, + virNetServerClientFilterFunc func, + void *opaque) +{ + virNetServerClientFilterPtr filter; + int ret = -1; + + virNetServerClientLock(client); + + if (VIR_ALLOC(filter) < 0) { + virReportOOMError(); + goto cleanup; + } + + filter->id = client->nextFilterID++; + filter->func = func; + filter->opaque = opaque; + + filter->next = client->filters; + client->filters = filter; + + ret = filter->id; + +cleanup: + virNetServerClientUnlock(client); + return ret; +} + + +void virNetServerClientRemoveFilter(virNetServerClientPtr client, + int filterID) +{ + virNetServerClientFilterPtr tmp, prev; + virNetServerClientLock(client); + + prev = NULL; + tmp = client->filters; + while (tmp) { + if (tmp->id == filterID) { + if (prev) + prev->next = tmp->next; + else + client->filters = tmp->next; + + VIR_FREE(tmp); + break; + } + tmp = tmp->next; + } + + virNetServerClientUnlock(client); +} + + +/* Check the client's access. */ +static int +virNetServerClientCheckAccess(virNetServerClientPtr client) +{ + virNetMessagePtr confirm; + + /* Verify client certificate. */ + if (virNetTLSContextCheckCertificate(client->tlsCtxt, client->tls) < 0) + return -1; + + if (client->tx) { + VIR_INFO0(_("client had unexpected data pending tx after access check")); + return -1; + } + + if (!(confirm = virNetMessageNew())) + 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->bufferLength = 1; + confirm->bufferOffset = 0; + confirm->buffer[0] = '\1'; + + client->tx = confirm; + + return 0; +} + + +virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock, + int auth, + bool readonly, + virNetTLSContextPtr tls) +{ + virNetServerClientPtr client; + + VIR_DEBUG("sock=%p auth=%d tls=%p", sock, auth, tls); + + if (VIR_ALLOC(client) < 0) { + virReportOOMError(); + return NULL; + } + + if (virMutexInit(&client->lock) < 0) + goto error; + + client->refs = 1; + client->sock = sock; + client->auth = auth; + client->readonly = readonly; + client->tlsCtxt = tls; + client->nrequests_max = 10; /* XXX */ + + if (tls) + virNetTLSContextRef(tls); + + /* Prepare one for packet receive */ + if (!(client->rx = virNetMessageNew())) + goto error; + client->rx->bufferLength = VIR_NET_MESSAGE_LEN_MAX; + client->nrequests = 1; + + VIR_DEBUG("client=%p refs=%d", client, client->refs); + + return client; + +error: + /* XXX ref counting is better than this */ + client->sock = NULL; /* Caller owns 'sock' upon failure */ + virNetServerClientFree(client); + return NULL; +} + +void virNetServerClientRef(virNetServerClientPtr client) +{ + virNetServerClientLock(client); + client->refs++; + DEBUG("client=%p refs=%d", client, client->refs); + virNetServerClientUnlock(client); +} + + +int virNetServerClientGetAuth(virNetServerClientPtr client) +{ + int auth; + virNetServerClientLock(client); + auth = client->auth; + virNetServerClientUnlock(client); + return auth; +} + +bool virNetServerClientGetReadonly(virNetServerClientPtr client) +{ + bool readonly; + virNetServerClientLock(client); + readonly = client->readonly; + virNetServerClientUnlock(client); + return readonly; +} + + +bool virNetServerClientHasTLSSession(virNetServerClientPtr client) +{ + bool has; + virNetServerClientLock(client); + has = client->tls ? true : false; + virNetServerClientUnlock(client); + return has; +} + +int virNetServerClientGetTLSKeySize(virNetServerClientPtr client) +{ + int size = 0; + virNetServerClientLock(client); + if (client->tls) + size = virNetTLSSessionGetKeySize(client->tls); + virNetServerClientUnlock(client); + return size; +} + +int virNetServerClientGetFD(virNetServerClientPtr client) +{ + int fd = 0; + virNetServerClientLock(client); + fd = virNetSocketGetFD(client->sock); + virNetServerClientUnlock(client); + return fd; +} + +bool virNetServerClientIsSecure(virNetServerClientPtr client) +{ + bool secure = false; + virNetServerClientLock(client); + if (client->tls) + secure = true; + else + secure = virNetSocketIsLocal(client->sock); + virNetServerClientUnlock(client); + return secure; +} + + +void virNetServerClientSetSASLSession(virNetServerClientPtr client, + virNetSASLSessionPtr sasl) +{ + /* We don't set the sasl session on the socket here + * because we need to send out the auth confirmation + * in the clear. Only once we complete the next 'tx' + * operation do we switch to SASL mode + */ + virNetServerClientLock(client); + client->sasl = sasl; + virNetSASLSessionRef(sasl); + virNetServerClientUnlock(client); +} + + +int virNetServerClientSetIdentity(virNetServerClientPtr client, + const char *identity) +{ + int ret = -1; + virNetServerClientLock(client); + if (!(client->identity = strdup(identity))) { + virReportOOMError(); + goto error; + } + ret = 0; + +error: + virNetServerClientUnlock(client); + return ret; +} + +const char *virNetServerClientGetIdentity(virNetServerClientPtr client) +{ + const char *identity; + virNetServerClientLock(client); + identity = client->identity; + virNetServerClientLock(client); + return identity; +} + +void virNetServerClientSetPrivateData(virNetServerClientPtr client, + void *opaque, + virNetServerClientFreeFunc ff) +{ + virNetServerClientLock(client); + + if (client->privateData && + client->privateDataFreeFunc) + client->privateDataFreeFunc(client->privateData); + + client->privateData = opaque; + client->privateDataFreeFunc = ff; + + virNetServerClientUnlock(client); +} + + +void *virNetServerClientGetPrivateData(virNetServerClientPtr client) +{ + void *data; + virNetServerClientLock(client); + data = client->privateData; + virNetServerClientUnlock(client); + return data; +} + + +void virNetServerClientSetDispatcher(virNetServerClientPtr client, + virNetServerClientDispatchFunc func, + void *opaque) +{ + virNetServerClientLock(client); + client->dispatchFunc = func; + client->dispatchOpaque = opaque; + virNetServerClientUnlock(client); +} + + +const char *virNetServerClientLocalAddrString(virNetServerClientPtr client) +{ + return virNetSocketLocalAddrString(client->sock); +} + + +const char *virNetServerClientRemoteAddrString(virNetServerClientPtr client) +{ + return virNetSocketRemoteAddrString(client->sock); +} + + +void virNetServerClientFree(virNetServerClientPtr client) +{ + if (!client) + return; + + virNetServerClientLock(client); + VIR_DEBUG("client=%p refs=%d", client, client->refs); + + client->refs--; + if (client->refs > 0) { + virNetServerClientUnlock(client); + return; + } + + if (client->privateData && + client->privateDataFreeFunc) + client->privateDataFreeFunc(client->privateData); + + VIR_FREE(client->identity); + virNetSASLSessionFree(client->sasl); + virNetTLSSessionFree(client->tls); + virNetTLSContextFree(client->tlsCtxt); + virNetSocketFree(client->sock); + virNetServerClientUnlock(client); + virMutexDestroy(&client->lock); + VIR_FREE(client); +} + + +/* + * + * We don't free stuff here, merely disconnect the client's + * network socket & resources. + * + * Full free of the client is done later in a safe point + * where it can be guaranteed it is no longer in use + */ +void virNetServerClientClose(virNetServerClientPtr client) +{ + virNetServerClientLock(client); + VIR_DEBUG("client=%p refs=%d", client, client->refs); + if (!client->sock) { + virNetServerClientUnlock(client); + return; + } + + /* Do now, even though we don't close the socket + * until end, to ensure we don't get invoked + * again due to tls shutdown */ + if (client->sock) + virNetSocketRemoveIOCallback(client->sock); + + if (client->tls) { + virNetTLSSessionFree(client->tls); + client->tls = NULL; + } + if (client->sock) { + virNetSocketFree(client->sock); + client->sock = NULL; + } + + while (client->rx) { + virNetMessagePtr msg + = virNetMessageQueueServe(&client->rx); + virNetMessageFree(msg); + } + while (client->tx) { + virNetMessagePtr msg + = virNetMessageQueueServe(&client->tx); + virNetMessageFree(msg); + } + + virNetServerClientUnlock(client); +} + + +bool virNetServerClientIsClosed(virNetServerClientPtr client) +{ + bool closed; + virNetServerClientLock(client); + closed = client->sock == NULL ? true : false; + virNetServerClientUnlock(client); + return closed; +} + +void virNetServerClientMarkClose(virNetServerClientPtr client) +{ + virNetServerClientLock(client); + client->wantClose = true; + virNetServerClientUnlock(client); +} + +bool virNetServerClientWantClose(virNetServerClientPtr client) +{ + bool wantClose; + virNetServerClientLock(client); + wantClose = client->wantClose; + virNetServerClientUnlock(client); + return wantClose; +} + + +int virNetServerClientInit(virNetServerClientPtr client) +{ + virNetServerClientLock(client); + + if (!client->tlsCtxt) { + /* Plain socket, so prepare to read first message */ + if (virNetServerClientRegisterEvent(client) < 0) + goto error; + } else { + int ret; + + if (!(client->tls = virNetTLSSessionNew(client->tlsCtxt, + NULL))) + goto error; + + virNetSocketSetTLSSession(client->sock, + client->tls); + + /* Begin the TLS handshake. */ + ret = virNetTLSSessionHandshake(client->tls); + if (ret == 0) { + /* Unlikely, but ... Next step is to check the certificate. */ + if (virNetServerClientCheckAccess(client) < 0) + goto error; + + /* Handshake & cert check OK, so prepare to read first message */ + if (virNetServerClientRegisterEvent(client) < 0) + goto error; + } else if (ret > 0) { + /* Most likely, need to do more handshake data */ + if (virNetServerClientRegisterEvent(client) < 0) + goto error; + } else { + goto error; + } + } + + virNetServerClientUnlock(client); + return 0; + +error: + client->wantClose = true; + virNetServerClientUnlock(client); + return -1; +} + + + +/* + * 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 virNetServerClientRead(virNetServerClientPtr client) +{ + ssize_t ret; + + if (client->rx->bufferLength <= client->rx->bufferOffset) { + virNetError(VIR_ERR_RPC, + _("unexpected zero/negative length request %lld"), + (long long int)(client->rx->bufferLength - client->rx->bufferOffset)); + client->wantClose = true; + return -1; + } + + ret = virNetSocketRead(client->sock, + client->rx->buffer + client->rx->bufferOffset, + client->rx->bufferLength - client->rx->bufferOffset); + + if (ret <= 0) + return ret; + + client->rx->bufferOffset += ret; + return ret; +} + + +/* + * Read data until we get a complete message to process + */ +static void virNetServerClientDispatchRead(virNetServerClientPtr client) +{ +readmore: + if (virNetServerClientRead(client) < 0) { + client->wantClose = true; + return; /* Error */ + } + + if (client->rx->bufferOffset < client->rx->bufferLength) + return; /* Still not read enough */ + + /* Either done with length word header */ + if (client->rx->bufferLength == VIR_NET_MESSAGE_LEN_MAX) { + if (virNetMessageDecodeLength(client->rx) < 0) + return; + + virNetServerClientUpdateEvent(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 */ + virNetMessagePtr msg = virNetMessageQueueServe(&client->rx); + virNetServerClientFilterPtr filter; + + /* Decode the header so we can use it for routing decisions */ + if (virNetMessageDecodeHeader(msg) < 0) { + virNetMessageFree(msg); + client->wantClose = true; + return; + } + + /* Maybe send off for queue against a filter */ + filter = client->filters; + while (filter) { + int ret = filter->func(client, msg, filter->opaque); + if (ret < 0 || ret > 0) { + virNetMessageFree(msg); + msg = NULL; + if (ret < 0) + client->wantClose = true; + break; + } + + filter = filter->next; + } + + /* Send off to for normal dispatch to workers */ + if (msg) { + if (!client->dispatchFunc || + client->dispatchFunc(client, msg, client->dispatchOpaque) < 0) { + virNetMessageFree(msg); + client->wantClose = true; + return; + } + } + + /* Possibly need to create another receive buffer */ + if (client->nrequests < client->nrequests_max) { + if (!(client->rx = virNetMessageNew())) { + client->wantClose = true; + } + client->rx->bufferLength = VIR_NET_MESSAGE_LEN_MAX; + client->nrequests++; + } + virNetServerClientUpdateEvent(client); + } +} + + +/* + * Send client->tx using no encoding + * + * Returns: + * -1 on error or EOF + * 0 on EAGAIN + * n number of bytes + */ +static ssize_t virNetServerClientWrite(virNetServerClientPtr client) +{ + ssize_t ret; + + if (client->tx->bufferLength < client->tx->bufferOffset) { + virNetError(VIR_ERR_RPC, + _("unexpected zero/negative length request %lld"), + (long long int)(client->tx->bufferLength - client->tx->bufferOffset)); + client->wantClose = true; + return -1; + } + + if (client->tx->bufferLength == client->tx->bufferOffset) + return 1; + + ret = virNetSocketWrite(client->sock, + 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; +} + + +/* + * Process all queued client->tx messages until + * we would block on I/O + */ +static void +virNetServerClientDispatchWrite(virNetServerClientPtr client) +{ + while (client->tx) { + ssize_t ret; + + ret = virNetServerClientWrite(client); + if (ret < 0) { + client->wantClose = true; + return; + } + if (ret == 0) + return; /* Would block on write EAGAIN */ + + if (client->tx->bufferOffset == client->tx->bufferLength) { + virNetMessagePtr msg; + + /* Completed this 'tx' operation, so now read for all + * future rx/tx to be under a SASL SSF layer + */ + if (client->sasl) { + virNetSocketSetSASLSession(client->sock, client->sasl); + virNetSASLSessionFree(client->sasl); + client->sasl = NULL; + } + + /* Get finished msg from head of tx queue */ + msg = virNetMessageQueueServe(&client->tx); + + if (msg->header.type == VIR_NET_REPLY) { + client->nrequests--; + /* See if the recv queue is currently throttled */ + if (!client->rx && + client->nrequests < client->nrequests_max) { + /* Ready to recv more messages */ + client->rx = msg; + client->rx->bufferLength = VIR_NET_MESSAGE_LEN_MAX; + msg = NULL; + client->nrequests++; + } + } + + virNetMessageFree(msg); + + virNetServerClientUpdateEvent(client); + } + } +} + +static void +virNetServerClientDispatchHandshake(virNetServerClientPtr client) +{ + int ret; + /* Continue the handshake. */ + ret = virNetTLSSessionHandshake(client->tls); + if (ret == 0) { + /* Finished. Next step is to check the certificate. */ + if (virNetServerClientCheckAccess(client) < 0) + client->wantClose = true; + else + virNetServerClientUpdateEvent(client); + } else if (ret > 0) { + /* Carry on waiting for more handshake. Update + the events just in case handshake data flow + direction has changed */ + virNetServerClientUpdateEvent (client); + } else { + /* Fatal error in handshake */ + client->wantClose = true; + } +} + +static void +virNetServerClientDispatchEvent(virNetSocketPtr sock, int events, void *opaque) +{ + virNetServerClientPtr client = opaque; + + virNetServerClientLock(client); + + if (client->sock != sock) { + virNetSocketRemoveIOCallback(sock); + virNetServerClientUnlock(client); + return; + } + + if (events & (VIR_EVENT_HANDLE_WRITABLE | + VIR_EVENT_HANDLE_READABLE)) { + if (client->tls && + virNetTLSSessionGetHandshakeStatus(client->tls) != + VIR_NET_TLS_HANDSHAKE_COMPLETE) { + virNetServerClientDispatchHandshake(client); + } else { + if (events & VIR_EVENT_HANDLE_WRITABLE) + virNetServerClientDispatchWrite(client); + if (events & VIR_EVENT_HANDLE_READABLE) + virNetServerClientDispatchRead(client); + } + } + + /* NB, will get HANGUP + READABLE at same time upon + * disconnect */ + if (events & (VIR_EVENT_HANDLE_ERROR | + VIR_EVENT_HANDLE_HANGUP)) + client->wantClose = true; + + virNetServerClientUnlock(client); +} + + +int virNetServerClientSendMessage(virNetServerClientPtr client, + virNetMessagePtr msg) +{ + int ret = -1; + VIR_DEBUG("msg=%p proc=%d len=%zu offset=%zu", + msg, msg->header.proc, + msg->bufferLength, msg->bufferOffset); + virNetServerClientLock(client); + + if (client->sock && !client->wantClose) { + virNetMessageQueuePush(&client->tx, msg); + + virNetServerClientUpdateEvent(client); + ret = 0; + } + + virNetServerClientUnlock(client); + return ret; +} + + +bool virNetServerClientNeedAuth(virNetServerClientPtr client) +{ + bool need = false; + virNetServerClientLock(client); + if (client->auth && !client->identity) + need = true; + virNetServerClientUnlock(client); + return need; +} diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h new file mode 100644 index 0000000..762f26a --- /dev/null +++ b/src/rpc/virnetserverclient.h @@ -0,0 +1,101 @@ +/* + * virnetserverclient.h: generic network RPC server client + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_NET_SERVER_CLIENT_H__ +# define __VIR_NET_SERVER_CLIENT_H__ + +# include "virnetsocket.h" +# include "virnetmessage.h" + +typedef struct _virNetServerClient virNetServerClient; +typedef virNetServerClient *virNetServerClientPtr; + +typedef int (*virNetServerClientDispatchFunc)(virNetServerClientPtr client, + virNetMessagePtr msg, + void *opaque); + +typedef int (*virNetServerClientFilterFunc)(virNetServerClientPtr client, + virNetMessagePtr msg, + void *opaque); + +virNetServerClientPtr virNetServerClientNew(virNetSocketPtr sock, + int auth, + bool readonly, + virNetTLSContextPtr tls); + +int virNetServerClientAddFilter(virNetServerClientPtr client, + virNetServerClientFilterFunc func, + void *opaque); + +void virNetServerClientRemoveFilter(virNetServerClientPtr client, + int filterID); + +int virNetServerClientGetAuth(virNetServerClientPtr client); +bool virNetServerClientGetReadonly(virNetServerClientPtr client); + +bool virNetServerClientHasTLSSession(virNetServerClientPtr client); +int virNetServerClientGetTLSKeySize(virNetServerClientPtr client); + +void virNetServerClientSetSASLSession(virNetServerClientPtr client, + virNetSASLSessionPtr sasl); + +int virNetServerClientGetFD(virNetServerClientPtr client); + +bool virNetServerClientIsSecure(virNetServerClientPtr client); + +int virNetServerClientSetIdentity(virNetServerClientPtr client, + const char *identity); +const char *virNetServerClientGetIdentity(virNetServerClientPtr client); + +void virNetServerClientRef(virNetServerClientPtr client); + +typedef void (*virNetServerClientFreeFunc)(void *data); + +void virNetServerClientSetPrivateData(virNetServerClientPtr client, + void *opaque, + virNetServerClientFreeFunc ff); +void *virNetServerClientGetPrivateData(virNetServerClientPtr client); + +void virNetServerClientSetDispatcher(virNetServerClientPtr client, + virNetServerClientDispatchFunc func, + void *opaque); +void virNetServerClientClose(virNetServerClientPtr client); + +bool virNetServerClientIsClosed(virNetServerClientPtr client); +void virNetServerClientMarkClose(virNetServerClientPtr client); +bool virNetServerClientWantClose(virNetServerClientPtr client); + +int virNetServerClientInit(virNetServerClientPtr client); + +const char *virNetServerClientLocalAddrString(virNetServerClientPtr client); +const char *virNetServerClientRemoteAddrString(virNetServerClientPtr client); + +int virNetServerClientSendMessage(virNetServerClientPtr client, + virNetMessagePtr msg); + +bool virNetServerClientNeedAuth(virNetServerClientPtr client); + +void virNetServerClientFree(virNetServerClientPtr client); + + +#endif /* __VIR_NET_SERVER_CLIENT_H__ */ diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c new file mode 100644 index 0000000..9ba2782 --- /dev/null +++ b/src/rpc/virnetserverprogram.c @@ -0,0 +1,477 @@ +/* + * virnetserverprogram.c: generic network RPC server program + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include "virnetserverprogram.h" +#include "virnetserverclient.h" + +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +struct _virNetServerProgram { + int refs; + + unsigned program; + unsigned version; + virNetServerProgramProcPtr procs; + size_t nprocs; +}; + +virNetServerProgramPtr virNetServerProgramNew(unsigned program, + unsigned version, + virNetServerProgramProcPtr procs, + size_t nprocs) +{ + virNetServerProgramPtr prog; + + if (VIR_ALLOC(prog) < 0) { + virReportOOMError(); + return NULL; + } + + prog->refs = 1; + prog->program = program; + prog->version = version; + prog->procs = procs; + prog->nprocs = nprocs; + + VIR_DEBUG("prog=%p refs=%d", prog, prog->refs); + + return prog; +} + + +int virNetServerProgramGetID(virNetServerProgramPtr prog) +{ + return prog->program; +} + + +int virNetServerProgramGetVersion(virNetServerProgramPtr prog) +{ + return prog->version; +} + + +void virNetServerProgramRef(virNetServerProgramPtr prog) +{ + prog->refs++; + VIR_DEBUG("prog=%p refs=%d", prog, prog->refs); +} + + +int virNetServerProgramMatches(virNetServerProgramPtr prog, + virNetMessagePtr msg) +{ + if (prog->program == msg->header.prog && + prog->version == msg->header.vers) + return 1; + return 0; +} + + +static virNetServerProgramProcPtr virNetServerProgramGetProc(virNetServerProgramPtr prog, + int procedure) +{ + if (procedure < 0) + return NULL; + if (procedure >= prog->nprocs) + return NULL; + + return &prog->procs[procedure]; +} + + +static void +virNetServerProgramEncodeError(virNetServerProgramPtr prog ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr) +{ + virErrorPtr verr = virGetLastError(); + if (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; + } else { + rerr->code = VIR_ERR_INTERNAL_ERROR; + rerr->domain = VIR_FROM_RPC; + rerr->message = verr->message ? malloc(sizeof(char*)) : NULL; + if (rerr->message) *rerr->message = strdup(_("Library function returned error but did not set virError")); + rerr->level = VIR_ERR_ERROR; + } +} + + +static int +virNetServerProgramSendError(virNetServerProgramPtr prog, + virNetServerClientPtr client, + virNetMessagePtr msg, + int procedure, + int type, + int serial) +{ + virNetMessageError rerr; + DEBUG("prog=%d ver=%d proc=%d type=%d serial=%d, msg=%p", + prog->program, prog->version, procedure, type, serial, msg); + + memset(&rerr, 0, sizeof(rerr)); + + virNetServerProgramEncodeError(prog, &rerr); + + /* Return header. */ + msg->header.prog = prog->program; + msg->header.vers = prog->version; + msg->header.proc = procedure; + msg->header.type = type; + msg->header.serial = serial; + msg->header.status = VIR_NET_ERROR; + + if (virNetMessageEncodeHeader(msg) < 0) + goto error; + + if (virNetMessageEncodePayload(msg, (xdrproc_t)xdr_virNetMessageError, &rerr) < 0) + goto error; + xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)&rerr); + + /* Put reply on end of tx queue to send out */ + if (virNetServerClientSendMessage(client, msg) < 0) + return -1; + + return 0; + +error: + VIR_WARN("Failed to serialize remote error '%p'", &rerr); + xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)&rerr); + return -1; +} + + +/* + * @client: the client to send the error to + * @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 +virNetServerProgramSendReplyError(virNetServerProgramPtr prog, + virNetServerClientPtr client, + virNetMessagePtr msg, + virNetMessageHeaderPtr req) +{ + /* + * For data streams, errors are sent back as data streams + * For method calls, errors are sent back as method replies + */ + return virNetServerProgramSendError(prog, + client, + msg, + req->proc, + req->type == VIR_NET_STREAM ? VIR_NET_STREAM : VIR_NET_REPLY, + req->serial); +} + + +int virNetServerProgramSendStreamError(virNetServerProgramPtr prog, + virNetServerClientPtr client, + virNetMessagePtr msg, + int procedure, + int serial) +{ + return virNetServerProgramSendError(prog, + client, + msg, + procedure, + VIR_NET_STREAM, + serial); +} + + +static int +virNetServerProgramDispatchCall(virNetServerProgramPtr prog, + virNetServerPtr server, + virNetServerClientPtr client, + virNetMessagePtr msg); + +/* + * @server: the unlocked server object + * @client: the unlocked client object + * @msg: the complete incoming message packet, with header already decoded + * + * This function is intended to be called from worker threads + * when an incoming message is ready to be dispatched for + * execution. + * + * Upon successful return the '@msg' instance will be released + * by this function (or more often, reused to send a reply). + * Upon failure, the '@msg' must be freed by the caller. + * + * Returns 0 if the message was dispatched, -1 upon fatal error + */ +int virNetServerProgramDispatch(virNetServerProgramPtr prog, + virNetServerPtr server, + virNetServerClientPtr client, + virNetMessagePtr msg) +{ + int ret = -1; + + DEBUG("prog=%d ver=%d type=%d status=%d serial=%d proc=%d", + msg->header.prog, msg->header.vers, msg->header.type, + msg->header.status, msg->header.serial, msg->header.proc); + + /* Check version, etc. */ + if (msg->header.prog != prog->program) { + virNetError(VIR_ERR_RPC, + _("program mismatch (actual %x, expected %x)"), + msg->header.prog, prog->program); + goto error; + } + + if (msg->header.vers != prog->version) { + virNetError(VIR_ERR_RPC, + _("version mismatch (actual %x, expected %x)"), + msg->header.vers, prog->version); + goto error; + } + + switch (msg->header.type) { + case VIR_NET_CALL: + ret = virNetServerProgramDispatchCall(prog, server, client, msg); + break; + + case VIR_NET_STREAM: + /* Since stream data is non-acked, async, we may continue to receive + * 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->header.serial, msg->header.proc, msg->header.status); + virNetMessageFree(msg); + ret = 0; + break; + + default: + virNetError(VIR_ERR_RPC, + _("Unexpected message type %u"), + msg->header.type); + goto error; + } + + return ret; + +error: + ret = virNetServerProgramSendReplyError(prog, client, msg, &msg->header); + + return ret; +} + + +/* + * @server: the unlocked server object + * @client: the unlocked 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 +virNetServerProgramDispatchCall(virNetServerProgramPtr prog, + virNetServerPtr server, + virNetServerClientPtr client, + virNetMessagePtr msg) +{ + char *arg = NULL; + char *ret = NULL; + int rv = -1; + virNetServerProgramProcPtr dispatcher; + + if (msg->header.status != VIR_NET_OK) { + virNetError(VIR_ERR_RPC, + _("Unexpected message status %u"), + msg->header.status); + goto error; + } + + dispatcher = virNetServerProgramGetProc(prog, msg->header.proc); + + if (!dispatcher) { + virNetError(VIR_ERR_RPC, + _("unknown procedure: %d"), + msg->header.proc); + goto error; + } + + /* If client is marked as needing auth, don't allow any RPC ops + * which are except for authentication ones + */ + if (virNetServerClientNeedAuth(client) && + dispatcher->needAuth) { + /* Explicitly *NOT* calling remoteDispatchAuthError() because + we want back-compatability with libvirt clients which don't + support the VIR_ERR_AUTH_FAILED error code */ + virNetError(VIR_ERR_RPC, + "%s", _("authentication required")); + goto error; + } + + if (VIR_ALLOC_N(arg, dispatcher->arg_len) < 0) { + virReportOOMError(); + goto error; + } + if (VIR_ALLOC_N(ret, dispatcher->ret_len) < 0) { + virReportOOMError(); + goto error; + } + + if (virNetMessageDecodePayload(msg, dispatcher->arg_filter, arg) < 0) + goto error; + + /* + * When the RPC handler is called: + * + * - Server object is unlocked + * - Client object is unlocked + * + * Without locking, it is safe to use: + * + * 'args and 'ret' + */ + rv = (dispatcher->func)(server, client, &msg->header, arg, ret); + + xdr_free(dispatcher->arg_filter, arg); + + if (rv < 0) + goto error; + + /* Return header. We're re-using same message object, so + * only need to tweak type/status fields */ + /*msg->header.prog = msg->header.prog;*/ + /*msg->header.vers = msg->header.vers;*/ + /*msg->header.proc = msg->header.proc;*/ + msg->header.type = VIR_NET_REPLY; + /*msg->header.serial = msg->header.serial;*/ + msg->header.status = VIR_NET_OK; + + if (virNetMessageEncodeHeader(msg) < 0) { + xdr_free(dispatcher->ret_filter, ret); + goto error; + } + + if (virNetMessageEncodePayload(msg, dispatcher->ret_filter, ret) < 0) { + xdr_free(dispatcher->ret_filter, ret); + goto error; + } + + xdr_free(dispatcher->ret_filter, ret); + VIR_FREE(arg); + VIR_FREE(ret); + + /* Put reply on end of tx queue to send out */ + return virNetServerClientSendMessage(client, msg); + +error: + /* Bad stuff (de-)serializing message, but we have an + * RPC error message we can send back to the client */ + rv = virNetServerProgramSendReplyError(prog, client, msg, &msg->header); + + VIR_FREE(arg); + VIR_FREE(ret); + + return rv; +} + + +int virNetServerProgramSendStreamData(virNetServerProgramPtr prog, + virNetServerClientPtr client, + virNetMessagePtr msg, + int procedure, + int serial, + const char *data, + size_t len) +{ + DEBUG("client=%p msg=%p data=%p len=%zu", client, msg, data, len); + + /* Return header. We're reusing same message object, so + * only need to tweak type/status fields */ + msg->header.prog = prog->program; + msg->header.vers = prog->version; + msg->header.proc = procedure; + msg->header.type = VIR_NET_STREAM; + msg->header.serial = 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->header.status = data ? VIR_NET_CONTINUE : VIR_NET_OK; + + if (virNetMessageEncodeHeader(msg) < 0) + return -1; + + if (data && len) { + if (virNetMessageEncodePayloadRaw(msg, data, len) < 0) + return -1; + + DEBUG("Total %zu", msg->bufferOffset); + } + + return virNetServerClientSendMessage(client, msg); +} + + +void virNetServerProgramFree(virNetServerProgramPtr prog) +{ + if (!prog) + return; + + VIR_DEBUG("prog=%p refs=%d", prog, prog->refs); + + prog->refs--; + if (prog->refs > 0) + return; + + VIR_FREE(prog); +} diff --git a/src/rpc/virnetserverprogram.h b/src/rpc/virnetserverprogram.h new file mode 100644 index 0000000..124a587 --- /dev/null +++ b/src/rpc/virnetserverprogram.h @@ -0,0 +1,104 @@ +/* + * virnetserverprogram.h: generic network RPC server program + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_NET_PROGRAM_H__ +# define __VIR_NET_PROGRAM_H__ + +# include <stdbool.h> + +# include "virnetmessage.h" +# include "virnetserverclient.h" + +typedef struct _virNetServer virNetServer; +typedef virNetServer *virNetServerPtr; + +typedef struct _virNetServerService virNetServerService; +typedef virNetServerService *virNetServerServicePtr; + +typedef struct _virNetServerProgram virNetServerProgram; +typedef virNetServerProgram *virNetServerProgramPtr; + +typedef struct _virNetServerProgramProc virNetServerProgramProc; +typedef virNetServerProgramProc *virNetServerProgramProcPtr; + +typedef struct _virNetServerProgramErrorHandler virNetServerProgramErrorHander; +typedef virNetServerProgramErrorHander *virNetServerProgramErrorHanderPtr; + +typedef int (*virNetServerProgramDispatchFunc)(virNetServerPtr server, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr, + void *args, + void *ret); + +struct _virNetServerProgramProc { + virNetServerProgramDispatchFunc func; + size_t arg_len; + xdrproc_t arg_filter; + size_t ret_len; + xdrproc_t ret_filter; + bool needAuth; +}; + +virNetServerProgramPtr virNetServerProgramNew(unsigned program, + unsigned version, + virNetServerProgramProcPtr procs, + size_t nprocs); + +int virNetServerProgramGetID(virNetServerProgramPtr prog); +int virNetServerProgramGetVersion(virNetServerProgramPtr prog); + +void virNetServerProgramRef(virNetServerProgramPtr prog); + +int virNetServerProgramMatches(virNetServerProgramPtr prog, + virNetMessagePtr msg); + +int virNetServerProgramDispatch(virNetServerProgramPtr prog, + virNetServerPtr server, + virNetServerClientPtr client, + virNetMessagePtr msg); + +int virNetServerProgramSendReplyError(virNetServerProgramPtr prog, + virNetServerClientPtr client, + virNetMessagePtr msg, + virNetMessageHeaderPtr req); + +int virNetServerProgramSendStreamError(virNetServerProgramPtr prog, + virNetServerClientPtr client, + virNetMessagePtr msg, + int procedure, + int serial); + +int virNetServerProgramSendStreamData(virNetServerProgramPtr prog, + virNetServerClientPtr client, + virNetMessagePtr msg, + int procedure, + int serial, + const char *data, + size_t len); + +void virNetServerProgramFree(virNetServerProgramPtr prog); + + + + +#endif /* __VIR_NET_SERVER_PROGRAM_H__ */ diff --git a/src/rpc/virnetserverservice.c b/src/rpc/virnetserverservice.c new file mode 100644 index 0000000..3f6cf4b --- /dev/null +++ b/src/rpc/virnetserverservice.c @@ -0,0 +1,247 @@ +/* + * virnetserverservice.c: generic network RPC server service + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include "virnetserverservice.h" + +#include "memory.h" +#include "virterror_internal.h" + + +#define VIR_FROM_THIS VIR_FROM_RPC + +struct _virNetServerService { + int refs; + + size_t nsocks; + virNetSocketPtr *socks; + + int auth; + bool readonly; + + virNetTLSContextPtr tls; + + virNetServerServiceDispatchFunc dispatchFunc; + void *dispatchOpaque; +}; + + + +static void virNetServerServiceAccept(virNetSocketPtr sock, + int events ATTRIBUTE_UNUSED, + void *opaque) +{ + virNetServerServicePtr svc = opaque; + virNetServerClientPtr client = NULL; + virNetSocketPtr clientsock = NULL; + + if (virNetSocketAccept(sock, &clientsock) < 0) + goto error; + + if (!clientsock) /* Connection already went away */ + goto cleanup; + + if (!(client = virNetServerClientNew(clientsock, + svc->auth, + svc->readonly, + svc->tls))) + goto error; + + if (!svc->dispatchFunc) + goto error; + + if (svc->dispatchFunc(svc, client, svc->dispatchOpaque) < 0) + virNetServerClientClose(client); + + virNetServerClientFree(client); + +cleanup: + return; + +error: + virNetSocketFree(clientsock); +} + + +virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename, + const char *service, + int auth, + bool readonly, + virNetTLSContextPtr tls) +{ + virNetServerServicePtr svc; + size_t i; + + if (VIR_ALLOC(svc) < 0) + goto no_memory; + + svc->refs = 1; + svc->auth = auth; + svc->readonly = readonly; + svc->tls = tls; + if (tls) + virNetTLSContextRef(tls); + + if (virNetSocketNewListenTCP(nodename, + service, + &svc->socks, + &svc->nsocks) < 0) + goto error; + + for (i = 0 ; i < svc->nsocks ; i++) { + if (virNetSocketListen(svc->socks[i]) < 0) + goto error; + + /* IO callback is initially disabled, until we're ready + * to deal with incoming clients */ + if (virNetSocketAddIOCallback(svc->socks[i], + 0, + virNetServerServiceAccept, + svc) < 0) + goto error; + } + + + return svc; + +no_memory: + virReportOOMError(); +error: + virNetServerServiceFree(svc); + return NULL; +} + + +virNetServerServicePtr virNetServerServiceNewUNIX(const char *path, + mode_t mask, + gid_t grp, + int auth, + bool readonly, + virNetTLSContextPtr tls) +{ + virNetServerServicePtr svc; + int i; + + if (VIR_ALLOC(svc) < 0) + goto no_memory; + + svc->refs = 1; + svc->auth = auth; + svc->readonly = readonly; + svc->tls = tls; + if (tls) + virNetTLSContextRef(tls); + + svc->nsocks = 1; + if (VIR_ALLOC_N(svc->socks, svc->nsocks) < 0) + goto no_memory; + + if (virNetSocketNewListenUNIX(path, + mask, + grp, + &svc->socks[0]) < 0) + goto error; + + for (i = 0 ; i < svc->nsocks ; i++) { + if (virNetSocketListen(svc->socks[i]) < 0) + goto error; + + /* IO callback is initially disabled, until we're ready + * to deal with incoming clients */ + if (virNetSocketAddIOCallback(svc->socks[i], + 0, + virNetServerServiceAccept, + svc) < 0) + goto error; + } + + + return svc; + +no_memory: + virReportOOMError(); +error: + virNetServerServiceFree(svc); + return NULL; +} + + +int virNetServerServiceGetAuth(virNetServerServicePtr svc) +{ + return svc->auth; +} + + +bool virNetServerServiceIsReadonly(virNetServerServicePtr svc) +{ + return svc->readonly; +} + + +void virNetServerServiceRef(virNetServerServicePtr svc) +{ + svc->refs++; +} + + +void virNetServerServiceSetDispatcher(virNetServerServicePtr svc, + virNetServerServiceDispatchFunc func, + void *opaque) +{ + svc->dispatchFunc = func; + svc->dispatchOpaque = opaque; +} + + +void virNetServerServiceFree(virNetServerServicePtr svc) +{ + int i; + + if (!svc) + return; + + svc->refs--; + if (svc->refs > 0) + return; + + for (i = 0 ; i < svc->nsocks ; i++) + virNetSocketFree(svc->socks[i]); + VIR_FREE(svc->socks); + + virNetTLSContextFree(svc->tls); + + VIR_FREE(svc); +} + +void virNetServerServiceToggle(virNetServerServicePtr svc, + bool enabled) +{ + int i; + + for (i = 0 ; i < svc->nsocks ; i++) + virNetSocketUpdateIOCallback(svc->socks[i], + enabled ? + VIR_EVENT_HANDLE_READABLE : + 0); +} diff --git a/src/rpc/virnetserverservice.h b/src/rpc/virnetserverservice.h new file mode 100644 index 0000000..b59c8fa --- /dev/null +++ b/src/rpc/virnetserverservice.h @@ -0,0 +1,65 @@ +/* + * virnetserverservice.h: generic network RPC server service + * + * Copyright (C) 2006-2010 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange + * + * 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_NET_SERVER_SERVICE_H__ +# define __VIR_NET_SERVER_SERVICE_H__ + +# include "virnetserverprogram.h" + +enum { + VIR_NET_SERVER_SERVICE_AUTH_NONE = 0, + VIR_NET_SERVER_SERVICE_AUTH_SASL, + VIR_NET_SERVER_SERVICE_AUTH_POLKIT, +}; + +typedef int (*virNetServerServiceDispatchFunc)(virNetServerServicePtr svc, + virNetServerClientPtr client, + void *opaque); + +virNetServerServicePtr virNetServerServiceNewTCP(const char *nodename, + const char *service, + int auth, + bool readonly, + virNetTLSContextPtr tls); +virNetServerServicePtr virNetServerServiceNewUNIX(const char *path, + mode_t mask, + gid_t grp, + int auth, + bool readonly, + virNetTLSContextPtr tls); + +int virNetServerServiceGetAuth(virNetServerServicePtr svc); +bool virNetServerServiceIsReadonly(virNetServerServicePtr svc); + +void virNetServerServiceRef(virNetServerServicePtr svc); + +void virNetServerServiceSetDispatcher(virNetServerServicePtr svc, + virNetServerServiceDispatchFunc func, + void *opaque); + +void virNetServerServiceFree(virNetServerServicePtr svc); + +void virNetServerServiceToggle(virNetServerServicePtr svc, + bool enabled); + +#endif -- 1.7.2.3

To facilitate creation of new clients using XDR RPC services, pull alot of the remote driver code into a set of reusable objects. - virNetClient: Encapsulates a socket connection to a remote RPC server. Handles all the network I/O for reading/writing RPC messages. Delegates RPC encoding and decoding to the registered programs - virNetClientProgram: Handles processing and dispatch of RPC messages for a single RPC (program,version). A program can register to receive async events from a client Each new client program now merely needs to define the list of RPC procedures & events it wants and their handlers. It does not need to deal with any of the network I/O functionality at all. --- po/POTFILES.in | 2 + src/Makefile.am | 13 +- src/rpc/virnetclient.c | 1090 +++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetclient.h | 75 +++ src/rpc/virnetclientprogram.c | 301 ++++++++++++ src/rpc/virnetclientprogram.h | 82 +++ 6 files changed, 1562 insertions(+), 1 deletions(-) create mode 100644 src/rpc/virnetclient.c create mode 100644 src/rpc/virnetclient.h create mode 100644 src/rpc/virnetclientprogram.c create mode 100644 src/rpc/virnetclientprogram.h diff --git a/po/POTFILES.in b/po/POTFILES.in index bb84ea3..0595adf 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -58,6 +58,8 @@ src/qemu/qemu_monitor_json.c src/qemu/qemu_monitor_text.c src/qemu/qemu_security_dac.c src/remote/remote_driver.c +src/rpc/virnetclient.c +src/rpc/virnetclientprogram.c src/rpc/virnetmessage.c src/rpc/virnetsaslcontext.c src/rpc/virnetsocket.c diff --git a/src/Makefile.am b/src/Makefile.am index 15a70d6..9fbf210 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1118,7 +1118,7 @@ libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD) EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) -noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt-net-rpc-server.la +noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt-net-rpc-server.la libvirt-net-rpc-client.la libvirt_net_rpc_la_SOURCES = \ ../daemon/event.c \ @@ -1154,6 +1154,17 @@ libvirt_net_rpc_server_la_LDFLAGS = \ libvirt_net_rpc_server_la_LIBADD = \ $(CYGWIN_EXTRA_LIBADD) +libvirt_net_rpc_client_la_SOURCES = \ + rpc/virnetclientprogram.h rpc/virnetclientprogram.c \ + rpc/virnetclient.h rpc/virnetclient.c +libvirt_net_rpc_client_la_CFLAGS = \ + $(AM_CFLAGS) +libvirt_net_rpc_client_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + $(CYGWIN_EXTRA_LDFLAGS) \ + $(MINGW_EXTRA_LDFLAGS)l +libvirt_net_rpc_client_la_LIBADD = \ + $(CYGWIN_EXTRA_LIBADD) libexec_PROGRAMS = diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c new file mode 100644 index 0000000..27ee685 --- /dev/null +++ b/src/rpc/virnetclient.c @@ -0,0 +1,1090 @@ +/* + * virnetclient.c: generic network RPC client + * + * Copyright (C) 2006-2010 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <unistd.h> +#include <poll.h> +#include <signal.h> + +#include "virnetclient.h" +#include "virnetsocket.h" +#include "memory.h" +#include "threads.h" +#include "files.h" +#include "logging.h" +#include "util.h" +#include "virterror_internal.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +typedef struct _virNetClientCall virNetClientCall; +typedef virNetClientCall *virNetClientCallPtr; + +enum { + VIR_NET_CLIENT_MODE_WAIT_TX, + VIR_NET_CLIENT_MODE_WAIT_RX, + VIR_NET_CLIENT_MODE_COMPLETE, +}; + +struct _virNetClientCall { + int mode; + + virNetMessagePtr msg; + int expectReply; + + virCond cond; + + +/* remote_error err; */ + + virNetClientCallPtr next; +}; + + +struct _virNetClient { + int refs; + + virMutex lock; + + virNetSocketPtr sock; + + virNetTLSSessionPtr tls; + char *hostname; + + virNetClientProgramPtr *programs; + size_t nprograms; + + /* For incoming message packets */ + virNetMessage msg; + + virNetSASLSessionPtr sasl; + + /* Self-pipe to wakeup threads waiting in poll() */ + int wakeupSendFD; + int wakeupReadFD; + + /* List of threads currently waiting for dispatch */ + virNetClientCallPtr waitDispatch; +}; + + +static void virNetClientLock(virNetClientPtr client) +{ + virMutexLock(&client->lock); +} + + +static void virNetClientUnlock(virNetClientPtr client) +{ + virMutexUnlock(&client->lock); +} + + +static void virNetClientIncomingEvent(virNetSocketPtr sock, + int events, + void *opaque); + +static virNetClientPtr virNetClientNew(virNetSocketPtr sock, + const char *hostname) +{ + virNetClientPtr client; + int wakeupFD[2] = { -1, -1 }; + + if (pipe(wakeupFD) < 0) { + virReportSystemError(errno, "%s", + _("unable to make pipe")); + goto error; + } + + if (VIR_ALLOC(client) < 0) + goto no_memory; + + client->refs = 1; + + if (virMutexInit(&client->lock) < 0) + goto error; + + client->sock = sock; + client->wakeupReadFD = wakeupFD[0]; + client->wakeupSendFD = wakeupFD[1]; + wakeupFD[0] = wakeupFD[1] = -1; + + if (hostname && + !(client->hostname = strdup(hostname))) + goto no_memory; + + /* Set up a callback to listen on the socket data */ + if (virNetSocketAddIOCallback(client->sock, + VIR_EVENT_HANDLE_READABLE, + virNetClientIncomingEvent, + client) < 0) + VIR_DEBUG0("Failed to add event watch, disabling events"); + + return client; + +no_memory: + virReportOOMError(); +error: + VIR_FORCE_CLOSE(wakeupFD[0]); + VIR_FORCE_CLOSE(wakeupFD[1]); + virNetClientFree(client); + return NULL; +} + + +virNetClientPtr virNetClientNewUNIX(const char *path, + bool spawnDaemon, + const char *binary) +{ + virNetSocketPtr sock; + + if (virNetSocketNewConnectUNIX(path, spawnDaemon, binary, &sock) < 0) + return NULL; + + return virNetClientNew(sock, NULL); +} + + +virNetClientPtr virNetClientNewTCP(const char *nodename, + const char *service) +{ + virNetSocketPtr sock; + + if (virNetSocketNewConnectTCP(nodename, service, &sock) < 0) + return NULL; + + return virNetClientNew(sock, nodename); +} + +virNetClientPtr virNetClientNewSSH(const char *nodename, + const char *service, + const char *binary, + const char *username, + bool noTTY, + const char *netcat, + const char *path) +{ + virNetSocketPtr sock; + + if (virNetSocketNewConnectSSH(nodename, service, binary, username, noTTY, netcat, path, &sock) < 0) + return NULL; + + return virNetClientNew(sock, NULL); +} + +virNetClientPtr virNetClientNewExternal(const char **cmdargv) +{ + virNetSocketPtr sock; + + if (virNetSocketNewConnectExternal(cmdargv, &sock) < 0) + return NULL; + + return virNetClientNew(sock, NULL); +} + + +void virNetClientRef(virNetClientPtr client) +{ + virNetClientLock(client); + client->refs++; + virNetClientUnlock(client); +} + + +void virNetClientFree(virNetClientPtr client) +{ + int i; + + if (!client) + return; + + virNetClientLock(client); + client->refs--; + if (client->refs > 0) { + virNetClientUnlock(client); + return; + } + + for (i = 0 ; i < client->nprograms ; i++) + virNetClientProgramFree(client->programs[i]); + VIR_FREE(client->programs); + + VIR_FORCE_CLOSE(client->wakeupSendFD); + VIR_FORCE_CLOSE(client->wakeupReadFD); + + VIR_FREE(client->hostname); + + virNetSocketRemoveIOCallback(client->sock); + virNetSocketFree(client->sock); + virNetTLSSessionFree(client->tls); + virNetSASLSessionFree(client->sasl); + virNetClientUnlock(client); + virMutexDestroy(&client->lock); + + VIR_FREE(client); +} + + +void virNetClientSetSASLSession(virNetClientPtr client, + virNetSASLSessionPtr sasl) +{ + virNetClientLock(client); + client->sasl = sasl; + virNetSASLSessionRef(sasl); + virNetSocketSetSASLSession(client->sock, client->sasl); + virNetClientUnlock(client); +} + + +int virNetClientSetTLSSession(virNetClientPtr client, + virNetTLSContextPtr tls) +{ + int ret; + char buf[1]; + int len; + struct pollfd fds[1]; +#ifdef HAVE_PTHREAD_SIGMASK + sigset_t oldmask, blockedsigs; + + sigemptyset (&blockedsigs); + sigaddset (&blockedsigs, SIGWINCH); + sigaddset (&blockedsigs, SIGCHLD); + sigaddset (&blockedsigs, SIGPIPE); +#endif + + virNetClientLock(client); + + if (!(client->tls = virNetTLSSessionNew(tls, + client->hostname))) + goto error; + + virNetSocketSetTLSSession(client->sock, client->tls); + + for (;;) { + ret = virNetTLSSessionHandshake(client->tls); + + if (ret < 0) + goto error; + if (ret == 0) + break; + + fds[0].fd = virNetSocketGetFD(client->sock); + fds[0].revents = 0; + if (virNetTLSSessionGetHandshakeStatus(client->tls) == + VIR_NET_TLS_HANDSHAKE_RECVING) + fds[0].events = POLLIN; + else + fds[0].events = POLLOUT; + + /* Block SIGWINCH from interrupting poll in curses programs, + * then restore the original signal mask again immediately + * after the call (RHBZ#567931). Same for SIGCHLD and SIGPIPE + * at the suggestion of Paolo Bonzini and Daniel Berrange. + */ +#ifdef HAVE_PTHREAD_SIGMASK + ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask)); +#endif + + repoll: + ret = poll(fds, ARRAY_CARDINALITY(fds), -1); + if (ret < 0 && errno == EAGAIN) + goto repoll; + +#ifdef HAVE_PTHREAD_SIGMASK + ignore_value(pthread_sigmask(SIG_BLOCK, &oldmask, NULL)); +#endif + } + + ret = virNetTLSContextCheckCertificate(tls, client->tls); + + if (ret < 0) + goto error; + + /* At this point, the server is verifying _our_ certificate, IP address, + * etc. If we make the grade, it will send us a '\1' byte. + */ + + fds[0].fd = virNetSocketGetFD(client->sock); + fds[0].revents = 0; + fds[0].events = POLLIN; + +#ifdef HAVE_PTHREAD_SIGMASK + /* Block SIGWINCH from interrupting poll in curses programs */ + ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask)); +#endif + + repoll2: + ret = poll(fds, ARRAY_CARDINALITY(fds), -1); + if (ret < 0 && errno == EAGAIN) + goto repoll2; + +#ifdef HAVE_PTHREAD_SIGMASK + ignore_value(pthread_sigmask(SIG_BLOCK, &oldmask, NULL)); +#endif + + len = virNetTLSSessionRead(client->tls, buf, 1); + if (len < 0) { + virReportSystemError(errno, "%s", + _("Unable to read TLS confirmation")); + goto error; + } + if (len != 1 || buf[0] != '\1') { + virNetError(VIR_ERR_RPC, "%s", + _("server verification (of our certificate or IP " + "address) failed")); + goto error; + } + + virNetClientUnlock(client); + return 0; + +error: + virNetTLSSessionFree(client->tls); + client->tls = NULL; + virNetClientUnlock(client); + return -1; +} + +bool virNetClientIsEncrypted(virNetClientPtr client) +{ + bool ret; + virNetClientLock(client); + ret = client->tls || client->sasl ? true : false; + virNetClientUnlock(client); + return ret; +} + + +int virNetClientAddProgram(virNetClientPtr client, + virNetClientProgramPtr prog) +{ + virNetClientLock(client); + + if (VIR_EXPAND_N(client->programs, client->nprograms, 1) < 0) + goto no_memory; + + client->programs[client->nprograms-1] = prog; + virNetClientProgramRef(prog); + + virNetClientUnlock(client); + return 0; + +no_memory: + virReportOOMError(); + virNetClientUnlock(client); + return -1; +} + + +const char *virNetClientLocalAddrString(virNetClientPtr client) +{ + return virNetSocketLocalAddrString(client->sock); +} + +const char *virNetClientRemoteAddrString(virNetClientPtr client) +{ + return virNetSocketRemoteAddrString(client->sock); +} + +int virNetClientGetTLSKeySize(virNetClientPtr client) +{ + int ret = 0; + virNetClientLock(client); + if (client->tls) + ret = virNetTLSSessionGetKeySize(client->tls); + virNetClientUnlock(client); + return ret; +} + +static int +virNetClientCallDispatchReply(virNetClientPtr client) +{ + virNetClientCallPtr thecall; + + /* Ok, definitely got an RPC reply now find + out who's been waiting for it */ + thecall = client->waitDispatch; + while (thecall && + !(thecall->msg->header.prog == client->msg.header.prog && + thecall->msg->header.vers == client->msg.header.vers && + thecall->msg->header.serial == client->msg.header.serial)) + thecall = thecall->next; + + if (!thecall) { + virNetError(VIR_ERR_RPC, + _("no call waiting for reply with prog %d vers %d serial %d"), + client->msg.header.prog, client->msg.header.vers, client->msg.header.serial); + return -1; + } + + memcpy(thecall->msg->buffer, client->msg.buffer, sizeof(client->msg.buffer)); + memcpy(&thecall->msg->header, &client->msg.header, sizeof(client->msg.header)); + thecall->msg->bufferLength = client->msg.bufferLength; + thecall->msg->bufferOffset = client->msg.bufferOffset; + + thecall->mode = VIR_NET_CLIENT_MODE_COMPLETE; + + return 0; +} + +static int virNetClientCallDispatchMessage(virNetClientPtr client) +{ + int i; + virNetClientProgramPtr prog = NULL; + + for (i = 0 ; i < client->nprograms ; i++) { + if (virNetClientProgramMatches(client->programs[i], + &client->msg)) { + prog = client->programs[i]; + break; + } + } + if (!prog) { + VIR_DEBUG("No program found for event with prog=%d vers=%d", + client->msg.header.prog, client->msg.header.vers); + return -1; + } + + virNetClientProgramDispatch(prog, client, &client->msg); + + return 0; +} + +static int virNetClientCallDispatchStream(virNetClientPtr client ATTRIBUTE_UNUSED) +{ +#if 0 + struct private_stream_data *privst; + virNetClientCallPtr thecall; + + /* Try and find a matching stream */ + privst = client->streams; + while (privst && + privst->serial != hdr->serial && + privst->proc_nr != hdr->proc) + privst = privst->next; + + if (!privst) { + VIR_DEBUG("No registered stream matching serial=%d, proc=%d", + hdr->serial, hdr->proc); + return -1; + } + + /* See if there's also a (optional) call waiting for this reply */ + thecall = client->waitDispatch; + while (thecall && + thecall->serial != hdr->serial) + thecall = thecall->next; + + + /* Status is either REMOTE_OK (meaning that what follows is a ret + * structure), or REMOTE_ERROR (and what follows is a remote_error + * structure). + */ + switch (hdr->status) { + case REMOTE_CONTINUE: { + int avail = privst->incomingLength - privst->incomingOffset; + int need = client->bufferLength - client->bufferOffset; + VIR_DEBUG0("Got a stream data packet"); + + /* XXX flag stream as complete somwhere if need==0 */ + + if (need > avail) { + int extra = need - avail; + if (VIR_REALLOC_N(privst->incoming, + privst->incomingLength + extra) < 0) { + VIR_DEBUG0("Out of memory handling stream data"); + return -1; + } + privst->incomingLength += extra; + } + + memcpy(privst->incoming + privst->incomingOffset, + client->buffer + client->bufferOffset, + client->bufferLength - client->bufferOffset); + privst->incomingOffset += (client->bufferLength - client->bufferOffset); + + if (thecall && thecall->want_reply) { + VIR_DEBUG("Got sync data packet offset=%d", privst->incomingOffset); + thecall->mode = REMOTE_MODE_COMPLETE; + } else { + VIR_DEBUG("Got aysnc data packet offset=%d", privst->incomingOffset); + remoteStreamEventTimerUpdate(privst); + } + return 0; + } + + case REMOTE_OK: + VIR_DEBUG0("Got a synchronous confirm"); + if (!thecall) { + VIR_DEBUG0("Got unexpected stream finish confirmation"); + return -1; + } + thecall->mode = REMOTE_MODE_COMPLETE; + return 0; + + case REMOTE_ERROR: + if (thecall && thecall->want_reply) { + VIR_DEBUG0("Got a synchronous error"); + /* Give the error straight to this call */ + memset (&thecall->err, 0, sizeof thecall->err); + if (!xdr_remote_error (xdr, &thecall->err)) { + remoteError(VIR_ERR_RPC, "%s", _("unmarshalling remote_error")); + return -1; + } + thecall->mode = REMOTE_MODE_ERROR; + } else { + VIR_DEBUG0("Got a asynchronous error"); + /* No call, so queue the error against the stream */ + if (privst->has_error) { + VIR_DEBUG0("Got unexpected duplicate stream error"); + return -1; + } + privst->has_error = 1; + memset (&privst->err, 0, sizeof privst->err); + if (!xdr_remote_error (xdr, &privst->err)) { + VIR_DEBUG0("Failed to unmarshall error"); + return -1; + } + } + return 0; + + default: + VIR_WARN("Stream with unexpected serial=%d, proc=%d, status=%d", + hdr->serial, hdr->proc, hdr->status); + return -1; + } +#endif + return 0; +} + + +static int +virNetClientCallDispatch(virNetClientPtr client) +{ + if (virNetMessageDecodeHeader(&client->msg) < 0) + return -1; + + switch (client->msg.header.type) { + case VIR_NET_REPLY: /* Normal RPC replies */ + return virNetClientCallDispatchReply(client); + + case VIR_NET_MESSAGE: /* Async notifications */ + return virNetClientCallDispatchMessage(client); + + case VIR_NET_STREAM: /* Stream protocol */ + return virNetClientCallDispatchStream(client); + + default: + virNetError(VIR_ERR_RPC, + _("got unexpected RPC call prog %d vers %d proc %d type %d"), + client->msg.header.prog, client->msg.header.vers, + client->msg.header.proc, client->msg.header.type); + return -1; + } +} + + +static ssize_t +virNetClientIOWriteMessage(virNetClientPtr client, + virNetClientCallPtr thecall) +{ + ssize_t ret; + + ret = virNetSocketWrite(client->sock, + thecall->msg->buffer + thecall->msg->bufferOffset, + thecall->msg->bufferLength - thecall->msg->bufferOffset); + if (ret <= 0) + return ret; + + thecall->msg->bufferOffset += ret; + + if (thecall->msg->bufferOffset == thecall->msg->bufferLength) { + thecall->msg->bufferOffset = thecall->msg->bufferLength = 0; + if (thecall->expectReply) + thecall->mode = VIR_NET_CLIENT_MODE_WAIT_RX; + else + thecall->mode = VIR_NET_CLIENT_MODE_COMPLETE; + } + + return ret; +} + + +static ssize_t +virNetClientIOHandleOutput(virNetClientPtr client) +{ + virNetClientCallPtr thecall = client->waitDispatch; + + while (thecall && + thecall->mode != VIR_NET_CLIENT_MODE_WAIT_TX) + thecall = thecall->next; + + if (!thecall) + return -1; /* Shouldn't happen, but you never know... */ + + while (thecall) { + ssize_t ret = virNetClientIOWriteMessage(client, thecall); + if (ret < 0) + return ret; + + if (thecall->mode == VIR_NET_CLIENT_MODE_WAIT_TX) + return 0; /* Blocking write, to back to event loop */ + + thecall = thecall->next; + } + + return 0; /* No more calls to send, all done */ +} + +static ssize_t +virNetClientIOReadMessage(virNetClientPtr client) +{ + size_t wantData; + ssize_t ret; + + /* Start by reading length word */ + if (client->msg.bufferLength == 0) + client->msg.bufferLength = 4; + + wantData = client->msg.bufferLength - client->msg.bufferOffset; + + ret = virNetSocketRead(client->sock, + client->msg.buffer + client->msg.bufferOffset, + wantData); + if (ret <= 0) + return ret; + + client->msg.bufferOffset += ret; + + return ret; +} + + +static ssize_t +virNetClientIOHandleInput(virNetClientPtr client) +{ + /* Read as much data as is available, until we get + * EAGAIN + */ + for (;;) { + ssize_t ret = virNetClientIOReadMessage(client); + + if (ret < 0) + return -1; + if (ret == 0) + return 0; /* Blocking on read */ + + /* Check for completion of our goal */ + if (client->msg.bufferOffset == client->msg.bufferLength) { + if (client->msg.bufferOffset == 4) { + ret = virNetMessageDecodeLength(&client->msg); + if (ret < 0) + return -1; + + /* + * We'll carry on around the loop to immediately + * process the message body, because it has probably + * already arrived. Worst case, we'll get EAGAIN on + * next iteration. + */ + } else { + ret = virNetClientCallDispatch(client); + client->msg.bufferOffset = client->msg.bufferLength = 0; + /* + * We've completed one call, so return even + * though there might still be more data on + * the wire. We need to actually let the caller + * deal with this arrived message to keep good + * response, and also to correctly handle EOF. + */ + return ret; + } + } + } +} + + +/* + * Process all calls pending dispatch/receive until we + * get a reply to our own call. Then quit and pass the buck + * to someone else. + */ +static int virNetClientIOEventLoop(virNetClientPtr client, + virNetClientCallPtr thiscall) +{ + struct pollfd fds[2]; + int ret; + + fds[0].fd = virNetSocketGetFD(client->sock); + fds[1].fd = client->wakeupReadFD; + + for (;;) { + virNetClientCallPtr tmp = client->waitDispatch; + virNetClientCallPtr prev; + char ignore; +#ifdef HAVE_PTHREAD_SIGMASK + sigset_t oldmask, blockedsigs; +#endif + + fds[0].events = fds[0].revents = 0; + fds[1].events = fds[1].revents = 0; + + fds[1].events = POLLIN; + while (tmp) { + if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_RX) + fds[0].events |= POLLIN; + if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_TX) + fds[0].events |= POLLOUT; + + tmp = tmp->next; + } + +#if 0 + XXX + if (client->streams) + fds[0].events |= POLLIN; +#endif + + /* Release lock while poll'ing so other threads + * can stuff themselves on the queue */ + virNetClientUnlock(client); + + /* Block SIGWINCH from interrupting poll in curses programs, + * then restore the original signal mask again immediately + * after the call (RHBZ#567931). Same for SIGCHLD and SIGPIPE + * at the suggestion of Paolo Bonzini and Daniel Berrange. + */ +#ifdef HAVE_PTHREAD_SIGMASK + sigemptyset (&blockedsigs); + sigaddset (&blockedsigs, SIGWINCH); + sigaddset (&blockedsigs, SIGCHLD); + sigaddset (&blockedsigs, SIGPIPE); + ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask)); +#endif + + repoll: + ret = poll(fds, ARRAY_CARDINALITY(fds), -1); + if (ret < 0 && errno == EAGAIN) + goto repoll; + +#ifdef HAVE_PTHREAD_SIGMASK + ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL)); +#endif + + virNetClientLock(client); + + if (fds[1].revents) { + VIR_DEBUG0("Woken up from poll by other thread"); + if (saferead(client->wakeupReadFD, &ignore, sizeof(ignore)) != sizeof(ignore)) { + virReportSystemError(errno, "%s", + _("read on wakeup fd failed")); + goto error; + } + } + + if (ret < 0) { + if (errno == EWOULDBLOCK) + continue; + virReportSystemError(errno, + "%s", _("poll on socket failed")); + goto error; + } + + if (fds[0].revents & POLLOUT) { + if (virNetClientIOHandleOutput(client) < 0) + goto error; + } + + if (fds[0].revents & POLLIN) { + if (virNetClientIOHandleInput(client) < 0) + goto error; + } + + /* Iterate through waiting threads and if + * any are complete then tell 'em to wakeup + */ + tmp = client->waitDispatch; + prev = NULL; + while (tmp) { + if (tmp != thiscall && + tmp->mode == VIR_NET_CLIENT_MODE_COMPLETE) { + /* Take them out of the list */ + if (prev) + prev->next = tmp->next; + else + client->waitDispatch = tmp->next; + + /* And wake them up.... + * ...they won't actually wakeup until + * we release our mutex a short while + * later... + */ + VIR_DEBUG("Waking up sleep %p %p", tmp, client->waitDispatch); + virCondSignal(&tmp->cond); + } + prev = tmp; + tmp = tmp->next; + } + + /* Now see if *we* are done */ + if (thiscall->mode == VIR_NET_CLIENT_MODE_COMPLETE) { + /* We're at head of the list already, so + * remove us + */ + client->waitDispatch = thiscall->next; + VIR_DEBUG("Giving up the buck %p %p", thiscall, client->waitDispatch); + /* See if someone else is still waiting + * and if so, then pass the buck ! */ + if (client->waitDispatch) { + VIR_DEBUG("Passing the buck to %p", client->waitDispatch); + virCondSignal(&client->waitDispatch->cond); + } + return 0; + } + + + if (fds[0].revents & (POLLHUP | POLLERR)) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("received hangup / error event on socket")); + goto error; + } + } + + +error: + client->waitDispatch = thiscall->next; + VIR_DEBUG("Giving up the buck due to I/O error %p %p", thiscall, client->waitDispatch); + /* See if someone else is still waiting + * and if so, then pass the buck ! */ + if (client->waitDispatch) { + VIR_DEBUG("Passing the buck to %p", client->waitDispatch); + virCondSignal(&client->waitDispatch->cond); + } + return -1; +} + + +/* + * This function sends a message to remote server and awaits a reply + * + * NB. This does not free the args structure (not desirable, since you + * often want this allocated on the stack or else it contains strings + * which come from the user). It does however free any intermediate + * results, eg. the error structure if there is one. + * + * NB(2). Make sure to memset (&ret, 0, sizeof ret) before calling, + * else Bad Things will happen in the XDR code. + * + * NB(3) You must have the client lock before calling this + * + * NB(4) This is very complicated. Multiple threads are allowed to + * use the client for RPC at the same time. Obviously only one of + * them can. So if someone's using the socket, other threads are put + * to sleep on condition variables. The existing thread may completely + * send & receive their RPC call/reply while they're asleep. Or it + * may only get around to dealing with sending the call. Or it may + * get around to neither. So upon waking up from slumber, the other + * thread may or may not have more work todo. + * + * We call this dance 'passing the buck' + * + * http://en.wikipedia.org/wiki/Passing_the_buck + * + * "Buck passing or passing the buck is the action of transferring + * responsibility or blame unto another person. It is also used as + * a strategy in power politics when the actions of one country/ + * nation are blamed on another, providing an opportunity for war." + * + * NB(5) Don't Panic! + */ +static int virNetClientIO(virNetClientPtr client, + virNetClientCallPtr thiscall) +{ + int rv = -1; + + VIR_DEBUG("program=%u version=%u serial=%u proc=%d type=%d length=%zu dispatch=%p", + thiscall->msg->header.prog, + thiscall->msg->header.vers, + thiscall->msg->header.serial, + thiscall->msg->header.proc, + thiscall->msg->header.type, + thiscall->msg->bufferLength, + client->waitDispatch); + + /* Check to see if another thread is dispatching */ + if (client->waitDispatch) { + /* Stick ourselves on the end of the wait queue */ + virNetClientCallPtr tmp = client->waitDispatch; + char ignore = 1; + while (tmp && tmp->next) + tmp = tmp->next; + if (tmp) + tmp->next = thiscall; + else + client->waitDispatch = thiscall; + + /* Force other thread to wakeup from poll */ + if (safewrite(client->wakeupSendFD, &ignore, sizeof(ignore)) != sizeof(ignore)) { + if (tmp) + tmp->next = NULL; + else + client->waitDispatch = NULL; + virReportSystemError(errno, "%s", + _("failed to wake up polling thread")); + return -1; + } + + VIR_DEBUG("Going to sleep %p %p", client->waitDispatch, thiscall); + /* Go to sleep while other thread is working... */ + if (virCondWait(&thiscall->cond, &client->lock) < 0) { + if (client->waitDispatch == thiscall) { + client->waitDispatch = thiscall->next; + } else { + tmp = client->waitDispatch; + while (tmp && tmp->next && + tmp->next != thiscall) { + tmp = tmp->next; + } + if (tmp && tmp->next == thiscall) + tmp->next = thiscall->next; + } + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to wait on condition")); + return -1; + } + + VIR_DEBUG("Wokeup from sleep %p %p", client->waitDispatch, thiscall); + /* Two reasons we can be woken up + * 1. Other thread has got our reply ready for us + * 2. Other thread is all done, and it is our turn to + * be the dispatcher to finish waiting for + * our reply + */ + if (thiscall->mode == VIR_NET_CLIENT_MODE_COMPLETE) { + rv = 0; + /* + * We avoided catching the buck and our reply is ready ! + * We've already had 'thiscall' removed from the list + * so just need to (maybe) handle errors & free it + */ + goto cleanup; + } + + /* Grr, someone passed the buck onto us ... */ + + } else { + /* We're first to catch the buck */ + client->waitDispatch = thiscall; + } + + VIR_DEBUG("We have the buck %p %p", client->waitDispatch, thiscall); + /* + * The buck stops here! + * + * At this point we're about to own the dispatch + * process... + */ + + /* + * Avoid needless wake-ups of the event loop in the + * case where this call is being made from a different + * thread than the event loop. These wake-ups would + * cause the event loop thread to be blocked on the + * mutex for the duration of the call + */ + virNetSocketUpdateIOCallback(client->sock, 0); + + rv = virNetClientIOEventLoop(client, thiscall); + + virNetSocketUpdateIOCallback(client->sock, VIR_EVENT_HANDLE_READABLE); + +cleanup: + VIR_DEBUG("All done with our call %p %p %d", client->waitDispatch, thiscall, rv); + return rv; +} + + +void virNetClientIncomingEvent(virNetSocketPtr sock, + int events, + void *opaque) +{ + virNetClientPtr client = opaque; + + virNetClientLock(client); + + /* This should be impossible, but it doesn't hurt to check */ + if (client->waitDispatch) + goto done; + + VIR_DEBUG("Event fired %p %d", sock, events); + + if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { + VIR_DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " + "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); + virNetSocketRemoveIOCallback(sock); + goto done; + } + + if (virNetClientIOHandleInput(client) < 0) + VIR_DEBUG0("Something went wrong during async message processing"); + +done: + virNetClientUnlock(client); +} + + +int virNetClientSend(virNetClientPtr client, + virNetMessagePtr msg, + bool expectReply) +{ + virNetClientCallPtr call; + int ret = -1; + + if (VIR_ALLOC(call) < 0) { + virReportOOMError(); + return -1; + } + + virNetClientLock(client); + + if (virCondInit(&call->cond) < 0) { + virNetError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize condition variable")); + goto cleanup; + } + + call->mode = VIR_NET_CLIENT_MODE_WAIT_TX; + call->msg = msg; + call->expectReply = expectReply; + + ret = virNetClientIO(client, call); + +cleanup: + VIR_FREE(call); + virNetClientUnlock(client); + return ret; +} diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h new file mode 100644 index 0000000..600b00a --- /dev/null +++ b/src/rpc/virnetclient.h @@ -0,0 +1,75 @@ +/* + * virnetclient.h: generic network RPC client + * + * Copyright (C) 2006-2010 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_NET_CLIENT_H__ +# define __VIR_NET_CLIENT_H__ + +# include <stdbool.h> + +# include "virnettlscontext.h" +# include "virnetmessage.h" +# include "virnetsaslcontext.h" +# include "virnetclientprogram.h" + + +virNetClientPtr virNetClientNewUNIX(const char *path, + bool spawnDaemon, + const char *daemon); + +virNetClientPtr virNetClientNewTCP(const char *nodename, + const char *service); + +virNetClientPtr virNetClientNewSSH(const char *nodename, + const char *service, + const char *binary, + const char *username, + bool noTTY, + const char *netcat, + const char *path); + +virNetClientPtr virNetClientNewExternal(const char **cmdargv); + +void virNetClientRef(virNetClientPtr client); + +int virNetClientAddProgram(virNetClientPtr client, + virNetClientProgramPtr prog); + +int virNetClientSend(virNetClientPtr client, + virNetMessagePtr msg, + bool expectReply); + +void virNetClientSetSASLSession(virNetClientPtr client, + virNetSASLSessionPtr sasl); + +int virNetClientSetTLSSession(virNetClientPtr client, + virNetTLSContextPtr tls); + +bool virNetClientIsEncrypted(virNetClientPtr client); + +const char *virNetClientLocalAddrString(virNetClientPtr client); +const char *virNetClientRemoteAddrString(virNetClientPtr client); + +int virNetClientGetTLSKeySize(virNetClientPtr client); + +void virNetClientFree(virNetClientPtr client); + +#endif /* __VIR_NET_CLIENT_H__ */ diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c new file mode 100644 index 0000000..73ae6eb --- /dev/null +++ b/src/rpc/virnetclientprogram.c @@ -0,0 +1,301 @@ +/* + * virnetclientprogram.c: generic network RPC client program + * + * Copyright (C) 2006-2010 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include "virnetclientprogram.h" +#include "virnetclient.h" +#include "virnetprotocol.h" + +#include "memory.h" +#include "virterror_internal.h" +#include "logging.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +struct _virNetClientProgram { + int refs; + + unsigned program; + unsigned version; + virNetClientProgramEventPtr events; + size_t nevents; + void *eventOpaque; +}; + +virNetClientProgramPtr virNetClientProgramNew(unsigned program, + unsigned version, + virNetClientProgramEventPtr events, + size_t nevents, + void *eventOpaque) +{ + virNetClientProgramPtr prog; + + if (VIR_ALLOC(prog) < 0) { + virReportOOMError(); + return NULL; + } + + prog->refs = 1; + prog->program = program; + prog->version = version; + prog->events = events; + prog->nevents = nevents; + prog->eventOpaque = eventOpaque; + + return prog; +} + + +void virNetClientProgramRef(virNetClientProgramPtr prog) +{ + prog->refs++; +} + + +void virNetClientProgramFree(virNetClientProgramPtr prog) +{ + if (!prog) + return; + + prog->refs--; + if (prog->refs > 0) + return; + + VIR_FREE(prog); +} + + +int virNetClientProgramMatches(virNetClientProgramPtr prog, + virNetMessagePtr msg) +{ + if (prog->program == msg->header.prog && + prog->version == msg->header.vers) + return 1; + return 0; +} + + +static int virNetClientProgramDispatchError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetMessagePtr msg) +{ + virNetMessageError err; + int ret = -1; + + memset(&err, 0, sizeof(err)); + + if (virNetMessageDecodePayload(msg, (xdrproc_t)xdr_virNetMessageError, &err) < 0) + goto cleanup; + + /* XXX what about the old "quiet" errors for missing auth RPC */ + if (err.domain == VIR_FROM_REMOTE && + err.code == VIR_ERR_RPC && + err.level == VIR_ERR_ERROR && + err.message && + STRPREFIX(*err.message, "unknown procedure")) { + virRaiseErrorFull(NULL, + __FILE__, __FUNCTION__, __LINE__, + err.domain, + VIR_ERR_NO_SUPPORT, + err.level, + err.str1 ? *err.str1 : NULL, + err.str2 ? *err.str2 : NULL, + err.str3 ? *err.str3 : NULL, + err.int1, + err.int2, + "%s", *err.message); + } else { + virRaiseErrorFull(NULL, + __FILE__, __FUNCTION__, __LINE__, + err.domain, + err.code, + err.level, + err.str1 ? *err.str1 : NULL, + err.str2 ? *err.str2 : NULL, + err.str3 ? *err.str3 : NULL, + err.int1, + err.int2, + "%s", err.message ? *err.message : _("Unknown error")); + } + + ret = 0; + +cleanup: + xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)&err); + return ret; +} + + +static virNetClientProgramEventPtr virNetClientProgramGetEvent(virNetClientProgramPtr prog, + int procedure) +{ + int i; + + for (i = 0 ; i < prog->nevents ; i++) { + if (prog->events[i].proc == procedure) + return &prog->events[i]; + } + + return NULL; +} + + +int virNetClientProgramDispatch(virNetClientProgramPtr prog, + virNetClientPtr client, + virNetMessagePtr msg) +{ + virNetClientProgramEventPtr event; + char *evdata; + + VIR_DEBUG("prog=%d ver=%d type=%d status=%d serial=%d proc=%d", + msg->header.prog, msg->header.vers, msg->header.type, + msg->header.status, msg->header.serial, msg->header.proc); + + /* Check version, etc. */ + if (msg->header.prog != prog->program) { + VIR_ERROR(_("program mismatch in event (actual %x, expected %x)"), + msg->header.prog, prog->program); + return -1; + } + + if (msg->header.vers != prog->version) { + VIR_ERROR(_("version mismatch in event (actual %x, expected %x)"), + msg->header.vers, prog->version); + return -1; + } + + if (msg->header.status != VIR_NET_OK) { + VIR_ERROR(_("status mismatch in event (actual %x, expected %x)"), + msg->header.status, VIR_NET_OK); + return -1; + } + + if (msg->header.type != VIR_NET_MESSAGE) { + VIR_ERROR(_("type mismatch in event (actual %x, expected %x)"), + msg->header.type, VIR_NET_MESSAGE); + return -1; + } + + event = virNetClientProgramGetEvent(prog, msg->header.proc); + + if (!event) { + VIR_ERROR(_("No event expected with procedure %x"), + msg->header.proc); + return -1; + } + + if (VIR_ALLOC_N(evdata, event->msg_len) < 0) { + virReportOOMError(); + return -1; + } + + if (virNetMessageDecodePayload(msg, event->msg_filter, evdata) < 0) + goto cleanup; + + event->func(prog, client, &evdata, prog->eventOpaque); + + xdr_free(event->msg_filter, evdata); + +cleanup: + VIR_FREE(evdata); + return 0; +} + + +int virNetClientProgramCall(virNetClientProgramPtr prog, + virNetClientPtr client, + unsigned serial, + int proc, + xdrproc_t args_filter, void *args, + xdrproc_t ret_filter, void *ret) +{ + virNetMessagePtr msg; + + if (!(msg = virNetMessageNew())) + return -1; + + msg->header.prog = prog->program; + msg->header.vers = prog->version; + msg->header.status = VIR_NET_OK; + msg->header.type = VIR_NET_CALL; + msg->header.serial = serial; + msg->header.proc = proc; + + if (virNetMessageEncodeHeader(msg) < 0) + goto error; + + if (virNetMessageEncodePayload(msg, args_filter, args) < 0) + goto error; + + if (virNetClientSend(client, msg, true) < 0) + goto error; + + /* None of these 3 should ever happen here, because + * virNetClientSend should have validated the reply, + * but it doesn't hurt to check again. + */ + if (msg->header.type != VIR_NET_REPLY) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected message type %d"), msg->header.type); + goto error; + } + if (msg->header.proc != proc) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected message proc %d != %d"), + msg->header.proc, proc); + goto error; + } + if (msg->header.serial != serial) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected message serial %d != %d"), + msg->header.serial, serial); + goto error; + } + + switch (msg->header.status) { + case VIR_NET_OK: + if (virNetMessageDecodePayload(msg, ret_filter, ret) < 0) + goto error; + break; + + case VIR_NET_ERROR: + virNetClientProgramDispatchError(prog, msg); + goto error; + + default: + virNetError(VIR_ERR_RPC, + _("Unexpected message status %d"), msg->header.status); + goto error; + } + + VIR_FREE(msg); + + return 0; + +error: + VIR_FREE(msg); + return -1; +} diff --git a/src/rpc/virnetclientprogram.h b/src/rpc/virnetclientprogram.h new file mode 100644 index 0000000..e52e442 --- /dev/null +++ b/src/rpc/virnetclientprogram.h @@ -0,0 +1,82 @@ +/* + * virnetclientprogram.h: generic network RPC client program + * + * Copyright (C) 2006-2010 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#ifndef __VIR_NET_CLIENT_PROGRAM_H__ +# define __VIR_NET_CLIENT_PROGRAM_H__ + +# include <rpc/types.h> +# include <rpc/xdr.h> + +# include "virnetmessage.h" + +typedef struct _virNetClient virNetClient; +typedef virNetClient *virNetClientPtr; + +typedef struct _virNetClientProgram virNetClientProgram; +typedef virNetClientProgram *virNetClientProgramPtr; + +typedef struct _virNetClientProgramEvent virNetClientProgramEvent; +typedef virNetClientProgramEvent *virNetClientProgramEventPtr; + +typedef struct _virNetClientProgramErrorHandler virNetClientProgramErrorHander; +typedef virNetClientProgramErrorHander *virNetClientProgramErrorHanderPtr; + + +typedef void (*virNetClientProgramDispatchFunc)(virNetClientProgramPtr prog, + virNetClientPtr client, + void *msg, + void *opaque); + +struct _virNetClientProgramEvent { + int proc; + virNetClientProgramDispatchFunc func; + size_t msg_len; + xdrproc_t msg_filter; +}; + +virNetClientProgramPtr virNetClientProgramNew(unsigned program, + unsigned version, + virNetClientProgramEventPtr events, + size_t nevents, + void *eventOpaque); + +void virNetClientProgramRef(virNetClientProgramPtr prog); + +void virNetClientProgramFree(virNetClientProgramPtr prog); + +int virNetClientProgramMatches(virNetClientProgramPtr prog, + virNetMessagePtr msg); + +int virNetClientProgramDispatch(virNetClientProgramPtr prog, + virNetClientPtr client, + virNetMessagePtr msg); + +int virNetClientProgramCall(virNetClientProgramPtr prog, + virNetClientPtr client, + unsigned serial, + int proc, + xdrproc_t args_filter, void *args, + xdrproc_t ret_filter, void *ret); + + + +#endif /* __VIR_NET_CLIENT_PROGRAM_H__ */ -- 1.7.2.3

A variant on the old remote_generate_stubs.pl which can generate generic stubs for RPC dispatch * src/rpc/gendispatch.pl: A script for generating RPC dispatchers --- src/Makefile.am | 4 + src/rpc/gendispatch.pl | 230 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 0 deletions(-) create mode 100644 src/rpc/gendispatch.pl diff --git a/src/Makefile.am b/src/Makefile.am index 9fbf210..18e61c5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1120,6 +1120,10 @@ EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt-net-rpc-server.la libvirt-net-rpc-client.la +EXTRA_DIST += \ + rpc/virnetprotocol.x \ + rpc/gendispatch.pl + libvirt_net_rpc_la_SOURCES = \ ../daemon/event.c \ rpc/virnetmessage.h rpc/virnetmessage.c \ diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl new file mode 100644 index 0000000..8f16948 --- /dev/null +++ b/src/rpc/gendispatch.pl @@ -0,0 +1,230 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2006-2010 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 +# +# This script parses a RPC program definition and produces +# boilerplate code for both ends of the remote connection. +# +# The first non-option argument specifies the prefix to be searched for, and +# output to, the boilerplate code. The second non-option argument is the +# file you want to operate on. For instance, to generate the dispatch table +# for both remote_protocol.x and qemu_protocol.x, you would run the +# following: +# +# generator.pl -c -t remote ../src/remote/remote_protocol.x +# generator.pl -t qemu ../src/remote/qemu_protocol.x +# +# By Richard Jones <rjones@redhat.com> + +use strict; + +use Getopt::Std; + +# Command line options. +our ($opt_p, $opt_t, $opt_a, $opt_r, $opt_d, $opt_c); +getopts ('ptardc'); + +my $structprefix = $ARGV[0]; +my $procprefix = uc $structprefix; +shift; + +# Convert name_of_call to NameOfCall. +sub name_to_ProcName { + my $name = shift; + my @elems = split /_/, $name; + @elems = map ucfirst, @elems; + join "", @elems +} + +# Read the input file (usually remote_protocol.x) and form an +# opinion about the name, args and return type of each RPC. +my ($name, $ProcName, $id, %calls, @calls); + +# only generate a close method if -c was passed +if ($opt_c) { + # REMOTE_PROC_CLOSE has no args or ret. + $calls{close} = { + name => "close", + ProcName => "Close", + UC_NAME => "CLOSE", + }; +} + +while (<>) { + if (/^struct ${structprefix}_(.*)_args/) { + $name = $1; + $ProcName = name_to_ProcName ($name); + + die "duplicate definition of ${structprefix}_${name}_args" + if exists $calls{$name}; + + $calls{$name} = { + name => $name, + ProcName => $ProcName, + UC_NAME => uc $name, + args => "${structprefix}_${name}_args", + }; + + } elsif (/^struct ${structprefix}_(.*)_ret/) { + $name = $1; + $ProcName = name_to_ProcName ($name); + + if (exists $calls{$name}) { + $calls{$name}->{ret} = "${structprefix}_${name}_ret"; + } else { + $calls{$name} = { + name => $name, + ProcName => $ProcName, + UC_NAME => uc $name, + ret => "${structprefix}_${name}_ret" + } + } + } elsif (/^struct ${structprefix}_(.*)_msg/) { + $name = $1; + $ProcName = name_to_ProcName ($name); + + $calls{$name} = { + name => $name, + ProcName => $ProcName, + UC_NAME => uc $name, + msg => "${structprefix}_${name}_msg" + } + } elsif (/^\s*${procprefix}_PROC_(.*?)\s+=\s+(\d+),?$/) { + $name = lc $1; + $id = $2; + $ProcName = name_to_ProcName ($name); + + $calls[$id] = $calls{$name}; + } +} + +#---------------------------------------------------------------------- +# Output + +print <<__EOF__; +/* Automatically generated by src/rpc/generator.pl + * Do not edit this file. Any changes you make will be lost. + * + * Copyright (C) 2006-2010 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 + * + */ + +__EOF__ + +# First we write out all the method signatures. We have one +# signature for the method that is manually implemented, which +# is strongly typed. +# Then a trivial helper method which is loosely typed based +# on what the RPC dispatch needs to use. The helper method +# casts the variables & calls the real method. The two methods +# are typically inlined by the compiler + +my @keys = sort (keys %calls); +foreach (@keys) { + # Skip things which are REMOTE_MESSAGE + next if $calls{$_}->{msg}; + + my $name = $structprefix . "Dispatch" . $calls{$_}->{ProcName}; + my $argtype = $calls{$_}->{args}; + my $rettype = $calls{$_}->{ret}; + + my $argann = $argtype ? "" : " ATTRIBUTE_UNUSED"; + my $retann = $rettype ? "" : " ATTRIBUTE_UNUSED"; + + print "static int ${name}(\n"; + print " virNetServerPtr server,\n"; + print " virNetServerClientPtr client,\n"; + print " virNetMessageHeaderPtr hdr"; + if ($argtype) { + print ",\n $argtype *args"; + } + if ($rettype) { + print ",\n $rettype *ret"; + } + print ");\n"; + + + print "static int ${name}Helper(\n"; + print " virNetServerPtr server,\n"; + print " virNetServerClientPtr client,\n"; + print " virNetMessageHeaderPtr hdr,\n"; + print " void *args$argann,\n"; + print " void *ret$retann)\n"; + print "{\n"; + print " VIR_DEBUG(\"server=%p client=%p hdr=%p args=%p ret=%p\", server, client, hdr, args, ret);\n"; + print " return $name(server, client, hdr"; + if ($argtype) { + print ", args"; + } + if ($rettype) { + print ", ret"; + } + print ");\n"; + print "}\n\n\n"; + +} + +# Then 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 ? "sizeof($argtype)" : "0"; + $retlen = $rettype ? "sizeof($rettype)" : "0"; + $argfilter = $argtype ? "xdr_$argtype" : "xdr_void"; + $retfilter = $rettype ? "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"; -- 1.7.2.3

This guts the current remote driver, removing all its networking handling code. Instead it calls out to the new virClientPtr and virClientProgramPtr APIs for all RPC & networking work. --- src/Makefile.am | 4 +- src/remote/remote_driver.c | 2596 ++++++++------------------------------------ 2 files changed, 451 insertions(+), 2149 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 18e61c5..334d535 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -474,11 +474,11 @@ libvirt_la_BUILT_LIBADD += libvirt_driver_remote.la endif libvirt_driver_remote_la_CFLAGS = \ $(GNUTLS_CFLAGS) \ - $(SASL_CFLAGS) \ -I@top_srcdir@/src/conf \ + -I@top_srcdir@/src/rpc \ $(AM_CFLAGS) libvirt_driver_remote_la_LDFLAGS = $(AM_LDFLAGS) -libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) $(SASL_LIBS) +libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) libvirt-net-rpc-client.la libvirt-net-rpc.la if WITH_DRIVER_MODULES libvirt_driver_remote_la_LDFLAGS += -module -avoid-version endif diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index fae191c..a997504 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -23,51 +23,13 @@ #include <config.h> -#include <stdio.h> -#include <stdlib.h> #include <unistd.h> -#include <string.h> #include <assert.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <arpa/inet.h> -#include <sys/wait.h> - -/* Windows socket compatibility functions. */ -#include <errno.h> -#include <sys/socket.h> - -#ifndef HAVE_WINSOCK2_H /* Unix & Cygwin. */ -# include <sys/un.h> -# include <net/if.h> -# include <netinet/in.h> -# include <netinet/tcp.h> -#endif - -#ifdef HAVE_PWD_H -# include <pwd.h> -#endif - -#ifdef HAVE_PATHS_H -# include <paths.h> -#endif -#include <rpc/types.h> -#include <rpc/xdr.h> -#include <gnutls/gnutls.h> -#include <gnutls/x509.h> -#include "gnutls_1_0_compat.h" -#if HAVE_SASL -# include <sasl/sasl.h> -#endif #include <libxml/uri.h> -#include <netdb.h> - -#include <poll.h> - +#include "virnetclient.h" +#include "virnetclientprogram.h" #include "virterror_internal.h" #include "logging.h" #include "datatypes.h" @@ -88,99 +50,22 @@ static int inside_daemon = 0; -struct remote_thread_call; - - -enum { - REMOTE_MODE_WAIT_TX, - REMOTE_MODE_WAIT_RX, - REMOTE_MODE_COMPLETE, - REMOTE_MODE_ERROR, -}; - -struct remote_thread_call { - int mode; - - /* Buffer for outgoing data packet - * 4 byte length, followed by RPC message header+body */ - char buffer[4 + REMOTE_MESSAGE_MAX]; - unsigned int bufferLength; - unsigned int bufferOffset; - - unsigned int serial; - unsigned int proc_nr; - - virCond cond; - - int want_reply; - xdrproc_t ret_filter; - char *ret; - - remote_error err; - - struct remote_thread_call *next; -}; +struct private_data { + virMutex lock; -struct private_stream_data { - unsigned int has_error : 1; - remote_error err; - - unsigned int serial; - unsigned int proc_nr; - - virStreamEventCallback cb; - void *cbOpaque; - virFreeCallback cbFree; - int cbEvents; - int cbTimer; - int cbDispatch; - - /* XXX this is potentially unbounded if the client - * app has domain events registered, since packets - * may be read off wire, while app isn't ready to - * recv them. Figure out how to address this some - * time.... - */ - char *incoming; - unsigned int incomingOffset; - unsigned int incomingLength; + virNetClientPtr client; + virNetClientProgramPtr remoteProgram; + virNetClientProgramPtr qemuProgram; - struct private_stream_data *next; -}; + int counter; /* Serial number for RPC */ -struct private_data { - virMutex lock; + virNetTLSContextPtr tls; - int sock; /* Socket. */ - int errfd; /* File handle connected to remote stderr */ int watch; /* File handle watch */ - pid_t pid; /* PID of tunnel process */ - int uses_tls; /* TLS enabled on socket? */ int is_secure; /* Secure if TLS or SASL or UNIX sockets */ - gnutls_session_t session; /* GnuTLS session (if uses_tls != 0). */ char *type; /* Cached return from remoteType. */ - int counter; /* Generates serial numbers for RPC. */ int localUses; /* Ref count for private data */ char *hostname; /* Original hostname */ - FILE *debugLog; /* Debug remote protocol */ - -#if HAVE_SASL - sasl_conn_t *saslconn; /* SASL context */ - - const char *saslDecoded; - unsigned int saslDecodedLength; - unsigned int saslDecodedOffset; - - const char *saslEncoded; - unsigned int saslEncodedLength; - unsigned int saslEncodedOffset; -#endif - - /* Buffer for incoming data packets - * 4 byte length, followed by RPC message header+body */ - char buffer[4 + REMOTE_MESSAGE_MAX]; - unsigned int bufferLength; - unsigned int bufferOffset; /* The list of domain event callbacks */ virDomainEventCallbackListPtr callbackList; @@ -191,22 +76,10 @@ struct private_data { int eventFlushTimer; /* Flag if we're in process of dispatching */ int domainEventDispatching; - - /* Self-pipe to wakeup threads waiting in poll() */ - int wakeupSendFD; - int wakeupReadFD; - - /* List of threads currently waiting for dispatch */ - struct remote_thread_call *waitDispatch; - - struct private_stream_data *streams; }; enum { - REMOTE_CALL_IN_OPEN = (1 << 0), - REMOTE_CALL_QUIET_MISSING_RPC = (1 << 1), - REMOTE_CALL_QEMU = (1 << 2), - REMOTE_CALL_NONBLOCK = (1 << 3), + REMOTE_CALL_QEMU = (1 << 0), }; @@ -220,22 +93,18 @@ static void remoteDriverUnlock(struct private_data *driver) virMutexUnlock(&driver->lock); } -static int remoteIO(virConnectPtr conn, - struct private_data *priv, - int flags, - struct remote_thread_call *thiscall); static int call (virConnectPtr conn, struct private_data *priv, int flags, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret); -static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int in_open, +static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth, const char *authtype); #if HAVE_SASL -static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, +static int remoteAuthSASL (virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth, const char *mech); #endif #if HAVE_POLKIT -static int remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, +static int remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth); #endif /* HAVE_POLKIT */ @@ -267,10 +136,6 @@ void remoteDomainEventQueueFlush(int timer, void *opaque); /* Helper functions for remoteOpen. */ static char *get_transport_from_scheme (char *scheme); -/* GnuTLS functions used by remoteOpen. */ -static int initialize_gnutls(void); -static gnutls_session_t negotiate_gnutls_on_connection (virConnectPtr conn, struct private_data *priv, int no_verify); - #ifdef WITH_LIBVIRTD static int remoteStartup(int privileged ATTRIBUTE_UNUSED) @@ -285,7 +150,7 @@ remoteStartup(int privileged ATTRIBUTE_UNUSED) #ifndef WIN32 /** - * remoteFindServerPath: + * remoteFindDaemonPath: * * Tries to find the path to the libvirtd binary. * @@ -312,36 +177,68 @@ remoteFindDaemonPath(void) } return NULL; } +#endif -/** - * qemuForkDaemon: - * - * Forks and try to launch the libvirtd daemon - * - * Returns 0 in case of success or -1 in case of detected error. - */ -static int -remoteForkDaemon(void) -{ - const char *daemonPath = remoteFindDaemonPath(); - const char *const daemonargs[] = { daemonPath, "--timeout=30", NULL }; - pid_t pid; - - if (!daemonPath) { - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to find libvirtd binary")); - return -1; - } - - if (virExecDaemonize(daemonargs, NULL, NULL, - &pid, -1, NULL, NULL, - VIR_EXEC_CLEAR_CAPS, - NULL, NULL, NULL) < 0) - return -1; - return 0; -} -#endif +static void +remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque); +static void +remoteDomainBuildEventReboot(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque); +static void +remoteDomainBuildEventRTCChange(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); +static void +remoteDomainBuildEventWatchdog(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); +static void +remoteDomainBuildEventIOError(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); +static void +remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); +static void +remoteDomainBuildEventGraphics(virNetClientProgramPtr prog, + virNetClientPtr client, + void *evdata, void *opaque); + +static virNetClientProgramEvent remoteDomainEvents[] = { + { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE, + remoteDomainBuildEventRTCChange, + sizeof(remote_domain_event_rtc_change_msg), + (xdrproc_t)xdr_remote_domain_event_rtc_change_msg }, + { REMOTE_PROC_DOMAIN_EVENT_REBOOT, + remoteDomainBuildEventReboot, + sizeof(remote_domain_event_reboot_msg), + (xdrproc_t)xdr_remote_domain_event_reboot_msg }, + { REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE, + remoteDomainBuildEventLifecycle, + sizeof(remote_domain_event_lifecycle_msg), + (xdrproc_t)xdr_remote_domain_event_lifecycle_msg }, + { REMOTE_PROC_DOMAIN_EVENT_WATCHDOG, + remoteDomainBuildEventWatchdog, + sizeof(remote_domain_event_watchdog_msg), + (xdrproc_t)xdr_remote_domain_event_watchdog_msg}, + { REMOTE_PROC_DOMAIN_EVENT_IO_ERROR, + remoteDomainBuildEventIOError, + sizeof(remote_domain_event_io_error_msg), + (xdrproc_t)xdr_remote_domain_event_io_error_msg }, + { REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON, + remoteDomainBuildEventIOErrorReason, + sizeof(remote_domain_event_io_error_reason_msg), + (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg }, + { REMOTE_PROC_DOMAIN_EVENT_GRAPHICS, + remoteDomainBuildEventGraphics, + sizeof(remote_domain_event_graphics_msg), + (xdrproc_t)xdr_remote_domain_event_graphics_address }, +}; enum virDrvOpenRemoteFlags { VIR_DRV_OPEN_REMOTE_RO = (1 << 0), @@ -374,7 +271,6 @@ doRemoteOpen (virConnectPtr conn, int flags) { struct qparam_set *vars = NULL; - int wakeupFD[2] = { -1, -1 }; char *transport_str = NULL; enum { trans_tls, @@ -503,15 +399,10 @@ doRemoteOpen (virConnectPtr conn, } else if (STRCASEEQ (var->name, "no_tty")) { no_tty = atoi (var->value); var->ignore = 1; - } else if (STRCASEEQ (var->name, "debug")) { - if (var->value && - STRCASEEQ (var->value, "stdout")) - priv->debugLog = stdout; - else - priv->debugLog = stderr; - } else + } else { DEBUG("passing through variable '%s' ('%s') to remote end", var->name, var->value); + } } /* Construct the original name. */ @@ -574,89 +465,35 @@ doRemoteOpen (virConnectPtr conn, goto failed; } + + VIR_DEBUG("Connecting with transport %d", transport); /* Connect to the remote service. */ switch (transport) { case trans_tls: - if (initialize_gnutls() == -1) goto failed; - priv->uses_tls = 1; + priv->tls = virNetTLSContextNewClient(LIBVIRT_CACERT, + LIBVIRT_CLIENTCERT, + LIBVIRT_CLIENTKEY, + no_verify ? false : true); + if (!priv->tls) + goto failed; priv->is_secure = 1; /*FALLTHROUGH*/ - case trans_tcp: { - // http://people.redhat.com/drepper/userapi-ipv6.html - struct addrinfo *res, *r; - struct addrinfo hints; - int saved_errno = EINVAL; - memset (&hints, 0, sizeof hints); - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG; - int e = getaddrinfo (priv->hostname, port, &hints, &res); - if (e != 0) { - remoteError(VIR_ERR_SYSTEM_ERROR, - _("unable to resolve hostname '%s': %s"), - priv->hostname, gai_strerror (e)); + case trans_tcp: + priv->client = virNetClientNewTCP(priv->hostname, port); + if (!priv->client) goto failed; - } - - /* Try to connect to each returned address in turn. */ - /* XXX This loop contains a subtle problem. In the case - * where a host is accessible over IPv4 and IPv6, it will - * try the IPv4 and IPv6 addresses in turn. However it - * should be able to present different client certificates - * (because the commonName field in a client cert contains - * the client IP address, which is different for IPv4 and - * IPv6). At the moment we only have a single client - * certificate, and no way to specify what address family - * that certificate belongs to. - */ - for (r = res; r; r = r->ai_next) { - int no_slow_start = 1; - - priv->sock = socket (r->ai_family, SOCK_STREAM, 0); - if (priv->sock == -1) { - saved_errno = errno; - continue; - } - - /* Disable Nagle - Dan Berrange. */ - setsockopt (priv->sock, - IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start, - sizeof no_slow_start); - - if (connect (priv->sock, r->ai_addr, r->ai_addrlen) == -1) { - saved_errno = errno; - VIR_FORCE_CLOSE(priv->sock); - continue; - } - if (priv->uses_tls) { - priv->session = - negotiate_gnutls_on_connection - (conn, priv, no_verify); - if (!priv->session) { - VIR_FORCE_CLOSE(priv->sock); - goto failed; - } - } - goto tcp_connected; + if (priv->tls) { + VIR_DEBUG0("Starting TLS session"); + if (virNetClientSetTLSSession(priv->client, priv->tls) < 0) + goto failed; } - freeaddrinfo (res); - virReportSystemError(saved_errno, - _("unable to connect to libvirtd at '%s'"), - priv->hostname); - goto failed; - - tcp_connected: - freeaddrinfo (res); - - // NB. All versioning is done by the RPC headers, so we don't - // need to worry (at this point anyway) about versioning. break; - } #ifndef WIN32 - case trans_unix: { + case trans_unix: if (!sockname) { if (flags & VIR_DRV_OPEN_REMOTE_USER) { char *userdir = virGetUserDirectory(getuid()); @@ -671,153 +508,57 @@ doRemoteOpen (virConnectPtr conn, VIR_FREE(userdir); } else { if (flags & VIR_DRV_OPEN_REMOTE_RO) - sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET_RO); + sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO); else - sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET); + sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET); if (sockname == NULL) goto out_of_memory; } + VIR_DEBUG("Proceeding with sockname %s", sockname); } -# ifndef UNIX_PATH_MAX -# define UNIX_PATH_MAX(addr) (sizeof (addr).sun_path) -# endif - struct sockaddr_un addr; - int trials = 0; - - memset (&addr, 0, sizeof addr); - addr.sun_family = AF_UNIX; - if (virStrcpyStatic(addr.sun_path, sockname) == NULL) { - remoteError(VIR_ERR_INTERNAL_ERROR, - _("Socket %s too big for destination"), sockname); - goto failed; - } - if (addr.sun_path[0] == '@') - addr.sun_path[0] = '\0'; - - autostart_retry: - priv->is_secure = 1; - priv->sock = socket (AF_UNIX, SOCK_STREAM, 0); - if (priv->sock == -1) { - virReportSystemError(errno, "%s", - _("unable to create socket")); - goto failed; - } - if (connect (priv->sock, (struct sockaddr *) &addr, sizeof addr) == -1) { - /* We might have to autostart the daemon in some cases.... - * It takes a short while for the daemon to startup, hence we - * have a number of retries, with a small sleep. This will - * sometimes cause multiple daemons to be started - this is - * ok because the duplicates will fail to bind to the socket - * and immediately exit, leaving just one daemon. - */ - if (errno == ECONNREFUSED && - flags & VIR_DRV_OPEN_REMOTE_AUTOSTART && - trials < 20) { - VIR_FORCE_CLOSE(priv->sock); - if (trials > 0 || - remoteForkDaemon() == 0) { - trials++; - usleep(1000 * 100 * trials); - goto autostart_retry; - } - } - virReportSystemError(errno, - _("unable to connect to '%s', libvirtd may need to be started"), - sockname); + if (!(priv->client = virNetClientNewUNIX(sockname, + flags & VIR_DRV_OPEN_REMOTE_AUTOSTART, + remoteFindDaemonPath()))) goto failed; - } break; - } - - case trans_ssh: { - int j, nr_args = 6; - - if (username) nr_args += 2; /* For -l username */ - if (no_tty) nr_args += 5; /* For -T -o BatchMode=yes -e none */ - if (port) nr_args += 2; /* For -p port */ + case trans_ssh: command = command ? command : strdup ("ssh"); if (command == NULL) goto out_of_memory; - // Generate the final command argv[] array. - // ssh [-p $port] [-l $username] $hostname $netcat -U $sockname [NULL] - if (VIR_ALLOC_N(cmd_argv, nr_args) < 0) - goto out_of_memory; - - j = 0; - cmd_argv[j++] = strdup (command); - if (port) { - cmd_argv[j++] = strdup ("-p"); - cmd_argv[j++] = strdup (port); - } - if (username) { - cmd_argv[j++] = strdup ("-l"); - cmd_argv[j++] = strdup (username); - } - if (no_tty) { - cmd_argv[j++] = strdup ("-T"); - cmd_argv[j++] = strdup ("-o"); - cmd_argv[j++] = strdup ("BatchMode=yes"); - cmd_argv[j++] = strdup ("-e"); - cmd_argv[j++] = strdup ("none"); - } - cmd_argv[j++] = strdup (priv->hostname); - cmd_argv[j++] = strdup (netcat ? netcat : "nc"); - cmd_argv[j++] = strdup ("-U"); - cmd_argv[j++] = strdup (sockname ? sockname : - (flags & VIR_CONNECT_RO - ? LIBVIRTD_PRIV_UNIX_SOCKET_RO - : LIBVIRTD_PRIV_UNIX_SOCKET)); - cmd_argv[j++] = 0; - assert (j == nr_args); - for (j = 0; j < (nr_args-1); j++) - if (cmd_argv[j] == NULL) + if (!sockname) { + if (flags & VIR_DRV_OPEN_REMOTE_RO) + sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO); + else + sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET); + if (sockname == NULL) goto out_of_memory; - - priv->is_secure = 1; - } - - /*FALLTHROUGH*/ - case trans_ext: { - pid_t pid; - int sv[2]; - int errfd[2]; - - /* Fork off the external process. Use socketpair to create a private - * (unnamed) Unix domain socket to the child process so we don't have - * to faff around with two file descriptors (a la 'pipe(2)'). - */ - if (socketpair (PF_UNIX, SOCK_STREAM, 0, sv) == -1) { - virReportSystemError(errno, "%s", - _("unable to create socket pair")); - goto failed; } - if (pipe(errfd) == -1) { - virReportSystemError(errno, "%s", - _("unable to create socket pair")); + if (!(priv->client = virNetClientNewSSH(priv->hostname, + port, + command, + username, + no_tty, + netcat ? netcat : "nc", + sockname))) goto failed; - } - if (virExec((const char**)cmd_argv, NULL, NULL, - &pid, sv[1], &(sv[1]), &(errfd[1]), - VIR_EXEC_CLEAR_CAPS) < 0) - goto failed; + priv->is_secure = 1; + break; - /* Parent continues here. */ - VIR_FORCE_CLOSE(sv[1]); - VIR_FORCE_CLOSE(errfd[1]); - priv->sock = sv[0]; - priv->errfd = errfd[0]; - priv->pid = pid; + case trans_ext: + if (!(priv->client = virNetClientNewExternal((const char **)cmd_argv))) + goto failed; /* Do not set 'is_secure' flag since we can't guarentee * an external program is secure, and this flag must be * pessimistic */ - } + break; + #else /* WIN32 */ case trans_unix: @@ -829,37 +570,31 @@ doRemoteOpen (virConnectPtr conn, goto failed; #endif /* WIN32 */ - } /* switch (transport) */ - if (virSetNonBlock(priv->sock) < 0) { - virReportSystemError(errno, "%s", - _("unable to make socket non-blocking")); - goto failed; - } - - if ((priv->errfd != -1) && virSetNonBlock(priv->errfd) < 0) { - virReportSystemError(errno, "%s", - _("unable to make socket non-blocking")); + if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM, + REMOTE_PROTOCOL_VERSION, + remoteDomainEvents, + ARRAY_CARDINALITY(remoteDomainEvents), + conn))) goto failed; - } - - if (pipe(wakeupFD) < 0) { - virReportSystemError(errno, "%s", - _("unable to make pipe")); + if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM, + QEMU_PROTOCOL_VERSION, + NULL, + 0, + NULL))) goto failed; - } - priv->wakeupReadFD = wakeupFD[0]; - priv->wakeupSendFD = wakeupFD[1]; /* Try and authenticate with server */ - if (remoteAuthenticate(conn, priv, 1, auth, authtype) == -1) + VIR_DEBUG0("Trying authentication"); + if (remoteAuthenticate(conn, priv, auth, authtype) == -1) goto failed; /* Finally we can call the remote side's open function. */ remote_open_args args = { &name, flags }; - if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN, + VIR_DEBUG("Trying to open URI %s", name); + if (call (conn, priv, 0, REMOTE_PROC_OPEN, (xdrproc_t) xdr_remote_open_args, (char *) &args, (xdrproc_t) xdr_void, (char *) NULL) == -1) goto failed; @@ -867,26 +602,14 @@ doRemoteOpen (virConnectPtr conn, /* Now try and find out what URI the daemon used */ if (conn->uri == NULL) { remote_get_uri_ret uriret; - int urierr; + VIR_DEBUG0("Trying to query remote URI"); memset (&uriret, 0, sizeof uriret); - urierr = call (conn, priv, - REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC, - REMOTE_PROC_GET_URI, - (xdrproc_t) xdr_void, (char *) NULL, - (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret); - if (urierr == -2) { - /* Should not really happen, since we only probe local libvirtd's, - & the library should always match the daemon. Only case is post - RPM upgrade where an old daemon instance is still running with - new client. Too bad. It is not worth the hassle to fix this */ - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("unable to auto-detect URI")); - goto failed; - } - if (urierr == -1) { + if (call (conn, priv, 0, + REMOTE_PROC_GET_URI, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret) < 0) goto failed; - } DEBUG("Auto-probed URI is %s", uriret.uri); conn->uri = xmlParseURI(uriret.uri); @@ -897,36 +620,23 @@ doRemoteOpen (virConnectPtr conn, } } - if(VIR_ALLOC(priv->callbackList)<0) { + if (VIR_ALLOC(priv->callbackList)<0) { virReportOOMError(); goto failed; } - if(VIR_ALLOC(priv->domainEvents)<0) { + if (VIR_ALLOC(priv->domainEvents)<0) { virReportOOMError(); goto failed; } - DEBUG0("Adding Handler for remote events"); - /* Set up a callback to listen on the socket data */ - if ((priv->watch = virEventAddHandle(priv->sock, - VIR_EVENT_HANDLE_READABLE, - remoteDomainEventFired, - conn, NULL)) < 0) { - DEBUG0("virEventAddHandle failed: No addHandleImpl defined." - " continuing without events."); - } else { - - DEBUG0("Adding Timeout for remote event queue flushing"); - if ( (priv->eventFlushTimer = virEventAddTimeout(-1, - remoteDomainEventQueueFlush, - conn, NULL)) < 0) { - DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. " - "continuing without events."); - virEventRemoveHandle(priv->watch); - priv->watch = -1; - } + DEBUG0("Adding Timeout for remote event queue flushing"); + if ((priv->eventFlushTimer = virEventAddTimeout(-1, + remoteDomainEventQueueFlush, + conn, NULL)) < 0) { + DEBUG0("Failed to add timer for dispatching events, disabling events"); } + /* Successful. */ retcode = VIR_DRV_OPEN_SUCCESS; @@ -956,30 +666,8 @@ doRemoteOpen (virConnectPtr conn, free_qparam_set (vars); failed: - /* Close the socket if we failed. */ - VIR_FORCE_CLOSE(priv->errfd); - - if (priv->sock >= 0) { - if (priv->uses_tls && priv->session) { - gnutls_bye (priv->session, GNUTLS_SHUT_RDWR); - gnutls_deinit (priv->session); - } - VIR_FORCE_CLOSE(priv->sock); -#ifndef WIN32 - if (priv->pid > 0) { - pid_t reap; - do { -retry: - reap = waitpid(priv->pid, NULL, 0); - if (reap == -1 && errno == EINTR) - goto retry; - } while (reap != -1 && reap != priv->pid); - } -#endif - } - - VIR_FORCE_CLOSE(wakeupFD[0]); - VIR_FORCE_CLOSE(wakeupFD[1]); + virNetClientFree(priv->client); + priv->client = NULL; VIR_FREE(priv->hostname); goto cleanup; @@ -1003,8 +691,6 @@ remoteAllocPrivateData(void) remoteDriverLock(priv); priv->localUses = 1; priv->watch = -1; - priv->sock = -1; - priv->errfd = -1; return priv; } @@ -1116,435 +802,101 @@ get_transport_from_scheme (char *scheme) return p ? p+1 : 0; } -/* GnuTLS functions used by remoteOpen. */ -static gnutls_certificate_credentials_t x509_cred; - - -static int -check_cert_file(const char *type, const char *file) -{ - struct stat sb; - if (stat(file, &sb) < 0) { - virReportSystemError(errno, - _("Cannot access %s '%s'"), - type, file); - return -1; - } - return 0; -} - +/*----------------------------------------------------------------------*/ -static void remote_debug_gnutls_log(int level, const char* str) { - DEBUG("%d %s", level, str); -} static int -initialize_gnutls(void) +doRemoteClose (virConnectPtr conn, struct private_data *priv) { - static int initialized = 0; - int err; - char *gnutlsdebug; - - if (initialized) return 0; - - gnutls_global_init (); - - if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) { - int val; - if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0) - val = 10; - gnutls_global_set_log_level(val); - gnutls_global_set_log_function(remote_debug_gnutls_log); + /* Remove event dispatch timeout */ + if (priv->eventFlushTimer != -1) { + virEventRemoveTimeout(priv->eventFlushTimer); + priv->eventFlushTimer = -1; } - - /* X509 stuff */ - err = gnutls_certificate_allocate_credentials (&x509_cred); - if (err) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to allocate TLS credentials: %s"), - gnutls_strerror (err)); - return -1; + /* Remove handle for remote events */ + if (priv->watch != -1) { + virEventRemoveHandle(priv->watch); + priv->watch = -1; } - - if (check_cert_file("CA certificate", LIBVIRT_CACERT) < 0) - return -1; - if (check_cert_file("client key", LIBVIRT_CLIENTKEY) < 0) - return -1; - if (check_cert_file("client certificate", LIBVIRT_CLIENTCERT) < 0) + if (call (conn, priv, 0, REMOTE_PROC_CLOSE, + (xdrproc_t) xdr_void, (char *) NULL, + (xdrproc_t) xdr_void, (char *) NULL) == -1) return -1; - /* Set the trusted CA cert. */ - DEBUG("loading CA file %s", LIBVIRT_CACERT); - err = - gnutls_certificate_set_x509_trust_file (x509_cred, LIBVIRT_CACERT, - GNUTLS_X509_FMT_PEM); - if (err < 0) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to load CA certificate: %s"), - gnutls_strerror (err)); - return -1; - } + virNetTLSContextFree(priv->tls); + priv->tls = NULL; + virNetClientFree(priv->client); + priv->client = NULL; + virNetClientProgramFree(priv->remoteProgram); + virNetClientProgramFree(priv->qemuProgram); + priv->remoteProgram = priv->qemuProgram = NULL; - /* Set the client certificate and private key. */ - DEBUG("loading client cert and key from files %s and %s", - LIBVIRT_CLIENTCERT, LIBVIRT_CLIENTKEY); - err = - gnutls_certificate_set_x509_key_file (x509_cred, - LIBVIRT_CLIENTCERT, - LIBVIRT_CLIENTKEY, - GNUTLS_X509_FMT_PEM); - if (err < 0) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to load private key/certificate: %s"), - gnutls_strerror (err)); - return -1; - } + /* Free hostname copy */ + VIR_FREE(priv->hostname); - initialized = 1; - return 0; -} + /* See comment for remoteType. */ + VIR_FREE(priv->type); -static int verify_certificate (virConnectPtr conn, struct private_data *priv, gnutls_session_t session); + /* Free callback list */ + virDomainEventCallbackListFree(priv->callbackList); -#if HAVE_WINSOCK2_H -static ssize_t -custom_gnutls_push(void *s, const void *buf, size_t len) -{ - return send((size_t)s, buf, len, 0); -} + /* Free queued events */ + virDomainEventQueueFree(priv->domainEvents); -static ssize_t -custom_gnutls_pull(void *s, void *buf, size_t len) -{ - return recv((size_t)s, buf, len, 0); + return 0; } -#endif -static gnutls_session_t -negotiate_gnutls_on_connection (virConnectPtr conn, - struct private_data *priv, - int no_verify) +static int +remoteClose (virConnectPtr conn) { - const int cert_type_priority[3] = { - GNUTLS_CRT_X509, - GNUTLS_CRT_OPENPGP, - 0 - }; - int err; - gnutls_session_t session; - - /* Initialize TLS session - */ - err = gnutls_init (&session, GNUTLS_CLIENT); - if (err) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to initialize TLS client: %s"), - gnutls_strerror (err)); - return NULL; - } + int ret = 0; + struct private_data *priv = conn->privateData; - /* Use default priorities */ - err = gnutls_set_default_priority (session); - if (err) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to set TLS algorithm priority: %s"), - gnutls_strerror (err)); - return NULL; - } - err = - gnutls_certificate_type_set_priority (session, - cert_type_priority); - if (err) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to set certificate priority: %s"), - gnutls_strerror (err)); - return NULL; + remoteDriverLock(priv); + priv->localUses--; + if (!priv->localUses) { + ret = doRemoteClose(conn, priv); + conn->privateData = NULL; + remoteDriverUnlock(priv); + virMutexDestroy(&priv->lock); + VIR_FREE (priv); } + if (priv) + remoteDriverUnlock(priv); - /* put the x509 credentials to the current session - */ - err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred); - if (err) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to set session credentials: %s"), - gnutls_strerror (err)); - return NULL; - } + return ret; +} - gnutls_transport_set_ptr (session, - (gnutls_transport_ptr_t) (long) priv->sock); +static int +remoteSupportsFeature (virConnectPtr conn, int feature) +{ + int rv = -1; + remote_supports_feature_args args; + remote_supports_feature_ret ret; + struct private_data *priv = conn->privateData; -#if HAVE_WINSOCK2_H - /* Make sure GnuTLS uses gnulib's replacment functions for send() and - * recv() on Windows */ - gnutls_transport_set_push_function(session, custom_gnutls_push); - gnutls_transport_set_pull_function(session, custom_gnutls_pull); -#endif + remoteDriverLock(priv); - /* Perform the TLS handshake. */ - again: - err = gnutls_handshake (session); - if (err < 0) { - if (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED) - goto again; - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to complete TLS handshake: %s"), - gnutls_strerror (err)); - return NULL; + /* VIR_DRV_FEATURE_REMOTE* features are handled directly. */ + if (feature == VIR_DRV_FEATURE_REMOTE) { + rv = 1; + goto done; } - /* Verify certificate. */ - if (verify_certificate (conn, priv, session) == -1) { - DEBUG0("failed to verify peer's certificate"); - if (!no_verify) return NULL; - } + args.feature = feature; - /* At this point, the server is verifying _our_ certificate, IP address, - * etc. If we make the grade, it will send us a '\1' byte. - */ - char buf[1]; - int len; - again_2: - len = gnutls_record_recv (session, buf, 1); - if (len < 0 && len != GNUTLS_E_UNEXPECTED_PACKET_LENGTH) { - if (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED) - goto again_2; - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to complete TLS initialization: %s"), - gnutls_strerror (len)); - return NULL; - } - if (len != 1 || buf[0] != '\1') { - remoteError(VIR_ERR_RPC, "%s", - _("server verification (of our certificate or IP " - "address) failed")); - return NULL; - } + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_SUPPORTS_FEATURE, + (xdrproc_t) xdr_remote_supports_feature_args, (char *) &args, + (xdrproc_t) xdr_remote_supports_feature_ret, (char *) &ret) == -1) + goto done; -#if 0 - /* Print session info. */ - print_info (session); -#endif + rv = ret.supported; - return session; -} - -static int -verify_certificate (virConnectPtr conn ATTRIBUTE_UNUSED, - struct private_data *priv, - gnutls_session_t session) -{ - int ret; - unsigned int status; - const gnutls_datum_t *certs; - unsigned int nCerts, i; - time_t now; - - if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to verify server certificate: %s"), - gnutls_strerror (ret)); - return -1; - } - - if ((now = time(NULL)) == ((time_t)-1)) { - virReportSystemError(errno, "%s", - _("cannot get current time")); - return -1; - } - - if (status != 0) { - const char *reason = _("Invalid certificate"); - - if (status & GNUTLS_CERT_INVALID) - reason = _("The certificate is not trusted."); - - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) - reason = _("The certificate hasn't got a known issuer."); - - if (status & GNUTLS_CERT_REVOKED) - reason = _("The certificate has been revoked."); - -#ifndef GNUTLS_1_0_COMPAT - if (status & GNUTLS_CERT_INSECURE_ALGORITHM) - reason = _("The certificate uses an insecure algorithm"); -#endif - - remoteError(VIR_ERR_RPC, - _("server certificate failed validation: %s"), - reason); - return -1; - } - - if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) { - remoteError(VIR_ERR_RPC, "%s",_("Certificate type is not X.509")); - return -1; - } - - if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) { - remoteError(VIR_ERR_RPC, "%s",_("gnutls_certificate_get_peers failed")); - return -1; - } - - for (i = 0 ; i < nCerts ; i++) { - gnutls_x509_crt_t cert; - - ret = gnutls_x509_crt_init (&cert); - if (ret < 0) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to initialize certificate: %s"), - gnutls_strerror (ret)); - return -1; - } - - ret = gnutls_x509_crt_import (cert, &certs[i], GNUTLS_X509_FMT_DER); - if (ret < 0) { - remoteError(VIR_ERR_GNUTLS_ERROR, - _("unable to import certificate: %s"), - gnutls_strerror (ret)); - gnutls_x509_crt_deinit (cert); - return -1; - } - - if (gnutls_x509_crt_get_expiration_time (cert) < now) { - remoteError(VIR_ERR_RPC, "%s", _("The certificate has expired")); - gnutls_x509_crt_deinit (cert); - return -1; - } - - if (gnutls_x509_crt_get_activation_time (cert) > now) { - remoteError(VIR_ERR_RPC, "%s", - _("The certificate is not yet activated")); - gnutls_x509_crt_deinit (cert); - return -1; - } - - if (i == 0) { - if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) { - remoteError(VIR_ERR_RPC, - _("Certificate's owner does not match the hostname (%s)"), - priv->hostname); - gnutls_x509_crt_deinit (cert); - return -1; - } - } - } - - return 0; -} - -/*----------------------------------------------------------------------*/ - - -static int -doRemoteClose (virConnectPtr conn, struct private_data *priv) -{ - if (priv->eventFlushTimer >= 0) { - /* Remove timeout */ - virEventRemoveTimeout(priv->eventFlushTimer); - /* Remove handle for remote events */ - virEventRemoveHandle(priv->watch); - priv->watch = -1; - } - - if (call (conn, priv, 0, REMOTE_PROC_CLOSE, - (xdrproc_t) xdr_void, (char *) NULL, - (xdrproc_t) xdr_void, (char *) NULL) == -1) - return -1; - - /* Close socket. */ - if (priv->uses_tls && priv->session) { - gnutls_bye (priv->session, GNUTLS_SHUT_RDWR); - gnutls_deinit (priv->session); - } -#if HAVE_SASL - if (priv->saslconn) - sasl_dispose (&priv->saslconn); -#endif - VIR_FORCE_CLOSE(priv->sock); - VIR_FORCE_CLOSE(priv->errfd); - -#ifndef WIN32 - if (priv->pid > 0) { - pid_t reap; - do { -retry: - reap = waitpid(priv->pid, NULL, 0); - if (reap == -1 && errno == EINTR) - goto retry; - } while (reap != -1 && reap != priv->pid); - } -#endif - VIR_FORCE_CLOSE(priv->wakeupReadFD); - VIR_FORCE_CLOSE(priv->wakeupSendFD); - - - /* Free hostname copy */ - VIR_FREE(priv->hostname); - - /* See comment for remoteType. */ - VIR_FREE(priv->type); - - /* Free callback list */ - virDomainEventCallbackListFree(priv->callbackList); - - /* Free queued events */ - virDomainEventQueueFree(priv->domainEvents); - - return 0; -} - -static int -remoteClose (virConnectPtr conn) -{ - int ret = 0; - struct private_data *priv = conn->privateData; - - remoteDriverLock(priv); - priv->localUses--; - if (!priv->localUses) { - ret = doRemoteClose(conn, priv); - conn->privateData = NULL; - remoteDriverUnlock(priv); - virMutexDestroy(&priv->lock); - VIR_FREE (priv); - } - if (priv) - remoteDriverUnlock(priv); - - return ret; -} - -static int -remoteSupportsFeature (virConnectPtr conn, int feature) -{ - int rv = -1; - remote_supports_feature_args args; - remote_supports_feature_ret ret; - struct private_data *priv = conn->privateData; - - remoteDriverLock(priv); - - /* VIR_DRV_FEATURE_REMOTE* features are handled directly. */ - if (feature == VIR_DRV_FEATURE_REMOTE) { - rv = 1; - goto done; - } - - args.feature = feature; - - memset (&ret, 0, sizeof ret); - if (call (conn, priv, 0, REMOTE_PROC_SUPPORTS_FEATURE, - (xdrproc_t) xdr_remote_supports_feature_args, (char *) &args, - (xdrproc_t) xdr_remote_supports_feature_ret, (char *) &ret) == -1) - goto done; - - rv = ret.supported; - -done: - remoteDriverUnlock(priv); - return rv; +done: + remoteDriverUnlock(priv); + return rv; } /* Unfortunately this function is defined to return a static string. @@ -1696,13 +1048,8 @@ static int remoteIsEncrypted(virConnectPtr conn) (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1) goto done; - if (priv->uses_tls) - encrypted = 1; -#if HAVE_SASL - else if (priv->saslconn) + if (virNetClientIsEncrypted(priv->client)) encrypted = 1; -#endif - /* We claim to be encrypted, if the remote driver * transport itself is encrypted, and the remote @@ -6837,7 +6184,6 @@ done: static int remoteAuthenticate (virConnectPtr conn, struct private_data *priv, - int in_open ATTRIBUTE_UNUSED, virConnectAuthPtr auth ATTRIBUTE_UNUSED, const char *authtype) { @@ -6845,16 +6191,19 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, int err, type = REMOTE_AUTH_NONE; memset(&ret, 0, sizeof ret); - err = call (conn, priv, - REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC, + err = call (conn, priv, 0, REMOTE_PROC_AUTH_LIST, (xdrproc_t) xdr_void, (char *) NULL, (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret); - if (err == -2) /* Missing RPC - old server - ignore */ - return 0; - - if (err < 0) + if (err < 0) { + virErrorPtr verr = virGetLastError(); + if (verr && verr->code == VIR_ERR_NO_SUPPORT) { + /* Missing RPC - old server - ignore */ + virResetLastError(); + return 0; + } return -1; + } if (ret.types.types_len == 0) return 0; @@ -6893,7 +6242,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, STRCASEEQLEN(authtype, "sasl.", 5)) mech = authtype + 5; - if (remoteAuthSASL(conn, priv, in_open, auth, mech) < 0) { + if (remoteAuthSASL(conn, priv, auth, mech) < 0) { VIR_FREE(ret.types.types_val); return -1; } @@ -6903,7 +6252,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, #if HAVE_POLKIT case REMOTE_AUTH_POLKIT: - if (remoteAuthPolkit(conn, priv, in_open, auth) < 0) { + if (remoteAuthPolkit(conn, priv, auth) < 0) { VIR_FREE(ret.types.types_val); return -1; } @@ -7095,11 +6444,9 @@ static void remoteAuthFillInteract(virConnectCredentialPtr cred, /* Perform the SASL authentication process */ static int -remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, +remoteAuthSASL (virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth, const char *wantmech) { - sasl_conn_t *saslconn = NULL; - sasl_security_properties_t secprops; remote_auth_sasl_init_ret iret; remote_auth_sasl_start_args sargs; remote_auth_sasl_start_ret sret; @@ -7107,48 +6454,22 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, remote_auth_sasl_step_ret pret; const char *clientout; char *serverin = NULL; - unsigned int clientoutlen, serverinlen; + size_t clientoutlen, serverinlen; const char *mech; int err, complete; - virSocketAddr sa; - char *localAddr = NULL, *remoteAddr = NULL; - const void *val; - sasl_ssf_t ssf; + int ssf; sasl_callback_t *saslcb = NULL; sasl_interact_t *interact = NULL; virConnectCredentialPtr cred = NULL; int ncred = 0; int ret = -1; const char *mechlist; + virNetSASLContextPtr saslCtxt; + virNetSASLSessionPtr sasl; DEBUG0("Client initialize SASL authentication"); - /* Sets up the SASL library as a whole */ - err = sasl_client_init(NULL); - if (err != SASL_OK) { - remoteError(VIR_ERR_AUTH_FAILED, - _("failed to initialize SASL library: %d (%s)"), - err, sasl_errstring(err, NULL, NULL)); - goto cleanup; - } - - /* Get local address in form IPADDR:PORT */ - sa.len = sizeof(sa.data.stor); - if (getsockname(priv->sock, &sa.data.sa, &sa.len) < 0) { - virReportSystemError(errno, "%s", - _("failed to get sock address")); - goto cleanup; - } - if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL) - goto cleanup; - /* Get remote address in form IPADDR:PORT */ - sa.len = sizeof(sa.data.stor); - if (getpeername(priv->sock, &sa.data.sa, &sa.len) < 0) { - virReportSystemError(errno, "%s", - _("failed to get peer address")); - goto cleanup; - } - if ((remoteAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL) + if (!(saslCtxt = virNetSASLContextNewClient())) goto cleanup; if (auth) { @@ -7159,63 +6480,37 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, } /* Setup a handle for being a client */ - err = sasl_client_new("libvirt", - priv->hostname, - localAddr, - remoteAddr, - saslcb, - SASL_SUCCESS_DATA, - &saslconn); - - if (err != SASL_OK) { - remoteError(VIR_ERR_AUTH_FAILED, - _("Failed to create SASL client context: %d (%s)"), - err, sasl_errstring(err, NULL, NULL)); + if (!(sasl = virNetSASLSessionNewClient(saslCtxt, + "libvirt", + priv->hostname, + virNetClientLocalAddrString(priv->client), + virNetClientRemoteAddrString(priv->client), + saslcb))) goto cleanup; - } /* Initialize some connection props we care about */ - if (priv->uses_tls) { - gnutls_cipher_algorithm_t cipher; - - cipher = gnutls_cipher_get(priv->session); - if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) { - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("invalid cipher size for TLS session")); + if (priv->tls) { + if ((ssf = virNetClientGetTLSKeySize(priv->client)) < 0) goto cleanup; - } + ssf *= 8; /* key size is bytes, sasl wants bits */ DEBUG("Setting external SSF %d", ssf); - err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf); - if (err != SASL_OK) { - remoteError(VIR_ERR_INTERNAL_ERROR, - _("cannot set external SSF %d (%s)"), - err, sasl_errstring(err, NULL, NULL)); + if (virNetSASLSessionExtKeySize(sasl, ssf) < 0) goto cleanup; - } } - memset (&secprops, 0, sizeof secprops); /* If we've got a secure channel (TLS or UNIX sock), we don't care about SSF */ - secprops.min_ssf = priv->is_secure ? 0 : 56; /* Equiv to DES supported by all Kerberos */ - secprops.max_ssf = priv->is_secure ? 0 : 100000; /* Very strong ! AES == 256 */ - secprops.maxbufsize = 100000; /* If we're not secure, then forbid any anonymous or trivially crackable auth */ - secprops.security_flags = priv->is_secure ? 0 : - SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; - - err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops); - if (err != SASL_OK) { - remoteError(VIR_ERR_INTERNAL_ERROR, - _("cannot set security props %d (%s)"), - err, sasl_errstring(err, NULL, NULL)); + if (virNetSASLSessionSecProps(sasl, + priv->is_secure ? 0 : 56, /* Equiv to DES supported by all Kerberos */ + priv->is_secure ? 0 : 100000, /* Very strong ! AES == 256 */ + priv->is_secure ? true : false) < 0) goto cleanup; - } /* First call is to inquire about supported mechanisms in the server */ memset (&iret, 0, sizeof iret); - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_INIT, + if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_INIT, (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_remote_auth_sasl_init_ret, (char *) &iret) != 0) goto cleanup; @@ -7235,22 +6530,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, restart: /* Start the auth negotiation on the client end first */ DEBUG("Client start negotiation mechlist '%s'", mechlist); - err = sasl_client_start(saslconn, - mechlist, - &interact, - &clientout, - &clientoutlen, - &mech); - if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) { - remoteError(VIR_ERR_AUTH_FAILED, - _("Failed to start SASL negotiation: %d (%s)"), - err, sasl_errdetail(saslconn)); - VIR_FREE(iret.mechlist); + if ((err = virNetSASLSessionClientStart(sasl, + mechlist, + &interact, + &clientout, + &clientoutlen, + &mech)) < 0) goto cleanup; - } /* Need to gather some credentials from the client */ - if (err == SASL_INTERACT) { + if (err == VIR_NET_SASL_INTERACT) { const char *msg; if (cred) { remoteAuthFreeCredentials(cred, ncred); @@ -7280,7 +6569,7 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, if (clientoutlen > REMOTE_AUTH_SASL_DATA_MAX) { remoteError(VIR_ERR_AUTH_FAILED, _("SASL negotiation data too long: %d bytes"), - clientoutlen); + (int)clientoutlen); goto cleanup; } /* NB, distinction of NULL vs "" is *critical* in SASL */ @@ -7289,11 +6578,12 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, sargs.data.data_val = (char*)clientout; sargs.data.data_len = clientoutlen; sargs.mech = (char*)mech; - DEBUG("Server start negotiation with mech %s. Data %d bytes %p", mech, clientoutlen, clientout); + DEBUG("Server start negotiation with mech %s. Data %d bytes %p", + mech, (int)clientoutlen, clientout); /* Now send the initial auth data to the server */ memset (&sret, 0, sizeof sret); - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_START, + if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_START, (xdrproc_t) xdr_remote_auth_sasl_start_args, (char *) &sargs, (xdrproc_t) xdr_remote_auth_sasl_start_ret, (char *) &sret) != 0) goto cleanup; @@ -7303,27 +6593,23 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, serverin = sret.nil ? NULL : sret.data.data_val; serverinlen = sret.data.data_len; DEBUG("Client step result complete: %d. Data %d bytes %p", - complete, serverinlen, serverin); + complete, (int)serverinlen, serverin); /* Loop-the-loop... * Even if the server has completed, the client must *always* do at least one step * in this loop to verify the server isn't lying about something. Mutual auth */ for (;;) { restep: - err = sasl_client_step(saslconn, - serverin, - serverinlen, - &interact, - &clientout, - &clientoutlen); - if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT) { - remoteError(VIR_ERR_AUTH_FAILED, - _("Failed SASL step: %d (%s)"), - err, sasl_errdetail(saslconn)); + if ((err = virNetSASLSessionClientStep(sasl, + serverin, + serverinlen, + &interact, + &clientout, + &clientoutlen)) < 0) goto cleanup; - } + /* Need to gather some credentials from the client */ - if (err == SASL_INTERACT) { + if (err == VIR_NET_SASL_INTERACT) { const char *msg; if (cred) { remoteAuthFreeCredentials(cred, ncred); @@ -7349,10 +6635,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, } VIR_FREE(serverin); - DEBUG("Client step result %d. Data %d bytes %p", err, clientoutlen, clientout); + DEBUG("Client step result %d. Data %d bytes %p", + err, (int)clientoutlen, clientout); /* Previous server call showed completion & we're now locally complete too */ - if (complete && err == SASL_OK) + if (complete && err == VIR_NET_SASL_COMPLETE) break; /* Not done, prepare to talk with the server for another iteration */ @@ -7361,10 +6648,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, pargs.nil = clientout ? 0 : 1; pargs.data.data_val = (char*)clientout; pargs.data.data_len = clientoutlen; - DEBUG("Server step with %d bytes %p", clientoutlen, clientout); + DEBUG("Server step with %d bytes %p", + (int)clientoutlen, clientout); memset (&pret, 0, sizeof pret); - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_STEP, + if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_STEP, (xdrproc_t) xdr_remote_auth_sasl_step_args, (char *) &pargs, (xdrproc_t) xdr_remote_auth_sasl_step_ret, (char *) &pret) != 0) goto cleanup; @@ -7375,10 +6663,10 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, serverinlen = pret.data.data_len; DEBUG("Client step result complete: %d. Data %d bytes %p", - complete, serverinlen, serverin); + complete, (int)serverinlen, serverin); /* This server call shows complete, and earlier client step was OK */ - if (complete && err == SASL_OK) { + if (complete && err == VIR_NET_SASL_COMPLETE) { VIR_FREE(serverin); break; } @@ -7386,14 +6674,9 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, /* Check for suitable SSF if not already secure (TLS or UNIX sock) */ if (!priv->is_secure) { - err = sasl_getprop(saslconn, SASL_SSF, &val); - if (err != SASL_OK) { - remoteError(VIR_ERR_AUTH_FAILED, - _("cannot query SASL ssf on connection %d (%s)"), - err, sasl_errstring(err, NULL, NULL)); + if ((ssf = virNetSASLSessionGetKeySize(sasl)) < 0) goto cleanup; - } - ssf = *(const int *)val; + DEBUG("SASL SSF value %d", ssf); if (ssf < 56) { /* 56 == DES level, good for Kerberos */ remoteError(VIR_ERR_AUTH_FAILED, @@ -7404,18 +6687,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, } DEBUG0("SASL authentication complete"); - priv->saslconn = saslconn; + virNetClientSetSASLSession(priv->client, sasl); ret = 0; cleanup: - VIR_FREE(localAddr); - VIR_FREE(remoteAddr); VIR_FREE(serverin); VIR_FREE(saslcb); remoteAuthFreeCredentials(cred, ncred); - if (ret != 0 && saslconn) - sasl_dispose(&saslconn); + virNetSASLSessionFree(sasl); + virNetSASLContextFree(saslCtxt); return ret; } @@ -7425,14 +6706,14 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, #if HAVE_POLKIT # if HAVE_POLKIT1 static int -remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, +remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth ATTRIBUTE_UNUSED) { remote_auth_polkit_ret ret; DEBUG0("Client initialize PolicyKit-1 authentication"); memset (&ret, 0, sizeof ret); - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT, + if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT, (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) { return -1; /* virError already set by call */ @@ -7445,7 +6726,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, /* Perform the PolicyKit authentication process */ static int -remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, +remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, virConnectAuthPtr auth) { remote_auth_polkit_ret ret; @@ -7483,7 +6764,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, } memset (&ret, 0, sizeof ret); - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT, + if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT, (xdrproc_t) xdr_void, (char *)NULL, (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) { return -1; /* virError already set by call */ @@ -7568,184 +6849,187 @@ done: return rv; } + +static int remoteDomainEventQueuePush(struct private_data *priv, + virDomainEventPtr event) +{ + int ret = -1; + remoteDriverLock(priv); + + if (virDomainEventQueuePush(priv->domainEvents, + event) < 0) { + DEBUG0("Error adding event to queue"); + goto cleanup; + } + + ret = 0; + virEventUpdateTimeout(priv->eventFlushTimer, 0); + +cleanup: + remoteDriverUnlock(priv); + return ret; +} + + /** * remoteDomainReadEventLifecycle * * Read the domain lifecycle event data off the wire */ -static virDomainEventPtr -remoteDomainReadEventLifecycle(virConnectPtr conn, XDR *xdr) +static void +remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) { - remote_domain_event_lifecycle_msg msg; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_lifecycle_msg *msg = evdata; virDomainPtr dom; virDomainEventPtr event = NULL; - memset (&msg, 0, sizeof msg); - - /* unmarshall parameters, and process it*/ - if (! xdr_remote_domain_event_lifecycle_msg(xdr, &msg) ) { - remoteError(VIR_ERR_RPC, "%s", - _("unable to demarshall lifecycle event")); - return NULL; - } - dom = get_nonnull_domain(conn,msg.dom); + dom = get_nonnull_domain(conn, msg->dom); if (!dom) - return NULL; - - event = virDomainEventNewFromDom(dom, msg.event, msg.detail); - xdr_free ((xdrproc_t) &xdr_remote_domain_event_lifecycle_msg, (char *) &msg); + return; + event = virDomainEventNewFromDom(dom, msg->event, msg->detail); virDomainFree(dom); - return event; + + if (remoteDomainEventQueuePush(priv, event) < 0) + virDomainEventFree(event); } -static virDomainEventPtr -remoteDomainReadEventReboot(virConnectPtr conn, XDR *xdr) +static void +remoteDomainBuildEventReboot(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) { - remote_domain_event_reboot_msg msg; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_reboot_msg *msg = evdata; virDomainPtr dom; virDomainEventPtr event = NULL; - memset (&msg, 0, sizeof msg); - - /* unmarshall parameters, and process it*/ - if (! xdr_remote_domain_event_reboot_msg(xdr, &msg) ) { - remoteError(VIR_ERR_RPC, "%s", - _("unable to demarshall reboot event")); - return NULL; - } - dom = get_nonnull_domain(conn,msg.dom); + dom = get_nonnull_domain(conn, msg->dom); if (!dom) - return NULL; + return; event = virDomainEventRebootNewFromDom(dom); - xdr_free ((xdrproc_t) &xdr_remote_domain_event_reboot_msg, (char *) &msg); - virDomainFree(dom); - return event; + + if (remoteDomainEventQueuePush(priv, event) < 0) + virDomainEventFree(event); } -static virDomainEventPtr -remoteDomainReadEventRTCChange(virConnectPtr conn, XDR *xdr) +static void +remoteDomainBuildEventRTCChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) { - remote_domain_event_rtc_change_msg msg; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_rtc_change_msg *msg = evdata; virDomainPtr dom; virDomainEventPtr event = NULL; - memset (&msg, 0, sizeof msg); - - /* unmarshall parameters, and process it*/ - if (! xdr_remote_domain_event_rtc_change_msg(xdr, &msg) ) { - remoteError(VIR_ERR_RPC, "%s", - _("unable to demarshall reboot event")); - return NULL; - } - dom = get_nonnull_domain(conn,msg.dom); + dom = get_nonnull_domain(conn, msg->dom); if (!dom) - return NULL; - - event = virDomainEventRTCChangeNewFromDom(dom, msg.offset); - xdr_free ((xdrproc_t) &xdr_remote_domain_event_rtc_change_msg, (char *) &msg); + return; + event = virDomainEventRTCChangeNewFromDom(dom, msg->offset); virDomainFree(dom); - return event; + + if (remoteDomainEventQueuePush(priv, event) < 0) + virDomainEventFree(event); } -static virDomainEventPtr -remoteDomainReadEventWatchdog(virConnectPtr conn, XDR *xdr) +static void +remoteDomainBuildEventWatchdog(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) { - remote_domain_event_watchdog_msg msg; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_watchdog_msg *msg = evdata; virDomainPtr dom; virDomainEventPtr event = NULL; - memset (&msg, 0, sizeof msg); - - /* unmarshall parameters, and process it*/ - if (! xdr_remote_domain_event_watchdog_msg(xdr, &msg) ) { - remoteError(VIR_ERR_RPC, "%s", - _("unable to demarshall reboot event")); - return NULL; - } - dom = get_nonnull_domain(conn,msg.dom); + dom = get_nonnull_domain(conn, msg->dom); if (!dom) - return NULL; - - event = virDomainEventWatchdogNewFromDom(dom, msg.action); - xdr_free ((xdrproc_t) &xdr_remote_domain_event_watchdog_msg, (char *) &msg); + return; + event = virDomainEventWatchdogNewFromDom(dom, msg->action); virDomainFree(dom); - return event; + + if (remoteDomainEventQueuePush(priv, event) < 0) + virDomainEventFree(event); } -static virDomainEventPtr -remoteDomainReadEventIOError(virConnectPtr conn, XDR *xdr) +static void +remoteDomainBuildEventIOError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) { - remote_domain_event_io_error_msg msg; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_io_error_msg *msg = evdata; virDomainPtr dom; virDomainEventPtr event = NULL; - memset (&msg, 0, sizeof msg); - - /* unmarshall parameters, and process it*/ - if (! xdr_remote_domain_event_io_error_msg(xdr, &msg) ) { - remoteError(VIR_ERR_RPC, "%s", - _("unable to demarshall reboot event")); - return NULL; - } - dom = get_nonnull_domain(conn,msg.dom); + dom = get_nonnull_domain(conn, msg->dom); if (!dom) - return NULL; + return; event = virDomainEventIOErrorNewFromDom(dom, - msg.srcPath, - msg.devAlias, - msg.action); - xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_msg, (char *) &msg); - + msg->srcPath, + msg->devAlias, + msg->action); virDomainFree(dom); - return event; + + if (remoteDomainEventQueuePush(priv, event) < 0) + virDomainEventFree(event); } -static virDomainEventPtr -remoteDomainReadEventIOErrorReason(virConnectPtr conn, XDR *xdr) +static void +remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) { - remote_domain_event_io_error_reason_msg msg; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_io_error_reason_msg *msg = evdata; virDomainPtr dom; virDomainEventPtr event = NULL; - memset (&msg, 0, sizeof msg); - - /* unmarshall parameters, and process it*/ - if (! xdr_remote_domain_event_io_error_reason_msg(xdr, &msg) ) { - remoteError(VIR_ERR_RPC, "%s", - _("unable to demarshall reboot event")); - return NULL; - } - dom = get_nonnull_domain(conn,msg.dom); + dom = get_nonnull_domain(conn,msg->dom); if (!dom) - return NULL; + return; event = virDomainEventIOErrorReasonNewFromDom(dom, - msg.srcPath, - msg.devAlias, - msg.action, - msg.reason); - xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_reason_msg, (char *) &msg); + msg->srcPath, + msg->devAlias, + msg->action, + msg->reason); virDomainFree(dom); - return event; + + if (remoteDomainEventQueuePush(priv, event) < 0) + virDomainEventFree(event); } -static virDomainEventPtr -remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr) +static void +remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, + virNetClientPtr client ATTRIBUTE_UNUSED, + void *evdata, void *opaque) { - remote_domain_event_graphics_msg msg; + virConnectPtr conn = opaque; + struct private_data *priv = conn->privateData; + remote_domain_event_graphics_msg *msg = evdata; virDomainPtr dom; virDomainEventPtr event = NULL; virDomainEventGraphicsAddressPtr localAddr = NULL; @@ -7753,58 +7037,49 @@ remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr) virDomainEventGraphicsSubjectPtr subject = NULL; int i; - memset (&msg, 0, sizeof msg); - - /* unmarshall parameters, and process it*/ - if (! xdr_remote_domain_event_graphics_msg(xdr, &msg) ) { - remoteError(VIR_ERR_RPC, "%s", - _("unable to demarshall reboot event")); - return NULL; - } - - dom = get_nonnull_domain(conn,msg.dom); + dom = get_nonnull_domain(conn, msg->dom); if (!dom) - return NULL; + return; if (VIR_ALLOC(localAddr) < 0) goto no_memory; - localAddr->family = msg.local.family; - if (!(localAddr->service = strdup(msg.local.service)) || - !(localAddr->node = strdup(msg.local.node))) + localAddr->family = msg->local.family; + if (!(localAddr->service = strdup(msg->local.service)) || + !(localAddr->node = strdup(msg->local.node))) goto no_memory; if (VIR_ALLOC(remoteAddr) < 0) goto no_memory; - remoteAddr->family = msg.remote.family; - if (!(remoteAddr->service = strdup(msg.remote.service)) || - !(remoteAddr->node = strdup(msg.remote.node))) + remoteAddr->family = msg->remote.family; + if (!(remoteAddr->service = strdup(msg->remote.service)) || + !(remoteAddr->node = strdup(msg->remote.node))) goto no_memory; if (VIR_ALLOC(subject) < 0) goto no_memory; - if (VIR_ALLOC_N(subject->identities, msg.subject.subject_len) < 0) + if (VIR_ALLOC_N(subject->identities, msg->subject.subject_len) < 0) goto no_memory; - subject->nidentity = msg.subject.subject_len; + subject->nidentity = msg->subject.subject_len; for (i = 0 ; i < subject->nidentity ; i++) { - if (!(subject->identities[i].type = strdup(msg.subject.subject_val[i].type)) || - !(subject->identities[i].name = strdup(msg.subject.subject_val[i].name))) + if (!(subject->identities[i].type = strdup(msg->subject.subject_val[i].type)) || + !(subject->identities[i].name = strdup(msg->subject.subject_val[i].name))) goto no_memory; } event = virDomainEventGraphicsNewFromDom(dom, - msg.phase, + msg->phase, localAddr, remoteAddr, - msg.authScheme, + msg->authScheme, subject); - xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg); virDomainFree(dom); - return event; -no_memory: - xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg); + if (remoteDomainEventQueuePush(priv, event) < 0) + virDomainEventFree(event); + return; +no_memory: if (localAddr) { VIR_FREE(localAddr->service); VIR_FREE(localAddr->node); @@ -7823,7 +7098,7 @@ no_memory: VIR_FREE(subject->identities); VIR_FREE(subject); } - return NULL; + return; } @@ -8160,7 +7435,7 @@ done: return rv; } - +#if 0 static struct private_stream_data * remoteStreamOpen(virStreamPtr st, int output ATTRIBUTE_UNUSED, @@ -8707,7 +7982,7 @@ done: return rv; } - +#endif static int remoteCPUCompare(virConnectPtr conn, const char *xmlDesc, @@ -9239,7 +8514,7 @@ done: return rv; } - +#if 0 static int remoteDomainOpenConsole(virDomainPtr dom, const char *devname, @@ -9278,6 +8553,7 @@ done: return rv; } +#endif /*----------------------------------------------------------------------*/ @@ -9320,534 +8596,7 @@ done: return rv; } -/*----------------------------------------------------------------------*/ - -static struct remote_thread_call * -prepareCall(struct private_data *priv, - int flags, - int proc_nr, - xdrproc_t args_filter, char *args, - xdrproc_t ret_filter, char *ret) -{ - XDR xdr; - struct remote_message_header hdr; - struct remote_thread_call *rv; - - if (VIR_ALLOC(rv) < 0) { - virReportOOMError(); - return NULL; - } - - if (virCondInit(&rv->cond) < 0) { - VIR_FREE(rv); - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("cannot initialize mutex")); - return NULL; - } - - /* Get a unique serial number for this message. */ - rv->serial = priv->counter++; - rv->proc_nr = proc_nr; - rv->ret_filter = ret_filter; - rv->ret = ret; - rv->want_reply = 1; - - if (flags & REMOTE_CALL_QEMU) { - hdr.prog = QEMU_PROGRAM; - hdr.vers = QEMU_PROTOCOL_VERSION; - } - else { - hdr.prog = REMOTE_PROGRAM; - hdr.vers = REMOTE_PROTOCOL_VERSION; - } - hdr.proc = proc_nr; - hdr.type = REMOTE_CALL; - hdr.serial = rv->serial; - hdr.status = REMOTE_OK; - - /* Serialise header followed by args. */ - xdrmem_create (&xdr, rv->buffer+4, REMOTE_MESSAGE_MAX, XDR_ENCODE); - if (!xdr_remote_message_header (&xdr, &hdr)) { - remoteError(VIR_ERR_RPC, "%s", _("xdr_remote_message_header failed")); - goto error; - } - - if (!(*args_filter) (&xdr, args)) { - remoteError(VIR_ERR_RPC, "%s", _("marshalling args")); - goto error; - } - - /* Get the length stored in buffer. */ - rv->bufferLength = xdr_getpos (&xdr); - xdr_destroy (&xdr); - - /* Length must include the length word itself (always encoded in - * 4 bytes as per RFC 4506). - */ - rv->bufferLength += REMOTE_MESSAGE_HEADER_XDR_LEN; - - /* Encode the length word. */ - xdrmem_create (&xdr, rv->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE); - if (!xdr_u_int (&xdr, &rv->bufferLength)) { - remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word)")); - goto error; - } - xdr_destroy (&xdr); - - return rv; - -error: - xdr_destroy (&xdr); - VIR_FREE(rv); - return NULL; -} - - - -static int -remoteIOWriteBuffer(struct private_data *priv, - const char *bytes, int len) -{ - int ret; - - if (priv->uses_tls) { - tls_resend: - ret = gnutls_record_send (priv->session, bytes, len); - if (ret < 0) { - if (ret == GNUTLS_E_INTERRUPTED) - goto tls_resend; - if (ret == GNUTLS_E_AGAIN) - return 0; - - remoteError(VIR_ERR_GNUTLS_ERROR, "%s", gnutls_strerror (ret)); - return -1; - } - } else { - resend: - ret = send (priv->sock, bytes, len, 0); - if (ret == -1) { - if (errno == EINTR) - goto resend; - if (errno == EWOULDBLOCK) - return 0; - - virReportSystemError(errno, "%s", _("cannot send data")); - return -1; - - } - } - - return ret; -} - - -static int -remoteIOReadBuffer(struct private_data *priv, - char *bytes, int len) -{ - int ret; - - if (priv->uses_tls) { - tls_resend: - ret = gnutls_record_recv (priv->session, bytes, len); - if (ret == GNUTLS_E_INTERRUPTED) - goto tls_resend; - if (ret == GNUTLS_E_AGAIN) - return 0; - - /* Treat 0 == EOF as an error */ - if (ret <= 0) { - if (ret < 0) - remoteError(VIR_ERR_GNUTLS_ERROR, - _("failed to read from TLS socket %s"), - gnutls_strerror (ret)); - else - remoteError(VIR_ERR_SYSTEM_ERROR, "%s", - _("server closed connection")); - return -1; - } - } else { - resend: - ret = recv (priv->sock, bytes, len, 0); - if (ret <= 0) { - if (ret == -1) { - if (errno == EINTR) - goto resend; - if (errno == EWOULDBLOCK) - return 0; - - char errout[1024] = "\0"; - if (priv->errfd != -1) { - if (saferead(priv->errfd, errout, sizeof(errout)) < 0) { - virReportSystemError(errno, "%s", - _("cannot recv data")); - return -1; - } - } - - virReportSystemError(errno, - _("cannot recv data: %s"), errout); - - } else { - char errout[1024] = "\0"; - if (priv->errfd != -1) { - if (saferead(priv->errfd, errout, sizeof(errout)) < 0) { - remoteError(VIR_ERR_SYSTEM_ERROR, - _("server closed connection: %s"), - virStrerror(errno, errout, sizeof errout)); - return -1; - } - } - - remoteError(VIR_ERR_SYSTEM_ERROR, - _("server closed connection: %s"), errout); - } - return -1; - } - } - - return ret; -} - - -static int -remoteIOWriteMessage(struct private_data *priv, - struct remote_thread_call *thecall) -{ -#if HAVE_SASL - if (priv->saslconn) { - const char *output; - unsigned int outputlen; - int err, ret; - - if (!priv->saslEncoded) { - err = sasl_encode(priv->saslconn, - thecall->buffer + thecall->bufferOffset, - thecall->bufferLength - thecall->bufferOffset, - &output, &outputlen); - if (err != SASL_OK) { - remoteError(VIR_ERR_INTERNAL_ERROR, - _("failed to encode SASL data: %s"), - sasl_errstring(err, NULL, NULL)); - return -1; - } - priv->saslEncoded = output; - priv->saslEncodedLength = outputlen; - priv->saslEncodedOffset = 0; - - thecall->bufferOffset = thecall->bufferLength; - } - - ret = remoteIOWriteBuffer(priv, - priv->saslEncoded + priv->saslEncodedOffset, - priv->saslEncodedLength - priv->saslEncodedOffset); - if (ret < 0) - return ret; - priv->saslEncodedOffset += ret; - - if (priv->saslEncodedOffset == priv->saslEncodedLength) { - priv->saslEncoded = NULL; - priv->saslEncodedOffset = priv->saslEncodedLength = 0; - if (thecall->want_reply) - thecall->mode = REMOTE_MODE_WAIT_RX; - else - thecall->mode = REMOTE_MODE_COMPLETE; - } - } else { -#endif - int ret; - ret = remoteIOWriteBuffer(priv, - thecall->buffer + thecall->bufferOffset, - thecall->bufferLength - thecall->bufferOffset); - if (ret < 0) - return ret; - thecall->bufferOffset += ret; - - if (thecall->bufferOffset == thecall->bufferLength) { - thecall->bufferOffset = thecall->bufferLength = 0; - if (thecall->want_reply) - thecall->mode = REMOTE_MODE_WAIT_RX; - else - thecall->mode = REMOTE_MODE_COMPLETE; - } -#if HAVE_SASL - } -#endif - return 0; -} - - -static int -remoteIOHandleOutput(struct private_data *priv) { - struct remote_thread_call *thecall = priv->waitDispatch; - - while (thecall && - thecall->mode != REMOTE_MODE_WAIT_TX) - thecall = thecall->next; - - if (!thecall) - return -1; /* Shouldn't happen, but you never know... */ - - while (thecall) { - int ret = remoteIOWriteMessage(priv, thecall); - if (ret < 0) - return ret; - - if (thecall->mode == REMOTE_MODE_WAIT_TX) - return 0; /* Blocking write, to back to event loop */ - - thecall = thecall->next; - } - - return 0; /* No more calls to send, all done */ -} - -static int -remoteIOReadMessage(struct private_data *priv) { - unsigned int wantData; - - /* Start by reading length word */ - if (priv->bufferLength == 0) - priv->bufferLength = 4; - - wantData = priv->bufferLength - priv->bufferOffset; - -#if HAVE_SASL - if (priv->saslconn) { - if (priv->saslDecoded == NULL) { - char encoded[8192]; - int ret, err; - ret = remoteIOReadBuffer(priv, encoded, sizeof(encoded)); - if (ret < 0) - return -1; - if (ret == 0) - return 0; - - err = sasl_decode(priv->saslconn, encoded, ret, - &priv->saslDecoded, &priv->saslDecodedLength); - if (err != SASL_OK) { - remoteError(VIR_ERR_INTERNAL_ERROR, - _("failed to decode SASL data: %s"), - sasl_errstring(err, NULL, NULL)); - return -1; - } - priv->saslDecodedOffset = 0; - } - - if ((priv->saslDecodedLength - priv->saslDecodedOffset) < wantData) - wantData = (priv->saslDecodedLength - priv->saslDecodedOffset); - - memcpy(priv->buffer + priv->bufferOffset, - priv->saslDecoded + priv->saslDecodedOffset, - wantData); - priv->saslDecodedOffset += wantData; - priv->bufferOffset += wantData; - if (priv->saslDecodedOffset == priv->saslDecodedLength) { - priv->saslDecodedOffset = priv->saslDecodedLength = 0; - priv->saslDecoded = NULL; - } - - return wantData; - } else { -#endif - int ret; - - ret = remoteIOReadBuffer(priv, - priv->buffer + priv->bufferOffset, - wantData); - if (ret < 0) - return -1; - if (ret == 0) - return 0; - - priv->bufferOffset += ret; - - return ret; -#if HAVE_SASL - } -#endif -} - - -static int -remoteIODecodeMessageLength(struct private_data *priv) { - XDR xdr; - unsigned int len; - - xdrmem_create (&xdr, priv->buffer, priv->bufferLength, XDR_DECODE); - if (!xdr_u_int (&xdr, &len)) { - remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word, reply)")); - return -1; - } - xdr_destroy (&xdr); - - if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) { - remoteError(VIR_ERR_RPC, "%s", - _("packet received from server too small")); - return -1; - } - - /* Length includes length word - adjust to real length to read. */ - len -= REMOTE_MESSAGE_HEADER_XDR_LEN; - - if (len > REMOTE_MESSAGE_MAX) { - remoteError(VIR_ERR_RPC, "%s", - _("packet received from server too large")); - return -1; - } - - /* Extend our declared buffer length and carry - on reading the header + payload */ - priv->bufferLength += len; - DEBUG("Got length, now need %d total (%d more)", priv->bufferLength, len); - return 0; -} - - -static int -processCallDispatchReply(virConnectPtr conn, struct private_data *priv, - remote_message_header *hdr, - XDR *xdr); - -static int -processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, - int in_open, - remote_message_header *hdr, - XDR *xdr); - -static int -processCallDispatchStream(virConnectPtr conn, struct private_data *priv, - remote_message_header *hdr, - XDR *xdr); - - -static int -processCallDispatch(virConnectPtr conn, struct private_data *priv, - int flags) { - XDR xdr; - struct remote_message_header hdr; - int len = priv->bufferLength - 4; - int rv = -1; - int expectedprog; - int expectedvers; - - /* Length word has already been read */ - priv->bufferOffset = 4; - - /* Deserialise reply header. */ - xdrmem_create (&xdr, priv->buffer + priv->bufferOffset, len, XDR_DECODE); - if (!xdr_remote_message_header (&xdr, &hdr)) { - remoteError(VIR_ERR_RPC, "%s", _("invalid header in reply")); - return -1; - } - - priv->bufferOffset += xdr_getpos(&xdr); - - expectedprog = REMOTE_PROGRAM; - expectedvers = REMOTE_PROTOCOL_VERSION; - if (flags & REMOTE_CALL_QEMU) { - expectedprog = QEMU_PROGRAM; - expectedvers = QEMU_PROTOCOL_VERSION; - } - - /* Check program, version, etc. are what we expect. */ - if (hdr.prog != expectedprog) { - remoteError(VIR_ERR_RPC, - _("unknown program (received %x, expected %x)"), - hdr.prog, expectedprog); - return -1; - } - if (hdr.vers != expectedvers) { - remoteError(VIR_ERR_RPC, - _("unknown protocol version (received %x, expected %x)"), - hdr.vers, expectedvers); - return -1; - } - - - switch (hdr.type) { - case REMOTE_REPLY: /* Normal RPC replies */ - rv = processCallDispatchReply(conn, priv, &hdr, &xdr); - break; - - case REMOTE_MESSAGE: /* Async notifications */ - rv = processCallDispatchMessage(conn, priv, flags & REMOTE_CALL_IN_OPEN, - &hdr, &xdr); - break; - - case REMOTE_STREAM: /* Stream protocol */ - rv = processCallDispatchStream(conn, priv, &hdr, &xdr); - break; - - default: - remoteError(VIR_ERR_RPC, - _("got unexpected RPC call %d from server"), - hdr.proc); - rv = -1; - break; - } - - xdr_destroy(&xdr); - return rv; -} - - -static int -processCallDispatchReply(virConnectPtr conn ATTRIBUTE_UNUSED, - struct private_data *priv, - remote_message_header *hdr, - XDR *xdr) { - struct remote_thread_call *thecall; - - /* Ok, definitely got an RPC reply now find - out who's been waiting for it */ - thecall = priv->waitDispatch; - while (thecall && - thecall->serial != hdr->serial) - thecall = thecall->next; - - if (!thecall) { - remoteError(VIR_ERR_RPC, - _("no call waiting for reply with serial %d"), - hdr->serial); - return -1; - } - - if (hdr->proc != thecall->proc_nr) { - remoteError(VIR_ERR_RPC, - _("unknown procedure (received %x, expected %x)"), - hdr->proc, thecall->proc_nr); - return -1; - } - - /* Status is either REMOTE_OK (meaning that what follows is a ret - * structure), or REMOTE_ERROR (and what follows is a remote_error - * structure). - */ - switch (hdr->status) { - case REMOTE_OK: - if (!(*thecall->ret_filter) (xdr, thecall->ret)) { - remoteError(VIR_ERR_RPC, "%s", _("unmarshalling ret")); - return -1; - } - thecall->mode = REMOTE_MODE_COMPLETE; - return 0; - - case REMOTE_ERROR: - memset (&thecall->err, 0, sizeof thecall->err); - if (!xdr_remote_error (xdr, &thecall->err)) { - remoteError(VIR_ERR_RPC, "%s", _("unmarshalling remote_error")); - return -1; - } - thecall->mode = REMOTE_MODE_ERROR; - return 0; - - default: - remoteError(VIR_ERR_RPC, _("unknown status (received %x)"), hdr->status); - return -1; - } -} - +#if 0 static int processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, int in_open, @@ -9866,31 +8615,31 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, switch (hdr->proc) { case REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE: - event = remoteDomainReadEventLifecycle(conn, xdr); + event = remoteDomainBuildEventLifecycle(conn, xdr); break; case REMOTE_PROC_DOMAIN_EVENT_REBOOT: - event = remoteDomainReadEventReboot(conn, xdr); + event = remoteDomainBuildEventReboot(conn, xdr); break; case REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE: - event = remoteDomainReadEventRTCChange(conn, xdr); + event = remoteDomainBuildEventRTCChange(conn, xdr); break; case REMOTE_PROC_DOMAIN_EVENT_WATCHDOG: - event = remoteDomainReadEventWatchdog(conn, xdr); + event = remoteDomainBuildEventWatchdog(conn, xdr); break; case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR: - event = remoteDomainReadEventIOError(conn, xdr); + event = remoteDomainBuildEventIOError(conn, xdr); break; case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON: - event = remoteDomainReadEventIOErrorReason(conn, xdr); + event = remoteDomainBuildEventIOErrorReason(conn, xdr); break; case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS: - event = remoteDomainReadEventGraphics(conn, xdr); + event = remoteDomainBuildEventGraphics(conn, xdr); break; default: @@ -9901,16 +8650,11 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, if (!event) return -1; - if (virDomainEventQueuePush(priv->domainEvents, - event) < 0) { - DEBUG0("Error adding event to queue"); - virDomainEventFree(event); - } - virEventUpdateTimeout(priv->eventFlushTimer, 0); - return 0; } +#endif +#if 0 static int processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED, struct private_data *priv, @@ -10017,485 +8761,43 @@ processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED, return -1; } } - -static int -remoteIOHandleInput(virConnectPtr conn, struct private_data *priv, - int flags) -{ - /* Read as much data as is available, until we get - * EAGAIN - */ - for (;;) { - int ret = remoteIOReadMessage(priv); - - if (ret < 0) - return -1; - if (ret == 0) - return 0; /* Blocking on read */ - - /* Check for completion of our goal */ - if (priv->bufferOffset == priv->bufferLength) { - if (priv->bufferOffset == 4) { - ret = remoteIODecodeMessageLength(priv); - if (ret < 0) - return -1; - - /* - * We'll carry on around the loop to immediately - * process the message body, because it has probably - * already arrived. Worst case, we'll get EAGAIN on - * next iteration. - */ - } else { - ret = processCallDispatch(conn, priv, flags); - priv->bufferOffset = priv->bufferLength = 0; - /* - * We've completed one call, so return even - * though there might still be more data on - * the wire. We need to actually let the caller - * deal with this arrived message to keep good - * response, and also to correctly handle EOF. - */ - return ret; - } - } - } -} - -/* - * Process all calls pending dispatch/receive until we - * get a reply to our own call. Then quit and pass the buck - * to someone else. - */ -static int -remoteIOEventLoop(virConnectPtr conn, - struct private_data *priv, - int flags, - struct remote_thread_call *thiscall) -{ - struct pollfd fds[2]; - int ret; - - fds[0].fd = priv->sock; - fds[1].fd = priv->wakeupReadFD; - - for (;;) { - struct remote_thread_call *tmp = priv->waitDispatch; - struct remote_thread_call *prev; - char ignore; -#ifdef HAVE_PTHREAD_SIGMASK - sigset_t oldmask, blockedsigs; -#endif - - fds[0].events = fds[0].revents = 0; - fds[1].events = fds[1].revents = 0; - - fds[1].events = POLLIN; - while (tmp) { - if (tmp->mode == REMOTE_MODE_WAIT_RX) - fds[0].events |= POLLIN; - if (tmp->mode == REMOTE_MODE_WAIT_TX) - fds[0].events |= POLLOUT; - - tmp = tmp->next; - } - - if (priv->streams) - fds[0].events |= POLLIN; - - /* Release lock while poll'ing so other threads - * can stuff themselves on the queue */ - remoteDriverUnlock(priv); - - /* Block SIGWINCH from interrupting poll in curses programs, - * then restore the original signal mask again immediately - * after the call (RHBZ#567931). Same for SIGCHLD and SIGPIPE - * at the suggestion of Paolo Bonzini and Daniel Berrange. - */ -#ifdef HAVE_PTHREAD_SIGMASK - sigemptyset (&blockedsigs); - sigaddset (&blockedsigs, SIGWINCH); - sigaddset (&blockedsigs, SIGCHLD); - sigaddset (&blockedsigs, SIGPIPE); - ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask)); #endif - repoll: - ret = poll(fds, ARRAY_CARDINALITY(fds), -1); - if (ret < 0 && errno == EAGAIN) - goto repoll; - -#ifdef HAVE_PTHREAD_SIGMASK - ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL)); -#endif - - remoteDriverLock(priv); - - if (fds[1].revents) { - ssize_t s; - DEBUG0("Woken up from poll by other thread"); - s = saferead(priv->wakeupReadFD, &ignore, sizeof(ignore)); - if (s < 0) { - virReportSystemError(errno, "%s", - _("read on wakeup fd failed")); - goto error; - } else if (s != sizeof(ignore)) { - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("read on wakeup fd failed")); - goto error; - } - } - - if (ret < 0) { - if (errno == EWOULDBLOCK) - continue; - virReportSystemError(errno, - "%s", _("poll on socket failed")); - goto error; - } - - if (fds[0].revents & POLLOUT) { - if (remoteIOHandleOutput(priv) < 0) - goto error; - } - - if (fds[0].revents & POLLIN) { - if (remoteIOHandleInput(conn, priv, flags) < 0) - goto error; - } - - /* Iterate through waiting threads and if - * any are complete then tell 'em to wakeup - */ - tmp = priv->waitDispatch; - prev = NULL; - while (tmp) { - if (tmp != thiscall && - (tmp->mode == REMOTE_MODE_COMPLETE || - tmp->mode == REMOTE_MODE_ERROR)) { - /* Take them out of the list */ - if (prev) - prev->next = tmp->next; - else - priv->waitDispatch = tmp->next; - - /* And wake them up.... - * ...they won't actually wakeup until - * we release our mutex a short while - * later... - */ - DEBUG("Waking up sleep %d %p %p", tmp->proc_nr, tmp, priv->waitDispatch); - virCondSignal(&tmp->cond); - } - prev = tmp; - tmp = tmp->next; - } - - /* Now see if *we* are done */ - if (thiscall->mode == REMOTE_MODE_COMPLETE || - thiscall->mode == REMOTE_MODE_ERROR) { - /* We're at head of the list already, so - * remove us - */ - priv->waitDispatch = thiscall->next; - DEBUG("Giving up the buck %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch); - /* See if someone else is still waiting - * and if so, then pass the buck ! */ - if (priv->waitDispatch) { - DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch); - virCondSignal(&priv->waitDispatch->cond); - } - return 0; - } - - - if (fds[0].revents & (POLLHUP | POLLERR)) { - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("received hangup / error event on socket")); - goto error; - } - } - - -error: - priv->waitDispatch = thiscall->next; - DEBUG("Giving up the buck due to I/O error %d %p %p", thiscall->proc_nr, thiscall, priv->waitDispatch); - /* See if someone else is still waiting - * and if so, then pass the buck ! */ - if (priv->waitDispatch) { - DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr, priv->waitDispatch); - virCondSignal(&priv->waitDispatch->cond); - } - return -1; -} - -/* - * This function sends a message to remote server and awaits a reply - * - * NB. This does not free the args structure (not desirable, since you - * often want this allocated on the stack or else it contains strings - * which come from the user). It does however free any intermediate - * results, eg. the error structure if there is one. - * - * NB(2). Make sure to memset (&ret, 0, sizeof ret) before calling, - * else Bad Things will happen in the XDR code. - * - * NB(3) You must have the private_data lock before calling this - * - * NB(4) This is very complicated. Due to connection cloning, multiple - * threads can want to use the socket at once. Obviously only one of - * them can. So if someone's using the socket, other threads are put - * to sleep on condition variables. The existing thread may completely - * send & receive their RPC call/reply while they're asleep. Or it - * may only get around to dealing with sending the call. Or it may - * get around to neither. So upon waking up from slumber, the other - * thread may or may not have more work todo. - * - * We call this dance 'passing the buck' - * - * http://en.wikipedia.org/wiki/Passing_the_buck - * - * "Buck passing or passing the buck is the action of transferring - * responsibility or blame unto another person. It is also used as - * a strategy in power politics when the actions of one country/ - * nation are blamed on another, providing an opportunity for war." - * - * NB(5) Don't Panic! - */ -static int -remoteIO(virConnectPtr conn, - struct private_data *priv, - int flags, - struct remote_thread_call *thiscall) -{ - int rv; - - DEBUG("Do proc=%d serial=%d length=%d wait=%p", - thiscall->proc_nr, thiscall->serial, - thiscall->bufferLength, priv->waitDispatch); - - /* Check to see if another thread is dispatching */ - if (priv->waitDispatch) { - /* Stick ourselves on the end of the wait queue */ - struct remote_thread_call *tmp = priv->waitDispatch; - char ignore = 1; - ssize_t s; - while (tmp && tmp->next) - tmp = tmp->next; - if (tmp) - tmp->next = thiscall; - else - priv->waitDispatch = thiscall; - - /* Force other thread to wakeup from poll */ - s = safewrite(priv->wakeupSendFD, &ignore, sizeof(ignore)); - if (s < 0) { - char errout[1024]; - remoteError(VIR_ERR_INTERNAL_ERROR, - _("failed to wake up polling thread: %s"), - virStrerror(errno, errout, sizeof errout)); - return -1; - } else if (s != sizeof(ignore)) { - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to wake up polling thread")); - return -1; - } - - DEBUG("Going to sleep %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall); - /* Go to sleep while other thread is working... */ - if (virCondWait(&thiscall->cond, &priv->lock) < 0) { - if (priv->waitDispatch == thiscall) { - priv->waitDispatch = thiscall->next; - } else { - tmp = priv->waitDispatch; - while (tmp && tmp->next && - tmp->next != thiscall) { - tmp = tmp->next; - } - if (tmp && tmp->next == thiscall) - tmp->next = thiscall->next; - } - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to wait on condition")); - return -1; - } - - DEBUG("Wokeup from sleep %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall); - /* Two reasons we can be woken up - * 1. Other thread has got our reply ready for us - * 2. Other thread is all done, and it is our turn to - * be the dispatcher to finish waiting for - * our reply - */ - if (thiscall->mode == REMOTE_MODE_COMPLETE || - thiscall->mode == REMOTE_MODE_ERROR) { - /* - * We avoided catching the buck and our reply is ready ! - * We've already had 'thiscall' removed from the list - * so just need to (maybe) handle errors & free it - */ - goto cleanup; - } - - /* Grr, someone passed the buck onto us ... */ - - } else { - /* We're first to catch the buck */ - priv->waitDispatch = thiscall; - } - - DEBUG("We have the buck %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall); - /* - * The buck stops here! - * - * At this point we're about to own the dispatch - * process... - */ - - /* - * Avoid needless wake-ups of the event loop in the - * case where this call is being made from a different - * thread than the event loop. These wake-ups would - * cause the event loop thread to be blocked on the - * mutex for the duration of the call - */ - if (priv->watch >= 0) - virEventUpdateHandle(priv->watch, 0); - - rv = remoteIOEventLoop(conn, priv, flags, thiscall); - - if (priv->watch >= 0) - virEventUpdateHandle(priv->watch, VIR_EVENT_HANDLE_READABLE); - - if (rv < 0) - return -1; - -cleanup: - DEBUG("All done with our call %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall); - if (thiscall->mode == REMOTE_MODE_ERROR) { - /* See if caller asked us to keep quiet about missing RPCs - * eg for interop with older servers */ - if (flags & REMOTE_CALL_QUIET_MISSING_RPC && - thiscall->err.domain == VIR_FROM_REMOTE && - thiscall->err.code == VIR_ERR_RPC && - thiscall->err.level == VIR_ERR_ERROR && - thiscall->err.message && - STRPREFIX(*thiscall->err.message, "unknown procedure")) { - rv = -2; - } else if (thiscall->err.domain == VIR_FROM_REMOTE && - thiscall->err.code == VIR_ERR_RPC && - thiscall->err.level == VIR_ERR_ERROR && - thiscall->err.message && - STRPREFIX(*thiscall->err.message, "unknown procedure")) { - /* - * convert missing remote entry points into the unsupported - * feature error - */ - virRaiseErrorFull(flags & REMOTE_CALL_IN_OPEN ? NULL : conn, - __FILE__, __FUNCTION__, __LINE__, - thiscall->err.domain, - VIR_ERR_NO_SUPPORT, - thiscall->err.level, - thiscall->err.str1 ? *thiscall->err.str1 : NULL, - thiscall->err.str2 ? *thiscall->err.str2 : NULL, - thiscall->err.str3 ? *thiscall->err.str3 : NULL, - thiscall->err.int1, - thiscall->err.int2, - "%s", *thiscall->err.message); - rv = -1; - } else { - virRaiseErrorFull(flags & REMOTE_CALL_IN_OPEN ? NULL : conn, - __FILE__, __FUNCTION__, __LINE__, - thiscall->err.domain, - thiscall->err.code, - thiscall->err.level, - thiscall->err.str1 ? *thiscall->err.str1 : NULL, - thiscall->err.str2 ? *thiscall->err.str2 : NULL, - thiscall->err.str3 ? *thiscall->err.str3 : NULL, - thiscall->err.int1, - thiscall->err.int2, - "%s", thiscall->err.message ? *thiscall->err.message : "unknown"); - rv = -1; - } - xdr_free((xdrproc_t)xdr_remote_error, (char *)&thiscall->err); - } else { - rv = 0; - } - return rv; -} - /* * Serial a set of arguments into a method call message, * send that to the server and wait for reply */ static int -call (virConnectPtr conn, struct private_data *priv, +call (virConnectPtr conn ATTRIBUTE_UNUSED, + struct private_data *priv, int flags, int proc_nr, xdrproc_t args_filter, char *args, xdrproc_t ret_filter, char *ret) { - struct remote_thread_call *thiscall; int rv; + virNetClientProgramPtr prog = flags & REMOTE_CALL_QEMU ? priv->qemuProgram : priv->remoteProgram; + int counter = priv->counter++; + priv->localUses++; - thiscall = prepareCall(priv, flags, proc_nr, args_filter, args, - ret_filter, ret); - - if (!thiscall) { - virReportOOMError(); - return -1; - } - - rv = remoteIO(conn, priv, flags, thiscall); - VIR_FREE(thiscall); + /* Unlock, so that if we get any async events/stream data + * while processing the RPC, we don't deadlock when our + * callbacks for those are invoked + */ + remoteDriverUnlock(priv); + rv = virNetClientProgramCall(prog, + priv->client, + counter, + proc_nr, + args_filter, args, + ret_filter, ret); + remoteDriverLock(priv); + priv->localUses--; return rv; } -/** remoteDomainEventFired: - * - * The callback for monitoring the remote socket - * for event data - */ -void -remoteDomainEventFired(int watch, - int fd, - int event, - void *opaque) -{ - virConnectPtr conn = opaque; - struct private_data *priv = conn->privateData; - - remoteDriverLock(priv); - - /* This should be impossible, but it doesn't hurt to check */ - if (priv->waitDispatch) - goto done; - - DEBUG("Event fired %d %d %d %X", watch, fd, event, event); - - if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { - DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or " - "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__); - virEventRemoveHandle(watch); - priv->watch = -1; - goto done; - } - - if (fd != priv->sock) { - virEventRemoveHandle(watch); - priv->watch = -1; - goto done; - } - - if (remoteIOHandleInput(conn, priv, 0) < 0) - DEBUG0("Something went wrong during async message processing"); - -done: - remoteDriverUnlock(priv); -} - static void remoteDomainEventDispatchFunc(virConnectPtr conn, virDomainEventPtr event, virConnectDomainEventGenericCallback cb, @@ -10748,7 +9050,7 @@ static virDriver remote_driver = { remoteNodeDeviceDettach, /* nodeDeviceDettach */ remoteNodeDeviceReAttach, /* nodeDeviceReAttach */ remoteNodeDeviceReset, /* nodeDeviceReset */ - remoteDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */ + NULL, //remoteDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */ remoteIsEncrypted, /* isEncrypted */ remoteIsSecure, /* isSecure */ remoteDomainIsActive, /* domainIsActive */ @@ -10776,7 +9078,7 @@ static virDriver remote_driver = { remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ remoteDomainSetMemoryParameters, /* domainSetMemoryParameters */ remoteDomainGetMemoryParameters, /* domainGetMemoryParameters */ - remoteDomainOpenConsole, /* domainOpenConsole */ + NULL, //remoteDomainOpenConsole, /* domainOpenConsole */ }; static virNetworkDriver network_driver = { -- 1.7.2.3

At 12/16/2010 07:22 PM, Daniel P. Berrange Write:
This guts the current remote driver, removing all its networking handling code. Instead it calls out to the new virClientPtr and virClientProgramPtr APIs for all RPC & networking work. --- src/Makefile.am | 4 +- src/remote/remote_driver.c | 2596 ++++++++------------------------------------ 2 files changed, 451 insertions(+), 2149 deletions(-)
<snip>
+ case trans_ext: + if (!(priv->client = virNetClientNewExternal((const char **)cmd_argv))) + goto failed;
cmd_argv is NULL, we should do init it before calling virNetClientNewExternal():

The standard remote protocol for libvirtd no longer needs to include definitions of the generic message header/error structs or status codes. This is all defined in the generic RPC protocol * src/remote/remote_protocol.x: Remove all RPC message definitions * src/remote/remote_protocol.h, src/remote/remote_protocol.c: Re-generate * daemon/remote_generate_stubs.pl: Delete obsolete script --- src/remote/remote_protocol.c | 85 ------------------------------- src/remote/remote_protocol.h | 35 ------------- src/remote/remote_protocol.x | 114 ------------------------------------------ 3 files changed, 0 insertions(+), 234 deletions(-) diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 6e07b70..a88439c 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -3747,88 +3747,3 @@ xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) return FALSE; return TRUE; } - -bool_t -xdr_remote_message_type (XDR *xdrs, remote_message_type *objp) -{ - - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_remote_message_status (XDR *xdrs, remote_message_status *objp) -{ - - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_remote_message_header (XDR *xdrs, remote_message_header *objp) -{ - register int32_t *buf; - - - if (xdrs->x_op == XDR_ENCODE) { - buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_int (xdrs, &objp->prog)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->vers)) - return FALSE; - if (!xdr_int (xdrs, &objp->proc)) - return FALSE; - - } else { - (void)IXDR_PUT_U_INT32(buf, objp->prog); - (void)IXDR_PUT_U_INT32(buf, objp->vers); - (void)IXDR_PUT_INT32(buf, objp->proc); - } - if (!xdr_remote_message_type (xdrs, &objp->type)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->serial)) - return FALSE; - if (!xdr_remote_message_status (xdrs, &objp->status)) - return FALSE; - return TRUE; - } else if (xdrs->x_op == XDR_DECODE) { - buf = (int32_t*)XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); - if (buf == NULL) { - if (!xdr_u_int (xdrs, &objp->prog)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->vers)) - return FALSE; - if (!xdr_int (xdrs, &objp->proc)) - return FALSE; - - } else { - objp->prog = IXDR_GET_U_LONG(buf); - objp->vers = IXDR_GET_U_LONG(buf); - objp->proc = IXDR_GET_INT32(buf); - } - if (!xdr_remote_message_type (xdrs, &objp->type)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->serial)) - return FALSE; - if (!xdr_remote_message_status (xdrs, &objp->status)) - return FALSE; - return TRUE; - } - - if (!xdr_u_int (xdrs, &objp->prog)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->vers)) - return FALSE; - if (!xdr_int (xdrs, &objp->proc)) - return FALSE; - if (!xdr_remote_message_type (xdrs, &objp->type)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->serial)) - return FALSE; - if (!xdr_remote_message_status (xdrs, &objp->status)) - return FALSE; - return TRUE; -} diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index 4240963..bbff882 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -30,9 +30,6 @@ extern "C" { #ifndef IXDR_GET_U_INT32 # define IXDR_GET_U_INT32 IXDR_GET_U_LONG #endif -#define REMOTE_MESSAGE_MAX 262144 -#define REMOTE_MESSAGE_HEADER_MAX 24 -#define REMOTE_MESSAGE_PAYLOAD_MAX 262120 #define REMOTE_STRING_MAX 65536 typedef char *remote_nonnull_string; @@ -2323,32 +2320,6 @@ enum remote_procedure { }; typedef enum remote_procedure remote_procedure; -enum remote_message_type { - REMOTE_CALL = 0, - REMOTE_REPLY = 1, - REMOTE_MESSAGE = 2, - REMOTE_STREAM = 3, -}; -typedef enum remote_message_type remote_message_type; - -enum remote_message_status { - REMOTE_OK = 0, - REMOTE_ERROR = 1, - REMOTE_CONTINUE = 2, -}; -typedef enum remote_message_status remote_message_status; -#define REMOTE_MESSAGE_HEADER_XDR_LEN 4 - -struct remote_message_header { - u_int prog; - u_int vers; - int proc; - remote_message_type type; - u_int serial; - remote_message_status status; -}; -typedef struct remote_message_header remote_message_header; - /* the xdr functions */ #if defined(__STDC__) || defined(__cplusplus) @@ -2693,9 +2664,6 @@ extern bool_t xdr_remote_domain_revert_to_snapshot_args (XDR *, remote_domain_r extern bool_t xdr_remote_domain_snapshot_delete_args (XDR *, remote_domain_snapshot_delete_args*); extern bool_t xdr_remote_domain_open_console_args (XDR *, remote_domain_open_console_args*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); -extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); -extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); -extern bool_t xdr_remote_message_header (XDR *, remote_message_header*); #else /* K&R C */ extern bool_t xdr_remote_nonnull_string (); @@ -3039,9 +3007,6 @@ extern bool_t xdr_remote_domain_revert_to_snapshot_args (); extern bool_t xdr_remote_domain_snapshot_delete_args (); extern bool_t xdr_remote_domain_open_console_args (); extern bool_t xdr_remote_procedure (); -extern bool_t xdr_remote_message_type (); -extern bool_t xdr_remote_message_status (); -extern bool_t xdr_remote_message_header (); #endif /* K&R C */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index e1981fd..733a460 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -60,15 +60,6 @@ /*----- Data types. -----*/ -/* Maximum total message size (serialised). */ -const REMOTE_MESSAGE_MAX = 262144; - -/* Size of struct remote_message_header (serialized)*/ -const REMOTE_MESSAGE_HEADER_MAX = 24; - -/* Size of message payload */ -const REMOTE_MESSAGE_PAYLOAD_MAX = 262120; - /* Length of long, but not unbounded, strings. * This is an arbitrary limit designed to stop the decoder from trying * to allocate unbounded amounts of memory when fed with a bad message. @@ -2102,108 +2093,3 @@ enum remote_procedure { */ }; -/* - * RPC wire format - * - * Each message consists of: - * - * Name | Type | Description - * -----------+-----------------------+------------------ - * Length | int | Total number of bytes in message _including_ length. - * Header | remote_message_header | Control information about procedure call - * Payload | - | Variable payload data per procedure - * - * In header, the 'serial' field varies according to: - * - * - type == REMOTE_CALL - * * serial is set by client, incrementing by 1 each time - * - * - type == REMOTE_REPLY - * * serial matches that from the corresponding REMOTE_CALL - * - * - type == REMOTE_MESSAGE - * * serial is always zero - * - * - type == REMOTE_STREAM - * * serial matches that from the corresponding REMOTE_CALL - * - * and the 'status' field varies according to: - * - * - type == REMOTE_CALL - * * REMOTE_OK always - * - * - type == REMOTE_REPLY - * * REMOTE_OK if RPC finished successfully - * * REMOTE_ERROR if something failed - * - * - type == REMOTE_MESSAGE - * * REMOTE_OK always - * - * - type == REMOTE_STREAM - * * REMOTE_CONTINUE if more data is following - * * REMOTE_OK if stream is complete - * * REMOTE_ERROR if stream had an error - * - * Payload varies according to type and status: - * - * - type == REMOTE_CALL - * XXX_args for procedure - * - * - type == REMOTE_REPLY - * * status == REMOTE_OK - * XXX_ret for procedure - * * status == REMOTE_ERROR - * remote_error Error information - * - * - type == REMOTE_MESSAGE - * * status == REMOTE_OK - * XXX_args for procedure - * * status == REMOTE_ERROR - * remote_error Error information - * - * - type == REMOTE_STREAM - * * status == REMOTE_CONTINUE - * byte[] raw stream data - * * status == REMOTE_ERROR - * remote_error error information - * * status == REMOTE_OK - * <empty> - */ -enum remote_message_type { - /* client -> server. args from a method call */ - REMOTE_CALL = 0, - /* server -> client. reply/error from a method call */ - REMOTE_REPLY = 1, - /* either direction. async notification */ - REMOTE_MESSAGE = 2, - /* either direction. stream data packet */ - REMOTE_STREAM = 3 -}; - -enum remote_message_status { - /* Status is always REMOTE_OK for calls. - * For replies, indicates no error. - */ - REMOTE_OK = 0, - - /* For replies, indicates that an error happened, and a struct - * remote_error follows. - */ - REMOTE_ERROR = 1, - - /* For streams, indicates that more data is still expected - */ - REMOTE_CONTINUE = 2 -}; - -/* 4 byte length word per header */ -const REMOTE_MESSAGE_HEADER_XDR_LEN = 4; - -struct remote_message_header { - unsigned prog; /* REMOTE_PROGRAM */ - unsigned vers; /* REMOTE_PROTOCOL_VERSION */ - int proc; /* REMOTE_PROC_x */ - remote_message_type type; - unsigned serial; /* Serial number of message. */ - remote_message_status status; -}; -- 1.7.2.3

Move the existing rpcgen_fix.pl script to rpcgenprotocol.pl and adjust it so that the script runs 'rpcgen' itself via a pipe, avoiding the need for any intermediate files. * Makefile.am: Re-write RPC generator rules * remote/rpcgen_fix.pl -> rpc/genprotocol.pl * remote/qemu_protocol.h, remote/remote_protocol.h, rpc/virnetprotocol.h: Re-generate --- src/Makefile.am | 75 ++++++++------------------ src/remote/qemu_protocol.h | 6 +- src/remote/remote_protocol.h | 6 +- src/remote/rpcgen_fix.pl | 91 ------------------------------- src/rpc/genprotocol.pl | 124 ++++++++++++++++++++++++++++++++++++++++++ src/rpc/virnetprotocol.h | 6 +- 6 files changed, 156 insertions(+), 152 deletions(-) delete mode 100644 src/remote/rpcgen_fix.pl create mode 100644 src/rpc/genprotocol.pl diff --git a/src/Makefile.am b/src/Makefile.am index 334d535..178a274 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -160,8 +160,7 @@ REMOTE_DRIVER_SOURCES = \ remote/qemu_protocol.c \ remote/qemu_protocol.h -EXTRA_DIST += remote/remote_protocol.x remote/qemu_protocol.x \ - remote/rpcgen_fix.pl +EXTRA_DIST += remote/remote_protocol.x remote/qemu_protocol.x # Ensure that we don't change the struct or member names or member ordering # in remote_protocol.x The embedded perl below needs a few comments, and @@ -496,58 +495,29 @@ if HAVE_RPCGEN # non-Linux people needing to test changes during dev. # rpcgen-normal: - rm -f rp.c-t rp.h-t rp.c-t1 rp.c-t2 rp.h-t1 - $(RPCGEN) -h -o rp.h-t $(srcdir)/remote/remote_protocol.x - $(RPCGEN) -c -o rp.c-t $(srcdir)/remote/remote_protocol.x -if HAVE_GLIBC_RPCGEN - perl -w $(srcdir)/remote/rpcgen_fix.pl rp.h-t > rp.h-t1 - perl -w $(srcdir)/remote/rpcgen_fix.pl rp.c-t > rp.c-t1 - (echo '#include <config.h>'; cat rp.c-t1) > rp.c-t2 - chmod 0444 rp.c-t2 rp.h-t1 - mv -f rp.h-t1 $(srcdir)/remote/remote_protocol.h - mv -f rp.c-t2 $(srcdir)/remote/remote_protocol.c - rm -f rp.c-t rp.h-t rp.c-t1 -else - chmod 0444 rp.c-t rp.h-t - mv -f rp.h-t $(srcdir)/remote/remote_protocol.h - mv -f rp.c-t $(srcdir)/remote/remote_protocol.c -endif + $(AM_V_GEN)perl -w $(srcdir)/rpc/genprotocol.pl $(RPCGEN) -h \ + $(srcdir)/remote/remote_protocol.x \ + $(srcdir)/remote/remote_protocol.h + $(AM_V_GEN)perl -w $(srcdir)/rpc/genprotocol.pl $(RPCGEN) -c \ + $(srcdir)/remote/remote_protocol.x \ + $(srcdir)/remote/remote_protocol.c + rpcgen-qemu: - rm -f rp_qemu.c-t rp_qemu.h-t rp_qemu.c-t1 rp_qemu.c-t2 rp_qemu.h-t1 - $(RPCGEN) -h -o rp_qemu.h-t $(srcdir)/remote/qemu_protocol.x - $(RPCGEN) -c -o rp_qemu.c-t $(srcdir)/remote/qemu_protocol.x -if HAVE_GLIBC_RPCGEN - perl -w $(srcdir)/remote/rpcgen_fix.pl rp_qemu.h-t > rp_qemu.h-t1 - perl -w $(srcdir)/remote/rpcgen_fix.pl rp_qemu.c-t > rp_qemu.c-t1 - (echo '#include <config.h>'; cat rp_qemu.c-t1) > rp_qemu.c-t2 - chmod 0444 rp_qemu.c-t2 rp_qemu.h-t1 - mv -f rp_qemu.h-t1 $(srcdir)/remote/qemu_protocol.h - mv -f rp_qemu.c-t2 $(srcdir)/remote/qemu_protocol.c - rm -f rp_qemu.c-t rp_qemu.h-t rp_qemu.c-t1 -else - chmod 0444 rp_qemu.c-t rp_qemu.h-t - mv -f rp_qemu.h-t $(srcdir)/remote/qemu_protocol.h - mv -f rp_qemu.c-t $(srcdir)/remote/qemu_protocol.c -endif + $(AM_V_GEN)perl -w $(srcdir)/rpc/genprotocol.pl $(RPCGEN) -h \ + $(srcdir)/remote/qemu_protocol.x \ + $(srcdir)/remote/qemu_protocol.h + $(AM_V_GEN)perl -w $(srcdir)/rpc/genprotocol.pl $(RPCGEN) -c \ + $(srcdir)/remote/qemu_protocol.x \ + $(srcdir)/remote/qemu_protocol.c rpcgen-net: - rm -f rp_net.c-t rp_net.h-t rp_net.c-t1 rp_net.c-t2 rp_net.h-t1 - $(RPCGEN) -h -o rp_net.h-t $(srcdir)/rpc/virnetprotocol.x - $(RPCGEN) -c -o rp_net.c-t $(srcdir)/rpc/virnetprotocol.x -if HAVE_GLIBC_RPCGEN - perl -w $(srcdir)/remote/rpcgen_fix.pl rp_net.h-t > rp_net.h-t1 - perl -w $(srcdir)/remote/rpcgen_fix.pl rp_net.c-t > rp_net.c-t1 - (echo '#include <config.h>'; cat rp_net.c-t1) > rp_net.c-t2 - chmod 0444 rp_net.c-t2 rp_net.h-t1 - mv -f rp_net.h-t1 $(srcdir)/rpc/virnetprotocol.h - mv -f rp_net.c-t2 $(srcdir)/rpc/virnetprotocol.c - rm -f rp_net.c-t rp_net.h-t rp_net.c-t1 -else - chmod 0444 rp_net.c-t rp_net.h-t - mv -f rp_net.h-t $(srcdir)/rpc/virnetprotocol.h - mv -f rp_net.c-t $(srcdir)/rpc/virnetprotocol.c -endif + $(AM_V_GEN)perl -w $(srcdir)/rpc/genprotocol.pl $(RPCGEN) -h \ + $(srcdir)/rpc/virnetprotocol.x \ + $(srcdir)/rpc/virnetprotocol.h + $(AM_V_GEN)perl -w $(srcdir)/rpc/genprotocol.pl $(RPCGEN) -c \ + $(srcdir)/rpc/virnetprotocol.x \ + $(srcdir)/rpc/virnetprotocol.c # # Maintainer-only target for re-generating the derived .c/.h source @@ -1121,8 +1091,9 @@ EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) noinst_LTLIBRARIES += libvirt-net-rpc.la libvirt-net-rpc-server.la libvirt-net-rpc-client.la EXTRA_DIST += \ - rpc/virnetprotocol.x \ - rpc/gendispatch.pl + rpc/virnetprotocol.x \ + rpc/gendispatch.pl \ + rpc/genprotocol.pl libvirt_net_rpc_la_SOURCES = \ ../daemon/event.c \ diff --git a/src/remote/qemu_protocol.h b/src/remote/qemu_protocol.h index b822187..26f11fb 100644 --- a/src/remote/qemu_protocol.h +++ b/src/remote/qemu_protocol.h @@ -3,8 +3,8 @@ * It was generated using rpcgen. */ -#ifndef _RP_QEMU_H_RPCGEN -#define _RP_QEMU_H_RPCGEN +#ifndef _QEMU_PROTOCOL_H_RPCGEN +#define _QEMU_PROTOCOL_H_RPCGEN #include <rpc/rpc.h> @@ -54,4 +54,4 @@ extern bool_t xdr_qemu_procedure (); } #endif -#endif /* !_RP_QEMU_H_RPCGEN */ +#endif /* !_QEMU_PROTOCOL_H_RPCGEN */ diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index bbff882..7e9fd1c 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -3,8 +3,8 @@ * It was generated using rpcgen. */ -#ifndef _RP_H_RPCGEN -#define _RP_H_RPCGEN +#ifndef _REMOTE_PROTOCOL_H_RPCGEN +#define _REMOTE_PROTOCOL_H_RPCGEN #include <rpc/rpc.h> @@ -3014,4 +3014,4 @@ extern bool_t xdr_remote_procedure (); } #endif -#endif /* !_RP_H_RPCGEN */ +#endif /* !_REMOTE_PROTOCOL_H_RPCGEN */ diff --git a/src/remote/rpcgen_fix.pl b/src/remote/rpcgen_fix.pl deleted file mode 100644 index 3cf5479..0000000 --- a/src/remote/rpcgen_fix.pl +++ /dev/null @@ -1,91 +0,0 @@ -# Fix XDR code (generated by rpcgen) so that it compiles -# with warnings turned on. -# -# This code is evil. Arguably better would be just to compile -# without -Werror. Update: The IXDR_PUT_LONG replacements are -# actually fixes for 64 bit, so this file is necessary. Arguably -# so is the type-punning fix. -# -# Copyright (C) 2007 Red Hat, Inc. -# -# See COPYING for the license of this software. -# -# Richard Jones <rjones@redhat.com> - -use strict; - -my $in_function = 0; -my @function = (); - -while (<>) { - if (m/^{/) { - $in_function = 1; - print; - next; - } - - s/\t/ /g; - - # Portability for Solaris RPC - s/u_quad_t/uint64_t/g; - s/quad_t/int64_t/g; - s/xdr_u_quad_t/xdr_uint64_t/g; - s/xdr_quad_t/xdr_int64_t/g; - s/(?<!IXDR_GET_INT32 )IXDR_GET_LONG/IXDR_GET_INT32/g; - s,#include "\./remote/remote_protocol\.h",#include "remote_protocol.h",; - - if (m/^}/) { - $in_function = 0; - - # Note: The body of the function is in @function. - - # Remove decl of buf, if buf isn't used in the function. - my @uses = grep /\bbuf\b/, @function; - @function = grep !/\bbuf\b/, @function if @uses == 1; - - # Remove decl of i, if i isn't used in the function. - @uses = grep /\bi\b/, @function; - @function = grep !/\bi\b/, @function if @uses == 1; - - # (char **)&objp->... gives: - # warning: dereferencing type-punned pointer will break - # strict-aliasing rules - # so rewrite it. - my %uses = (); - my $i = 0; - foreach (@function) { - $uses{$1} = $i++ if m/\(char \*\*\)\&(objp->[a-z_.]+_val)/i; - } - if (keys %uses >= 1) { - my $i = 1; - - foreach (keys %uses) { - $i = $uses{$_}; - unshift @function, - (" char **objp_cpp$i = (char **) (void *) &$_;\n"); - $i++; - } - @function = - map { s{\(char \*\*\)\&(objp->[a-z_.]+_val)} - {objp_cpp$uses{$1}}gi; $_ } @function; - } - - # The code uses 'IXDR_PUT_{U_,}LONG' but it's wrong in two - # ways: Firstly these functions are deprecated and don't - # work on 64 bit platforms. Secondly the return value should - # be ignored. Correct both these mistakes. - @function = - map { s/\bIXDR_PUT_((U_)?)LONG\b/(void)IXDR_PUT_$1INT32/; $_ } - map { s/\bXDR_INLINE\b/(int32_t*)XDR_INLINE/; $_ } - @function; - - print (join ("", @function)); - @function = (); - } - - unless ($in_function) { - print; - } else { - push @function, $_; - } -} diff --git a/src/rpc/genprotocol.pl b/src/rpc/genprotocol.pl new file mode 100644 index 0000000..9144fe9 --- /dev/null +++ b/src/rpc/genprotocol.pl @@ -0,0 +1,124 @@ +# +# Generate code for an XDR protocol, optionally applying +# fixups to the glibc rpcgen code so that it compiles +# with warnings turned on. +# +# This code is evil. Arguably better would be just to compile +# without -Werror. Update: The IXDR_PUT_LONG replacements are +# actually fixes for 64 bit, so this file is necessary. Arguably +# so is the type-punning fix. +# +# Copyright (C) 2007 Red Hat, Inc. +# +# See COPYING for the license of this software. +# +# Richard Jones <rjones@redhat.com> + +use strict; + +my $in_function = 0; +my @function = (); + +my $rpcgen = shift; +my $mode = shift; +my $xdrdef = shift; +my $target = shift; + +unlink $target; + +open RPCGEN, "-|", $rpcgen, $mode, $xdrdef + or die "cannot run $rpcgen $mode $xdrdef: $!"; +open TARGET, ">$target" + or die "cannot create $target: $!"; + +my $fixup = $^O eq "linux"; + +if ($mode eq "-c") { + print TARGET "#include <config.h>\n"; +} + +while (<RPCGEN>) { + unless ($fixup) { + print TARGET; + next; + } + + if (m/^{/) { + $in_function = 1; + print TARGET; + next; + } + + s/\t/ /g; + + # Portability for Solaris RPC + s/u_quad_t/uint64_t/g; + s/quad_t/int64_t/g; + s/xdr_u_quad_t/xdr_uint64_t/g; + s/xdr_quad_t/xdr_int64_t/g; + s/(?<!IXDR_GET_INT32 )IXDR_GET_LONG/IXDR_GET_INT32/g; + s,#include "\./remote/remote_protocol\.h",#include "remote_protocol.h",; + + if (m/^}/) { + $in_function = 0; + + # Note: The body of the function is in @function. + + # Remove decl of buf, if buf isn't used in the function. + my @uses = grep /\bbuf\b/, @function; + @function = grep !/\bbuf\b/, @function if @uses == 1; + + # Remove decl of i, if i isn't used in the function. + @uses = grep /\bi\b/, @function; + @function = grep !/\bi\b/, @function if @uses == 1; + + # (char **)&objp->... gives: + # warning: dereferencing type-punned pointer will break + # strict-aliasing rules + # so rewrite it. + my %uses = (); + my $i = 0; + foreach (@function) { + $uses{$1} = $i++ if m/\(char \*\*\)\&(objp->[a-z_.]+_val)/i; + } + if (keys %uses >= 1) { + my $i = 1; + + foreach (keys %uses) { + $i = $uses{$_}; + unshift @function, + (" char **objp_cpp$i = (char **) (void *) &$_;\n"); + $i++; + } + @function = + map { s{\(char \*\*\)\&(objp->[a-z_.]+_val)} + {objp_cpp$uses{$1}}gi; $_ } @function; + } + + # The code uses 'IXDR_PUT_{U_,}LONG' but it's wrong in two + # ways: Firstly these functions are deprecated and don't + # work on 64 bit platforms. Secondly the return value should + # be ignored. Correct both these mistakes. + @function = + map { s/\bIXDR_PUT_((U_)?)LONG\b/(void)IXDR_PUT_$1INT32/; $_ } + map { s/\bXDR_INLINE\b/(int32_t*)XDR_INLINE/; $_ } + @function; + + print TARGET (join ("", @function)); + @function = (); + } + + unless ($in_function) { + print TARGET; + } else { + push @function, $_; + } +} + +close TARGET + or die "cannot save $target: $!"; +close RPCGEN + or die "cannot shutdown $rpcgen: $!"; + +chmod 0444, $target + or die "cannot set $target readonly: $!"; diff --git a/src/rpc/virnetprotocol.h b/src/rpc/virnetprotocol.h index 9f4a79a..9d0021c 100644 --- a/src/rpc/virnetprotocol.h +++ b/src/rpc/virnetprotocol.h @@ -3,8 +3,8 @@ * It was generated using rpcgen. */ -#ifndef _RP_NET_H_RPCGEN -#define _RP_NET_H_RPCGEN +#ifndef _VIRNETPROTOCOL_H_RPCGEN +#define _VIRNETPROTOCOL_H_RPCGEN #include <rpc/rpc.h> @@ -133,4 +133,4 @@ extern bool_t xdr_virNetMessageError (); } #endif -#endif /* !_RP_NET_H_RPCGEN */ +#endif /* !_VIRNETPROTOCOL_H_RPCGEN */ -- 1.7.2.3

Start of a trivial test case for the socket APIs. Only tests simple server setup & client connect for UNIX sockets so far * tests/Makefile.am: Add socket test * tests/virnetsockettest.c: New test case * tests/testutils.c: Avoid overriding LIBVIRT_DEBUG settings --- tests/.gitignore | 1 + tests/Makefile.am | 9 ++- tests/testutils.c | 8 ++- tests/virnetsockettest.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 tests/virnetsockettest.c diff --git a/tests/.gitignore b/tests/.gitignore index e3906f0..9c00860 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -30,6 +30,7 @@ statstest storagepoolxml2xmltest storagevolxml2xmltest virbuftest +virnetsockettest virshtest vmx2xmltest xencapstest diff --git a/tests/Makefile.am b/tests/Makefile.am index 0a235cf..ef78c34 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -74,7 +74,7 @@ EXTRA_DIST = \ check_PROGRAMS = virshtest conftest sockettest \ nodeinfotest qparamtest virbuftest \ - commandtest commandhelper + commandtest commandhelper virnetsockettest if WITH_XEN check_PROGRAMS += xml2sexprtest sexpr2xmltest \ @@ -159,6 +159,7 @@ TESTS = virshtest \ virbuftest \ sockettest \ commandtest \ + virnetsockettest \ $(test_scripts) if WITH_XEN @@ -361,6 +362,12 @@ commandhelper_SOURCES = \ commandhelper_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" commandhelper_LDADD = $(LDADDS) +virnetsockettest_SOURCES = \ + virnetsockettest.c testutils.h testutils.c +virnetsockettest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" +virnetsockettest_LDADD = $(LDADDS) + + if WITH_SECDRIVER_SELINUX seclabeltest_SOURCES = \ seclabeltest.c diff --git a/tests/testutils.c b/tests/testutils.c index 17584ac..ea1e5c6 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -481,9 +481,11 @@ int virtTestMain(int argc, return 1; virLogSetFromEnv(); - if (virLogDefineOutput(virtTestLogOutput, virtTestLogClose, &testLog, - 0, 0, NULL, 0) < 0) - return 1; + if (!getenv("LIBVIRT_DEBUG") && !virLogGetNbOutputs()) { + if (virLogDefineOutput(virtTestLogOutput, virtTestLogClose, &testLog, + 0, 0, NULL, 0) < 0) + return 1; + } #if TEST_OOM if ((oomStr = getenv("VIR_TEST_OOM")) != NULL) { diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c new file mode 100644 index 0000000..de3185f --- /dev/null +++ b/tests/virnetsockettest.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2006-2010 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <stdlib.h> +#include <signal.h> + +#include "testutils.h" +#include "util.h" +#include "virterror_internal.h" +#include "memory.h" +#include "logging.h" +#include "ignore-value.h" + +#include "rpc/virnetsocket.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +static char *argv0; +static char cwd[PATH_MAX]; + +static int testSocketUNIXAccept(const void *data ATTRIBUTE_UNUSED) +{ + virNetSocketPtr lsock = NULL; /* Listen socket */ + virNetSocketPtr ssock = NULL; /* Server socket */ + virNetSocketPtr csock = NULL; /* Client socket */ + int ret = -1; + + char *path; + if (virAsprintf(&path, "%s/%s-test.sock", cwd, argv0) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virNetSocketNewListenUNIX(path, 0700, getgid(), &lsock) < 0) + goto cleanup; + + if (virNetSocketListen(lsock) < 0) + goto cleanup; + + if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0) + goto cleanup; + + virNetSocketFree(csock); + + if (virNetSocketAccept(lsock, &ssock) != -1) { + char c; + if (virNetSocketWrite(ssock, &c, 1) != -1) { + VIR_DEBUG0("Unexpected client socket present"); + goto cleanup; + } + } + + + + ret = 0; + +cleanup: + VIR_FREE(path); + return ret; +} + + +static int testSocketUNIXAddrs(const void *data ATTRIBUTE_UNUSED) +{ + virNetSocketPtr lsock = NULL; /* Listen socket */ + virNetSocketPtr ssock = NULL; /* Server socket */ + virNetSocketPtr csock = NULL; /* Client socket */ + int ret = -1; + + char *path; + if (virAsprintf(&path, "%s/%s-test.sock", cwd, argv0) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virNetSocketNewListenUNIX(path, 0700, getgid(), &lsock) < 0) + goto cleanup; + + if (STRNEQ(virNetSocketLocalAddrString(lsock), "127.0.0.1;0")) { + VIR_DEBUG0("Unexpected local address"); + goto cleanup; + } + + if (virNetSocketRemoteAddrString(lsock) != NULL) { + VIR_DEBUG0("Unexpected remote address"); + goto cleanup; + } + + if (virNetSocketListen(lsock) < 0) + goto cleanup; + + if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0) + goto cleanup; + + if (STRNEQ(virNetSocketLocalAddrString(csock), "127.0.0.1;0")) { + VIR_DEBUG0("Unexpected local address"); + goto cleanup; + } + + if (STRNEQ(virNetSocketRemoteAddrString(csock), "127.0.0.1;0")) { + VIR_DEBUG0("Unexpected local address"); + goto cleanup; + } + + + if (virNetSocketAccept(lsock, &ssock) < 0) { + VIR_DEBUG0("Unexpected client socket missing"); + goto cleanup; + } + + + if (STRNEQ(virNetSocketLocalAddrString(ssock), "127.0.0.1;0")) { + VIR_DEBUG0("Unexpected local address"); + goto cleanup; + } + + if (STRNEQ(virNetSocketRemoteAddrString(ssock), "127.0.0.1;0")) { + VIR_DEBUG0("Unexpected local address"); + goto cleanup; + } + + + ret = 0; + +cleanup: + VIR_FREE(path); + return ret; +} + + +static int +mymain(int argc, char **argv) +{ + int ret = 0; + + argv0 = argv[0]; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", argv0); + return (EXIT_FAILURE); + } + + signal(SIGPIPE, SIG_IGN); + + if (!(getcwd(cwd, sizeof(cwd)))) + return (EXIT_FAILURE); + + if (virtTestRun("Socket UNIX Accept", 1, testSocketUNIXAccept, NULL) < 0) + ret = -1; + + if (virtTestRun("Socket UNIX Addrs", 1, testSocketUNIXAddrs, NULL) < 0) + ret = -1; + + return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +VIRT_TEST_MAIN(mymain) -- 1.7.2.3

Add a test case which validates the RPC message encoding & decoding to/from XDR representation. Covers the core message header, the error class and streams. * testutils.c, testutils.h: Helper for printing binary differences * virnetmessagetest.c: Validate all XDR encoding/decoding --- tests/.gitignore | 1 + tests/Makefile.am | 9 +- tests/testutils.c | 62 ++++++ tests/testutils.h | 4 + tests/virnetmessagetest.c | 509 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 584 insertions(+), 1 deletions(-) create mode 100644 tests/virnetmessagetest.c diff --git a/tests/.gitignore b/tests/.gitignore index 9c00860..9d80507 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -30,6 +30,7 @@ statstest storagepoolxml2xmltest storagevolxml2xmltest virbuftest +virnetmessagetest virnetsockettest virshtest vmx2xmltest diff --git a/tests/Makefile.am b/tests/Makefile.am index ef78c34..c45cc91 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -74,7 +74,8 @@ EXTRA_DIST = \ check_PROGRAMS = virshtest conftest sockettest \ nodeinfotest qparamtest virbuftest \ - commandtest commandhelper virnetsockettest + commandtest commandhelper virnetsockettest \ + virnetmessagetest if WITH_XEN check_PROGRAMS += xml2sexprtest sexpr2xmltest \ @@ -160,6 +161,7 @@ TESTS = virshtest \ sockettest \ commandtest \ virnetsockettest \ + virnetmessagetest \ $(test_scripts) if WITH_XEN @@ -367,6 +369,11 @@ virnetsockettest_SOURCES = \ virnetsockettest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" virnetsockettest_LDADD = $(LDADDS) +virnetmessagetest_SOURCES = \ + virnetmessagetest.c testutils.h testutils.c +virnetmessagetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" +virnetmessagetest_LDADD = $(LDADDS) + if WITH_SECDRIVER_SELINUX seclabeltest_SOURCES = \ diff --git a/tests/testutils.c b/tests/testutils.c index ea1e5c6..01956b2 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -360,6 +360,68 @@ int virtTestDifference(FILE *stream, return 0; } +/** + * @param stream: output stream write to differences to + * @param expect: expected output text + * @param actual: actual output text + * + * Display expected and actual output text, trimmed to + * first and last characters at which differences occur + */ +int virtTestDifferenceBin(FILE *stream, + const char *expect, + const char *actual, + size_t length) +{ + size_t start = 0, end = length; + ssize_t i; + + if (!virTestGetDebug()) + return 0; + + if (virTestGetDebug() < 2) { + /* Skip to first character where they differ */ + for (i = 0 ; i < length ; i++) { + if (expect[i] != actual[i]) { + start = i; + break; + } + } + + /* Work backwards to last character where they differ */ + for (i = (length -1) ; i >= 0 ; i--) { + if (expect[i] != actual[i]) { + end = i; + break; + } + } + } + /* Round to nearest boundary of 4 */ + start -= (start % 4); + end += 4 - (end % 4); + + /* Show the trimmed differences */ + fprintf(stream, "\nExpect [ Region %d-%d", (int)start, (int)end); + for (i = start; i < end ; i++) { + if ((i % 4) == 0) + fprintf(stream, "\n "); + fprintf(stream, "0x%02x, ", ((int)expect[i])&0xff); + } + fprintf(stream, "]\n"); + fprintf(stream, "Actual [ Region %d-%d", (int)start, (int)end); + for (i = start; i < end ; i++) { + if ((i % 4) == 0) + fprintf(stream, "\n "); + fprintf(stream, "0x%02x, ", ((int)actual[i])&0xff); + } + fprintf(stream, "]\n"); + + /* Pad to line up with test name ... in virTestRun */ + fprintf(stream, " ... "); + + return 0; +} + #if TEST_OOM static void virtTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED, diff --git a/tests/testutils.h b/tests/testutils.h index 88603a1..0a7321a 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -36,6 +36,10 @@ int virtTestClearLineRegex(const char *pattern, int virtTestDifference(FILE *stream, const char *expect, const char *actual); +int virtTestDifferenceBin(FILE *stream, + const char *expect, + const char *actual, + size_t length); unsigned int virTestGetDebug(void); unsigned int virTestGetVerbose(void); diff --git a/tests/virnetmessagetest.c b/tests/virnetmessagetest.c new file mode 100644 index 0000000..db40fb5 --- /dev/null +++ b/tests/virnetmessagetest.c @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2010 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: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <config.h> + +#include <stdlib.h> +#include <signal.h> + +#include "testutils.h" +#include "util.h" +#include "virterror_internal.h" +#include "memory.h" +#include "logging.h" +#include "ignore-value.h" + +#include "rpc/virnetmessage.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +static char *argv0; +static char cwd[PATH_MAX]; + +static int testMessageHeaderEncode(const void *args ATTRIBUTE_UNUSED) +{ + virNetMessage msg; + const char expect[] = { + 0x00, 0x00, 0x00, 0x1c, /* Length */ + 0x11, 0x22, 0x33, 0x44, /* Program */ + 0x00, 0x00, 0x00, 0x01, /* Version */ + 0x00, 0x00, 0x06, 0x66, /* Procedure */ + 0x00, 0x00, 0x00, 0x00, /* Type */ + 0x00, 0x00, 0x00, 0x99, /* Serial */ + 0x00, 0x00, 0x00, 0x00, /* Status */ + }; + memset(&msg, 0, sizeof(msg)); + + msg.header.prog = 0x11223344; + msg.header.vers = 0x01; + msg.header.proc = 0x666; + msg.header.type = VIR_NET_CALL; + msg.header.serial = 0x99; + msg.header.status = VIR_NET_OK; + + if (virNetMessageEncodeHeader(&msg) < 0) + return -1; + + if (ARRAY_CARDINALITY(expect) != msg.bufferOffset) { + VIR_DEBUG("Expect message offset %d got %d", + (int)sizeof(expect), msg.bufferOffset); + return -1; + } + + if (msg.bufferLength != sizeof(msg.buffer)) { + VIR_DEBUG("Expect message offset %d got %d", + (int)sizeof(msg.buffer), msg.bufferLength); + return -1; + } + + if (memcmp(expect, msg.buffer, sizeof(expect)) != 0) { + virtTestDifferenceBin(stderr, expect, msg.buffer, sizeof(expect)); + return -1; + } + + return 0; +} + +static int testMessageHeaderDecode(const void *args ATTRIBUTE_UNUSED) +{ + virNetMessage msg = { + .bufferOffset = 0, + .bufferLength = 0x4, + .buffer = { + 0x00, 0x00, 0x00, 0x1c, /* Length */ + 0x11, 0x22, 0x33, 0x44, /* Program */ + 0x00, 0x00, 0x00, 0x01, /* Version */ + 0x00, 0x00, 0x06, 0x66, /* Procedure */ + 0x00, 0x00, 0x00, 0x01, /* Type */ + 0x00, 0x00, 0x00, 0x99, /* Serial */ + 0x00, 0x00, 0x00, 0x01, /* Status */ + }, + .header = { 0, 0, 0, 0, 0, 0 }, + }; + + msg.header.prog = 0x11223344; + msg.header.vers = 0x01; + msg.header.proc = 0x666; + msg.header.type = VIR_NET_CALL; + msg.header.serial = 0x99; + msg.header.status = VIR_NET_OK; + + if (virNetMessageDecodeLength(&msg) < 0) { + VIR_DEBUG0("Failed to decode message header"); + return -1; + } + + if (msg.bufferOffset != 0x4) { + VIR_DEBUG("Expecting offset %d got %d", + 4, msg.bufferOffset); + return -1; + } + + if (msg.bufferLength != 0x1c) { + VIR_DEBUG("Expecting length %d got %d", + 0x1c, msg.bufferLength); + return -1; + } + + if (virNetMessageDecodeHeader(&msg) < 0) { + VIR_DEBUG0("Failed to decode message header"); + return -1; + } + + if (msg.bufferOffset != msg.bufferLength) { + VIR_DEBUG("Expect message offset %d got %d", + msg.bufferOffset, msg.bufferLength); + return -1; + } + + if (msg.header.prog != 0x11223344) { + VIR_DEBUG("Expect prog %d got %d", + 0x11223344, msg.header.prog); + return -1; + } + if (msg.header.vers != 0x1) { + VIR_DEBUG("Expect vers %d got %d", + 0x11223344, msg.header.vers); + return -1; + } + if (msg.header.proc != 0x666) { + VIR_DEBUG("Expect proc %d got %d", + 0x666, msg.header.proc); + return -1; + } + if (msg.header.type != VIR_NET_REPLY) { + VIR_DEBUG("Expect type %d got %d", + VIR_NET_REPLY, msg.header.type); + return -1; + } + if (msg.header.serial != 0x99) { + VIR_DEBUG("Expect serial %d got %d", + 0x99, msg.header.serial); + return -1; + } + if (msg.header.status != VIR_NET_ERROR) { + VIR_DEBUG("Expect status %d got %d", + VIR_NET_ERROR, msg.header.status); + return -1; + } + + return 0; +} + +static int testMessagePayloadEncode(const void *args ATTRIBUTE_UNUSED) +{ + virNetMessage msg; + virNetMessageError err; + const char expect[] = { + 0x00, 0x00, 0x00, 0x74, /* Length */ + 0x11, 0x22, 0x33, 0x44, /* Program */ + 0x00, 0x00, 0x00, 0x01, /* Version */ + 0x00, 0x00, 0x06, 0x66, /* Procedure */ + 0x00, 0x00, 0x00, 0x02, /* Type */ + 0x00, 0x00, 0x00, 0x99, /* Serial */ + 0x00, 0x00, 0x00, 0x01, /* Status */ + + 0x00, 0x00, 0x00, 0x01, /* Error code */ + 0x00, 0x00, 0x00, 0x07, /* Error domain */ + 0x00, 0x00, 0x00, 0x01, /* Error message pointer */ + 0x00, 0x00, 0x00, 0x0b, /* Error message length */ + 'H', 'e', 'l', 'l', /* Error message string */ + 'o', ' ', 'W', 'o', + 'r', 'l', 'd', '\0', + 0x00, 0x00, 0x00, 0x02, /* Error level */ + 0x00, 0x00, 0x00, 0x00, /* Error domain pointer */ + 0x00, 0x00, 0x00, 0x01, /* Error str1 pointer */ + 0x00, 0x00, 0x00, 0x03, /* Error str1 length */ + 'O', 'n', 'e', '\0', /* Error str1 message */ + 0x00, 0x00, 0x00, 0x01, /* Error str2 pointer */ + 0x00, 0x00, 0x00, 0x03, /* Error str2 length */ + 'T', 'w', 'o', '\0', /* Error str2 message */ + 0x00, 0x00, 0x00, 0x01, /* Error str3 pointer */ + 0x00, 0x00, 0x00, 0x05, /* Error str3 length */ + 'T', 'h', 'r', 'e', /* Error str3 message */ + 'e', '\0', '\0', '\0', + 0x00, 0x00, 0x00, 0x01, /* Error int1 */ + 0x00, 0x00, 0x00, 0x02, /* Error int2 */ + 0x00, 0x00, 0x00, 0x00, /* Error network pointer */ + }; + memset(&msg, 0, sizeof(msg)); + memset(&err, 0, sizeof(err)); + + err.code = VIR_ERR_INTERNAL_ERROR; + err.domain = VIR_FROM_RPC; + if (VIR_ALLOC(err.message) < 0) + return -1; + *err.message = strdup("Hello World"); + err.level = VIR_ERR_ERROR; + if (VIR_ALLOC(err.str1) < 0) + return -1; + *err.str1 = strdup("One"); + if (VIR_ALLOC(err.str2) < 0) + return -1; + *err.str2 = strdup("Two"); + if (VIR_ALLOC(err.str3) < 0) + return -1; + *err.str3 = strdup("Three"); + err.int1 = 1; + err.int2 = 2; + + msg.header.prog = 0x11223344; + msg.header.vers = 0x01; + msg.header.proc = 0x666; + msg.header.type = VIR_NET_MESSAGE; + msg.header.serial = 0x99; + msg.header.status = VIR_NET_ERROR; + + if (virNetMessageEncodeHeader(&msg) < 0) + return -1; + + if (virNetMessageEncodePayload(&msg, (xdrproc_t)xdr_virNetMessageError, &err) < 0) + return -1; + + if (ARRAY_CARDINALITY(expect) != msg.bufferLength) { + VIR_DEBUG("Expect message length %d got %d", + (int)sizeof(expect), msg.bufferLength); + return -1; + } + + if (msg.bufferOffset != 0) { + VIR_DEBUG("Expect message offset 0 got %d", + msg.bufferOffset); + return -1; + } + + if (memcmp(expect, msg.buffer, sizeof(expect)) != 0) { + virtTestDifferenceBin(stderr, expect, msg.buffer, sizeof(expect)); + return -1; + } + + return 0; +} + +static int testMessagePayloadDecode(const void *args ATTRIBUTE_UNUSED) +{ + virNetMessageError err; + virNetMessage msg = { + .bufferOffset = 0, + .bufferLength = 0x4, + .buffer = { + 0x00, 0x00, 0x00, 0x74, /* Length */ + 0x11, 0x22, 0x33, 0x44, /* Program */ + 0x00, 0x00, 0x00, 0x01, /* Version */ + 0x00, 0x00, 0x06, 0x66, /* Procedure */ + 0x00, 0x00, 0x00, 0x02, /* Type */ + 0x00, 0x00, 0x00, 0x99, /* Serial */ + 0x00, 0x00, 0x00, 0x01, /* Status */ + + 0x00, 0x00, 0x00, 0x01, /* Error code */ + 0x00, 0x00, 0x00, 0x07, /* Error domain */ + 0x00, 0x00, 0x00, 0x01, /* Error message pointer */ + 0x00, 0x00, 0x00, 0x0b, /* Error message length */ + 'H', 'e', 'l', 'l', /* Error message string */ + 'o', ' ', 'W', 'o', + 'r', 'l', 'd', '\0', + 0x00, 0x00, 0x00, 0x02, /* Error level */ + 0x00, 0x00, 0x00, 0x00, /* Error domain pointer */ + 0x00, 0x00, 0x00, 0x01, /* Error str1 pointer */ + 0x00, 0x00, 0x00, 0x03, /* Error str1 length */ + 'O', 'n', 'e', '\0', /* Error str1 message */ + 0x00, 0x00, 0x00, 0x01, /* Error str2 pointer */ + 0x00, 0x00, 0x00, 0x03, /* Error str2 length */ + 'T', 'w', 'o', '\0', /* Error str2 message */ + 0x00, 0x00, 0x00, 0x01, /* Error str3 pointer */ + 0x00, 0x00, 0x00, 0x05, /* Error str3 length */ + 'T', 'h', 'r', 'e', /* Error str3 message */ + 'e', '\0', '\0', '\0', + 0x00, 0x00, 0x00, 0x01, /* Error int1 */ + 0x00, 0x00, 0x00, 0x02, /* Error int2 */ + 0x00, 0x00, 0x00, 0x00, /* Error network pointer */ + }, + .header = { 0, 0, 0, 0, 0, 0 }, + }; + memset(&err, 0, sizeof(err)); + + if (virNetMessageDecodeLength(&msg) < 0) { + VIR_DEBUG0("Failed to decode message header"); + return -1; + } + + if (msg.bufferOffset != 0x4) { + VIR_DEBUG("Expecting offset %d got %d", + 4, msg.bufferOffset); + return -1; + } + + if (msg.bufferLength != 0x74) { + VIR_DEBUG("Expecting length %d got %d", + 0x74, msg.bufferLength); + return -1; + } + + if (virNetMessageDecodeHeader(&msg) < 0) { + VIR_DEBUG0("Failed to decode message header"); + return -1; + } + + if (msg.bufferOffset != 28) { + VIR_DEBUG("Expect message offset %d got %d", + msg.bufferOffset, 28); + return -1; + } + + if (msg.bufferLength != 0x74) { + VIR_DEBUG("Expecting length %d got %d", + 0x1c, msg.bufferLength); + return -1; + } + + if (virNetMessageDecodePayload(&msg, (xdrproc_t)xdr_virNetMessageError, &err) < 0) { + VIR_DEBUG0("Failed to decode message payload"); + return -1; + } + + if (err.code != VIR_ERR_INTERNAL_ERROR) { + VIR_DEBUG("Expect code %d got %d", + VIR_ERR_INTERNAL_ERROR, err.code); + return -1; + } + + if (err.domain != VIR_FROM_RPC) { + VIR_DEBUG("Expect domain %d got %d", + VIR_ERR_RPC, err.domain); + return -1; + } + + if (err.message == NULL || + STRNEQ(*err.message, "Hello World")) { + VIR_DEBUG("Expect str1 'Hello World' got %s", + err.message ? *err.message : "(null)"); + return -1; + } + + if (err.dom != NULL) { + VIR_DEBUG0("Expect NULL dom"); + return -1; + } + + if (err.level != VIR_ERR_ERROR) { + VIR_DEBUG("Expect leve %d got %d", + VIR_ERR_ERROR, err.level); + return -1; + } + + if (err.str1 == NULL || + STRNEQ(*err.str1, "One")) { + VIR_DEBUG("Expect str1 'One' got %s", + err.str1 ? *err.str1 : "(null)"); + return -1; + } + + if (err.str2 == NULL || + STRNEQ(*err.str2, "Two")) { + VIR_DEBUG("Expect str3 'Two' got %s", + err.str2 ? *err.str2 : "(null)"); + return -1; + } + + if (err.str3 == NULL || + STRNEQ(*err.str3, "Three")) { + VIR_DEBUG("Expect str3 'Three' got %s", + err.str3 ? *err.str3 : "(null)"); + return -1; + } + + if (err.int1 != 1) { + VIR_DEBUG("Expect int1 1 got %d", + err.int1); + return -1; + } + + if (err.int2 != 2) { + VIR_DEBUG("Expect int2 2 got %d", + err.int2); + return -1; + } + + if (err.net != NULL) { + VIR_DEBUG0("Expect NULL network"); + return -1; + } + + xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)&err); + return 0; +} + +static int testMessagePayloadStreamEncode(const void *args ATTRIBUTE_UNUSED) +{ + char stream[] = "The quick brown fox jumps over the lazy dog"; + virNetMessage msg; + const char expect[] = { + 0x00, 0x00, 0x00, 0x47, /* Length */ + 0x11, 0x22, 0x33, 0x44, /* Program */ + 0x00, 0x00, 0x00, 0x01, /* Version */ + 0x00, 0x00, 0x06, 0x66, /* Procedure */ + 0x00, 0x00, 0x00, 0x03, /* Type */ + 0x00, 0x00, 0x00, 0x99, /* Serial */ + 0x00, 0x00, 0x00, 0x02, /* Status */ + + 'T', 'h', 'e', ' ', + 'q', 'u', 'i', 'c', + 'k', ' ', 'b', 'r', + 'o', 'w', 'n', ' ', + 'f', 'o', 'x', ' ', + 'j', 'u', 'm', 'p', + 's', ' ', 'o', 'v', + 'e', 'r', ' ', 't', + 'h', 'e', ' ', 'l', + 'a', 'z', 'y', ' ', + 'd', 'o', 'g', + }; + memset(&msg, 0, sizeof(msg)); + + msg.header.prog = 0x11223344; + msg.header.vers = 0x01; + msg.header.proc = 0x666; + msg.header.type = VIR_NET_STREAM; + msg.header.serial = 0x99; + msg.header.status = VIR_NET_CONTINUE; + + if (virNetMessageEncodeHeader(&msg) < 0) + return -1; + + if (virNetMessageEncodePayloadRaw(&msg, stream, strlen(stream)) < 0) + return -1; + + if (ARRAY_CARDINALITY(expect) != msg.bufferLength) { + VIR_DEBUG("Expect message length %d got %d", + (int)sizeof(expect), msg.bufferLength); + return -1; + } + + if (msg.bufferOffset != 0) { + VIR_DEBUG("Expect message offset 0 got %d", + msg.bufferOffset); + return -1; + } + + if (memcmp(expect, msg.buffer, sizeof(expect)) != 0) { + virtTestDifferenceBin(stderr, expect, msg.buffer, sizeof(expect)); + return -1; + } + + return 0; +} + + +static int +mymain(int argc, char **argv) +{ + int ret = 0; + + argv0 = argv[0]; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", argv0); + return (EXIT_FAILURE); + } + + signal(SIGPIPE, SIG_IGN); + + if (!(getcwd(cwd, sizeof(cwd)))) + return (EXIT_FAILURE); + + if (virtTestRun("Message Header Encode", 1, testMessageHeaderEncode, NULL) < 0) + ret = -1; + + if (virtTestRun("Message Header Decode", 1, testMessageHeaderDecode, NULL) < 0) + ret = -1; + + if (virtTestRun("Message Payload Encode", 1, testMessagePayloadEncode, NULL) < 0) + ret = -1; + + if (virtTestRun("Message Payload Decode", 1, testMessagePayloadDecode, NULL) < 0) + ret = -1; + + if (virtTestRun("Message Payload Stream Encode", 1, testMessagePayloadStreamEncode, NULL) < 0) + ret = -1; + + return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +VIRT_TEST_MAIN(mymain) -- 1.7.2.3

On Thu, Dec 16, 2010 at 11:21:52AM +0000, Daniel P. Berrange wrote:
A followup to
http://www.redhat.com/archives/libvir-list/2010-December/msg00051.html
Since that time
- The SASL/TLS I/O code has been integrated into the virNetSocket class directly to remove duplication between client&servers - libvirtd has been converted to use the new APIs - Error handling has been sanitized across libvirtd to use the normal virReportError APIs - A couple of test cases have been written - Many locking, ref counting & ramdom crash bugs fixed - Some basic interoperability testing against previous code
This is still not quite functionally complete, so not ready to apply. The missing pieces are
- Make the client side streams code work again - Re-integrate DTrace probes in libvirtd
To save time, the patches are also available directly on my 'rpc' branch http://gitorious.org/~berrange/libvirt/staging/commits/rpc Daniel

On 12/16/2010 04:37 AM, Daniel P. Berrange wrote:
This is still not quite functionally complete, so not ready to apply. The missing pieces are
- Make the client side streams code work again - Re-integrate DTrace probes in libvirtd
To save time, the patches are also available directly on my 'rpc' branch
That's great for online browsing, but it took me a few minutes to figure out how to retrieve it for local browsing: git fetch git://gitorious.org/libvirt/libvirt/staging rpc -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

This guts the libvirtd daemon, removing all its networking and RPC handling code. Instead it calls out to the new virServerPtr APIs for all its RPC & networking work As a fallout all libvirtd daemon error reporting now takes place via the normal internal error reporting APIs. There is no need to call separate error reporting APIs in RPC code, nor should code use VIR_WARN/VIR_ERROR for reporting fatal problems anymore. NB, this mail has been edit to remove all the auto-generated code changes, to try & reduce the size somewhat. So none of the remote_dispatch* or qemu_dispatch* files remain. * daemon/qemu_dispatch_*.h, daemon/remote_dispatch_*.h: Remove old generated dispatcher code * daemon/qemu_dispatch.h, daemon/remote_dispatch.h: New dispatch code * daemon/dispatch.c, daemon/dispatch.h: Remove obsoleted code * daemon/remote.c, daemon/remote.h: Rewrite for new dispatch APIs * daemon/libvirtd.c, daemon/libvirtd.h: Remove all networking code * daemon/stream.c, daemon/stream.h: Update for new APIs * daemon/Makefile.am: Link to libvirt-net-rpc-server.la --- daemon/Makefile.am | 59 +- daemon/dispatch.c | 707 ----- daemon/dispatch.h | 70 - daemon/libvirtd.c | 2993 +++++---------------- daemon/libvirtd.h | 246 +-- daemon/qemu_dispatch.h | 58 + daemon/qemu_dispatch_args.h | 5 - daemon/qemu_dispatch_prototypes.h | 12 - daemon/qemu_dispatch_ret.h | 5 - daemon/qemu_dispatch_table.h | 14 - daemon/remote.c | 3802 +++++++++++---------------- daemon/remote.h | 64 +- daemon/remote_dispatch.h | 5073 +++++++++++++++++++++++++++++++++++ daemon/remote_dispatch_args.h | 173 -- daemon/remote_dispatch_prototypes.h | 1564 ----------- daemon/remote_dispatch_ret.h | 140 - daemon/remote_dispatch_table.h | 1019 ------- daemon/remote_generate_stubs.pl | 195 -- daemon/stream.c | 479 ++-- daemon/stream.h | 28 +- po/POTFILES.in | 1 - 21 files changed, 7567 insertions(+), 9140 deletions(-) delete mode 100644 daemon/dispatch.c delete mode 100644 daemon/dispatch.h create mode 100644 daemon/qemu_dispatch.h delete mode 100644 daemon/qemu_dispatch_args.h delete mode 100644 daemon/qemu_dispatch_prototypes.h delete mode 100644 daemon/qemu_dispatch_ret.h delete mode 100644 daemon/qemu_dispatch_table.h create mode 100644 daemon/remote_dispatch.h delete mode 100644 daemon/remote_dispatch_args.h delete mode 100644 daemon/remote_dispatch_prototypes.h delete mode 100644 daemon/remote_dispatch_ret.h delete mode 100644 daemon/remote_dispatch_table.h delete mode 100755 daemon/remote_generate_stubs.pl diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 72778e5..5acb3f8 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -3,19 +3,11 @@ CLEANFILES = DAEMON_SOURCES = \ - event.c event.h \ libvirtd.c libvirtd.h \ - remote.c remote.h \ - dispatch.c dispatch.h \ stream.c stream.h \ - remote_dispatch_prototypes.h \ - remote_dispatch_table.h \ - remote_dispatch_args.h \ - remote_dispatch_ret.h \ - qemu_dispatch_prototypes.h \ - qemu_dispatch_table.h \ - qemu_dispatch_args.h \ - qemu_dispatch_ret.h \ + remote.c remote.h \ + remote_dispatch.h \ + qemu_dispatch.h \ ../src/remote/remote_protocol.c \ ../src/remote/qemu_protocol.c @@ -24,7 +16,6 @@ AVAHI_SOURCES = \ DISTCLEANFILES = EXTRA_DIST = \ - remote_generate_stubs.pl \ libvirtd.conf \ libvirtd.init.in \ libvirtd.policy-0 \ @@ -82,6 +73,7 @@ libvirtd_CFLAGS = \ -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) \ $(POLKIT_CFLAGS) \ @@ -100,7 +92,10 @@ libvirtd_LDADD = \ $(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 @@ -206,43 +201,17 @@ endif remote.c: \ - remote_dispatch_prototypes.h \ - remote_dispatch_table.h \ - qemu_dispatch_prototypes.h \ - qemu_dispatch_table.h - -remote.h: \ - remote_dispatch_args.h \ - remote_dispatch_ret.h \ - qemu_dispatch_args.h \ - qemu_dispatch_ret.h + remote_dispatch.h \ + qemu_dispatch.h REMOTE_PROTOCOL = $(top_srcdir)/src/remote/remote_protocol.x QEMU_PROTOCOL = $(top_srcdir)/src/remote/qemu_protocol.x -remote_dispatch_prototypes.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -p remote $(REMOTE_PROTOCOL) > $@ - -remote_dispatch_table.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -t remote $(REMOTE_PROTOCOL) > $@ - -remote_dispatch_args.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -a remote $(REMOTE_PROTOCOL) > $@ - -remote_dispatch_ret.h: $(srcdir)/remote_generate_stubs.pl $(REMOTE_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -c -r remote $(REMOTE_PROTOCOL) > $@ - -qemu_dispatch_prototypes.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -p qemu $(QEMU_PROTOCOL) > $@ - -qemu_dispatch_table.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -t qemu $(QEMU_PROTOCOL) > $@ - -qemu_dispatch_args.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -a qemu $(QEMU_PROTOCOL) > $@ +remote_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl $(REMOTE_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl -c remote $(REMOTE_PROTOCOL) > $@ -qemu_dispatch_ret.h: $(srcdir)/remote_generate_stubs.pl $(QEMU_PROTOCOL) - $(AM_V_GEN)perl -w $(srcdir)/remote_generate_stubs.pl -r qemu $(QEMU_PROTOCOL) > $@ +qemu_dispatch.h: $(srcdir)/../src/rpc/gendispatch.pl $(QEMU_PROTOCOL) + $(AM_V_GEN)perl -w $(srcdir)/../src/rpc/gendispatch.pl qemu $(QEMU_PROTOCOL) > $@ LOGROTATE_CONFS = libvirtd.qemu.logrotate libvirtd.lxc.logrotate \ libvirtd.uml.logrotate diff --git a/daemon/dispatch.c b/daemon/dispatch.c deleted file mode 100644 index bf2ac73..0000000 --- a/daemon/dispatch.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * 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 <stdbool.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 remoteDispatchOOMError (remote_error *rerr) -{ - remoteDispatchStringError(rerr, - VIR_ERR_NO_MEMORY, - "out of memory"); -} - - -void remoteDispatchConnError (remote_error *rerr, - virConnectPtr conn) -{ - virErrorPtr verr; - - if (conn) - verr = virConnGetLastError(conn); - else - 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; - - 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; - - 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; - - 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); - - 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; -} diff --git a/daemon/dispatch.h b/daemon/dispatch.h deleted file mode 100644 index 85f8fc3..0000000 --- a/daemon/dispatch.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 remoteDispatchOOMError (remote_error *rerr); -void remoteDispatchConnError (remote_error *rerr, - virConnectPtr conn); - - -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__ */ diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 2df9337..0203588 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -23,31 +23,13 @@ #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" #include "virterror_internal.h" @@ -56,16 +38,20 @@ #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.h" +#include "files.h" +#include "virterror_internal.h" +#include "logging.h" #include "memory.h" -#include "stream.h" +#include "conf.h" +#include "virnetserver.h" +#include "threads.h" +#include "remote.h" +#include "remote_driver.h" +//#include "stream.h" #include "hooks.h" +#include "uuid.h" #include "virtaudit.h" #ifdef HAVE_AVAHI # include "mdns.h" @@ -106,100 +92,57 @@ # 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; -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, @@ -229,194 +172,9 @@ VIR_ENUM_IMPL(virDaemonErr, VIR_DAEMON_ERR_LAST, "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 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; - - /* Initialise GnuTLS. */ - gnutls_global_init (); - - 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; - - qemudDebug ("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; - - 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; - 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_INFO0(_("Reloading configuration on SIGHUP")); - virHookCall(VIR_HOOK_DRIVER_DAEMON, "-", - VIR_HOOK_DAEMON_OP_RELOAD, SIGHUP, "SIGHUP", NULL); - if (virStateReload() < 0) - VIR_WARN0("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; @@ -501,7 +259,8 @@ static int daemonForkIntoBackground(void) { } } -static int qemudWritePidFile(const char *pidFile) { +static int daemonWritePidFile(const char *pidFile, const char *argv0) +{ int fd; FILE *fh; char ebuf[1024]; @@ -538,325 +297,84 @@ static int qemudWritePidFile(const char *pidFile) { return 0; } -static int qemudListenUnix(struct qemud_server *server, - char *path, int readonly, int auth) { - struct qemud_socket *sock; - mode_t oldmask; - gid_t oldgrp; - char ebuf[1024]; - - if (VIR_ALLOC(sock) < 0) { - VIR_ERROR0(_("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'; - - oldgrp = getgid(); - oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask); - if (server->privileged && setgid(unix_sock_gid)) { - VIR_ERROR(_("Failed to set group ID to %d"), unix_sock_gid); - goto cleanup; - } - - 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)); - goto cleanup; - } - umask(oldmask); - if (server->privileged && setgid(oldgrp)) { - VIR_ERROR(_("Failed to restore group ID to %d"), oldgrp); - 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 */ } -static struct qemud_server *qemudInitialize(void) { - struct qemud_server *server; - - if (VIR_ALLOC(server) < 0) { - VIR_ERROR0(_("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_ERROR0(_("cannot initialize mutex")); - VIR_FREE(server); - return NULL; - } - if (virCondInit(&server->job) < 0) { - VIR_ERROR0(_("cannot initialize condition variable")); - virMutexDestroy(&server->lock); - VIR_FREE(server); - return NULL; - } - - if (virEventInit() < 0) { - VIR_ERROR0(_("Failed to initialize event system")); - 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 @@ -912,83 +430,104 @@ static struct qemud_server *qemudInitialize(void) { oneRegister(); # endif #endif - - virEventRegisterImpl(virEventAddHandleImpl, - virEventUpdateHandleImpl, - virEventRemoveHandleImpl, - virEventAddTimeoutImpl, - virEventUpdateTimeoutImpl, - virEventRemoveTimeoutImpl); - - return server; } -static int qemudNetworkInit(struct qemud_server *server) { - char *sockname = NULL; - char *roSockname = NULL; -#if HAVE_SASL - int err; -#endif /* HAVE_SASL */ +static int daemonSetupNetworking(virNetServerPtr srv, + struct daemonConfig *config, + const char *sock_path, + const char *sock_path_ro, + bool ipsock) +{ + 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 (!virNetServerIsPrivileged(srv)) { + VIR_WARN0("Cannot set group when not running as root"); + return -1; + } + if (virGetGroupID(config->unix_sock_group, &unix_sock_gid) < 0) + return -1; + } - if (qemudInitPaths(server, &sockname, &roSockname) < 0) - goto cleanup; + 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 (qemudListenUnix(server, sockname, 0, auth_unix_rw) < 0) - goto cleanup; - sockname = 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 (roSockname != NULL && qemudListenUnix(server, roSockname, 1, auth_unix_ro) < 0) - goto cleanup; - roSockname = NULL; + 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; -#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 (virNetServerAddService(srv, svc) < 0) + goto error; + if (svcRO && + virNetServerAddService(srv, svcRO) < 0) + goto error; -#if HAVE_POLKIT0 - if (auth_unix_rw == REMOTE_AUTH_POLKIT || - auth_unix_ro == REMOTE_AUTH_POLKIT) { - DBusError derr; + if (ipsock) { + if (config->listen_tcp && + !(svcTCP = virNetServerServiceNewTCP(config->listen_addr, + config->tcp_port, + config->auth_tcp, + false, + NULL))) + goto error; - dbus_connection_set_change_sigpipe(FALSE); - dbus_threads_init_default(); + if (virNetServerAddService(srv, svcTCP) < 0) + 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 (config->listen_tls) { + virNetTLSContextPtr ctxt = NULL; - if (ipsock) { - if (listen_tcp && remoteListenTCP (server, listen_addr, tcp_port, QEMUD_SOCK_TYPE_TCP, auth_tcp) < 0) - goto cleanup; + 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; - if (listen_tls) { - if (remoteInitializeGnuTLS () < 0) - goto cleanup; + if (!(svcTLS = + virNetServerServiceNewTCP(config->listen_addr, + config->tls_port, + config->auth_tls, + false, + ctxt))) { + virNetTLSContextFree(ctxt); + goto error; + } + if (virNetServerAddService(srv, svcTLS) < 0) + goto error; - if (remoteListenTCP (server, listen_addr, tls_port, QEMUD_SOCK_TYPE_TLS, auth_tls) < 0) - goto cleanup; + virNetTLSContextFree(ctxt); } } -#ifdef HAVE_AVAHI - if (server->privileged && mdns_adv) { +#ifdef HAVE_AVAHIXXXXXXXXXXXXX + if (virNetServerIsPrivileged(srv) && mdns_adv) { struct libvirtd_mdns_group *group; struct qemud_socket *sock; int port = 0; @@ -1016,7 +555,7 @@ static int qemudNetworkInit(struct qemud_server *server) { VIR_FREE(localhost); if (ret < 0) { virReportOOMError(); - goto cleanup; + goto error; } group = libvirtd_mdns_add_group(server->mdns, groupname); VIR_FREE(groupname); @@ -1048,235 +587,47 @@ static int qemudNetworkInit(struct qemud_server *server) { } #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 = virEventAddHandleImpl(sock->fd, - VIR_EVENT_HANDLE_READABLE | - VIR_EVENT_HANDLE_ERROR | - VIR_EVENT_HANDLE_HANGUP, - qemudDispatchServerEvent, - server, NULL)) < 0) { - VIR_ERROR0(_("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. */ - 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_ERROR0(_("The client certificate is not trusted.")); - - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) - VIR_ERROR0(_("The client certificate has unknown issuer.")); - - if (status & GNUTLS_CERT_REVOKED) - VIR_ERROR0(_("The client certificate has been revoked.")); - -#ifndef GNUTLS_1_0_COMPAT - if (status & GNUTLS_CERT_INSECURE_ALGORITHM) - VIR_ERROR0(_("The client certificate uses an insecure algorithm.")); -#endif - - goto authdeny; - } - - if (gnutls_certificate_type_get(client->tlssession) != GNUTLS_CRT_X509) { - VIR_ERROR0(_("Only x509 certificates are supported")); - goto authdeny; - } - if (!(certs = gnutls_certificate_get_peers(client->tlssession, &nCerts))) { - VIR_ERROR0(_("The certificate has no peers")); - goto authdeny; + 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; } - now = time (NULL); - - for (i = 0; i < nCerts; i++) { - gnutls_x509_crt_t cert; - - if (gnutls_x509_crt_init (&cert) < 0) { - VIR_ERROR0(_("Unable to initialize certificate")); - goto authfail; - } - - if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) { - VIR_ERROR0(_("Unable to load certificate")); - gnutls_x509_crt_deinit (cert); - goto authfail; - } - - 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 (!remoteCheckDN (name)) { - /* This is the most common error: make it informative. */ - VIR_ERROR0(_("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 HAVE_POLKIT0 + if (auth_unix_rw == REMOTE_AUTH_POLKIT || + auth_unix_ro == REMOTE_AUTH_POLKIT) { + DBusError derr; - if (gnutls_x509_crt_get_expiration_time (cert) < now) { - VIR_ERROR0(_("The client certificate has expired")); - gnutls_x509_crt_deinit (cert); - goto authdeny; - } + dbus_connection_set_change_sigpipe(FALSE); + dbus_threads_init_default(); - if (gnutls_x509_crt_get_activation_time (cert) > now) { - VIR_ERROR0(_("The client certificate is not yet active")); - gnutls_x509_crt_deinit (cert); - goto authdeny; + 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; } + dbus_connection_set_exit_on_disconnect(server->sysbus, FALSE); } +#endif - 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); +error: + virNetServerServiceFree(svcTLS); + virNetServerServiceFree(svcTCP); + virNetServerServiceFree(svc); + virNetServerServiceFree(svcRO); 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_ERROR0(_("remoteCheckCertificate: " - "failed to verify client's certificate")); - if (!tls_no_verify_certificate) return -1; - else VIR_INFO0(_("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) { @@ -1295,1211 +646,52 @@ int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *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_ERROR0(_("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_ERROR0(_("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); - 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_ERROR0(_("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_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) - 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; - } - } -#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); - 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) { - virEventRemoveHandleImpl(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) { - 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) -{ - 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; - } - - /*qemudDebug ("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; - char encoded[8192]; - ssize_t encodedLen = sizeof(encoded); - encodedLen = qemudClientReadBuf(client, encoded, encodedLen); - - if (encodedLen <= 0) - return encodedLen; - - ret = sasl_decode(client->saslconn, encoded, 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) { - /*qemudDebug ("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); - DEBUG0("Failed to decode packet length"); - qemudDispatchClientFailure(client); - return; - } - xdr_destroy (&x); - - if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) { - 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) { - 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 = virEventAddHandleImpl(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); - - virEventUpdateHandleImpl(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 (virEventRunOnce() < 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) { - DEBUG0("Timer expired but still active, not shutting down"); - virEventUpdateTimeoutImpl(timerid, -1); - } else { - DEBUG0("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 = virEventAddTimeoutImpl(-1, - qemudInactiveTimer, - server, NULL)) < 0) { - VIR_ERROR0(_("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_ERROR0(_("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) { - DEBUG("Deactivating shutdown timer %d", timerid); - virEventUpdateTimeoutImpl(timerid, -1); - timerActive = 0; - } - } else { - if (!virStateActive() && - !server->clients) { - DEBUG("Activating shutdown timer %d", timerid); - virEventUpdateTimeoutImpl(timerid, timeout * 1000); - timerActive = 1; - } - } - } - - virMutexUnlock(&server->lock); - if (qemudOneLoop() < 0) { - virMutexLock(&server->lock); - DEBUG0("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; +# error "UNIX socket credentials not supported/implemented on this platform yet..." +# endif + return 0; } +#endif -static void qemudCleanup(struct qemud_server *server) { - struct qemud_socket *sock; - VIR_FORCE_CLOSE(server->sigread); - VIR_FORCE_CLOSE(server->sigwrite); +#if 0 +XXX connection check - sock = server->sockets; - while (sock) { - struct qemud_socket *next = sock->next; - if (sock->watch) - virEventRemoveHandleImpl(sock->watch); - VIR_FORCE_CLOSE(sock->fd); +#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; - /* 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); + if (qemudGetSocketIdentity(client->fd, &uid, &pid) < 0) + goto error; - 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++; + /* 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, addrstr); + client->auth = REMOTE_AUTH_NONE; } - 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); +static int daemonShutdownCheck(virNetServerPtr srv ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + 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 @@ -2598,13 +790,11 @@ checkType (virConfValuePtr p, const char *filename, 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) @@ -2615,8 +805,8 @@ checkType (virConfValuePtr p, const char *filename, 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) @@ -2635,15 +825,11 @@ static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, cons 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); @@ -2653,26 +839,6 @@ static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, cons 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 syslog and the logging @@ -2680,13 +846,10 @@ remoteReadSaslAllowedUsernameList (virConfPtr conf ATTRIBUTE_UNUSED, * debugging is asked for then output informations or debug. */ static int -qemudSetLogging(virConfPtr conf, const char *filename) +daemonSetupLogging(struct daemonConfig *config, + bool verbose, + bool godaemon) { - int log_level = 0; - char *log_filters = NULL; - char *log_outputs = NULL; - int ret = -1; - virLogReset(); /* @@ -2703,21 +866,16 @@ qemudSetLogging(virConfPtr conf, const char *filename) * 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); - } + if (virLogGetNbFilters() == 0) + virLogParseFilters(config->log_filters); - if (virLogGetNbOutputs() == 0) { - GET_CONF_STR (conf, filename, log_outputs); - virLogParseOutputs(log_outputs); - } + if (virLogGetNbOutputs() == 0) + virLogParseOutputs(config->log_outputs); /* * If no defined outputs, then direct to syslog when running @@ -2726,13 +884,13 @@ qemudSetLogging(virConfPtr conf, const char *filename) if (virLogGetNbOutputs() == 0) { char *tmp = NULL; if (godaemon) { - if (virAsprintf (&tmp, "%d:syslog:libvirtd", - virLogGetDefaultPriority()) < 0) - goto free_and_fail; + if (virAsprintf(&tmp, "%d:syslog:libvirtd", + virLogGetDefaultPriority()) < 0) + goto no_memory; } else { - if (virAsprintf (&tmp, "%d:stderr", - virLogGetDefaultPriority()) < 0) - goto free_and_fail; + if (virAsprintf(&tmp, "%d:stderr", + virLogGetDefaultPriority()) < 0) + goto no_memory; } virLogParseOutputs(tmp); VIR_FREE(tmp); @@ -2744,46 +902,175 @@ qemudSetLogging(virConfPtr conf, const char *filename) if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO)) virLogSetDefaultPriority(VIR_LOG_INFO); - ret = 0; + return 0; -free_and_fail: - VIR_FREE(log_filters); - VIR_FREE(log_outputs); - return(ret); +no_memory: + virReportOOMError(); + return -1; } -/* 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) +daemonConfigFilePath(bool privileged, char **configfile) { - virConfPtr conf; + 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; + +no_memory: + virReportOOMError(); +error: + return -1; +} + +static void +daemonConfigFree(struct daemonConfig *data); + +static struct daemonConfig* +daemonConfigNew(bool privileged) +{ + struct daemonConfig *data; + + if (VIR_ALLOC(data) < 0) { + virReportOOMError(); + return NULL; + } + + data->listen_tls = 1; + data->listen_tcp = 0; - /* 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 (!(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 - /* 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; + 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; + + if (!(data->key_file = strdup(LIBVIRT_SERVERKEY))) + goto no_memory; + if (!(data->cert_file = strdup(LIBVIRT_SERVERCERT))) + goto no_memory; + if (!(data->ca_file = strdup(LIBVIRT_CACERT))) + goto no_memory; + + data->min_workers = 5; + data->max_workers = 20; + data->max_clients = 20; + + data->max_requests = 20; + data->max_client_requests = 5; + + data->audit_level = 1; + data->audit_logging = 0; + + + 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 +daemonConfigLoad(struct daemonConfig *data, + const char *filename) +{ + virConfPtr conf; + conf = virConfReadFile (filename, 0); - if (!conf) return -1; + if (!conf) + return -1; - /* - * First get all the logging settings and activate them - */ - if (qemudSetLogging(conf, filename) < 0) - goto free_and_fail; GET_CONF_INT (conf, filename, listen_tcp); GET_CONF_INT (conf, filename, listen_tls); @@ -2791,76 +1078,28 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename) 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_WARN0("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_ERROR0(_("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_ERROR0(_("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); @@ -2874,12 +1113,14 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename) 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); @@ -2893,51 +1134,31 @@ remoteReadConfigFile (struct qemud_server *server, const char *filename) 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); 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); @@ -2956,72 +1177,61 @@ qemudSetupPrivs (void) 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); - - sig_action.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &sig_action, NULL); +static void daemonRunStateInit(void *opaque) +{ + virNetServerPtr srv = opaque; - if (virEventAddHandleImpl(sigpipe[0], - VIR_EVENT_HANDLE_READABLE, - qemudDispatchSignalEvent, - server, NULL) < 0) { - VIR_ERROR0(_("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_ERROR0(_("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) { fprintf (stderr, _("\n\ @@ -3077,12 +1287,18 @@ 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; struct option opts[] = { { "verbose", no_argument, &verbose, 1}, @@ -3100,7 +1316,7 @@ int main(int argc, char **argv) { 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); } @@ -3142,65 +1358,96 @@ int main(int argc, char **argv) { 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; + if (!(remote_config_file = strdup(optarg))) + exit(EXIT_FAILURE); break; case OPT_VERSION: - version (); + daemonVersion(argv[0]); return 0; case '?': - usage (); + daemonUsage(argv[0]); 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(geteuid() == 0 ? true : false))) + exit(EXIT_FAILURE); + + /* No explicit config, so try and find a default one */ + if (remote_config_file == NULL && + daemonConfigFilePath(geteuid() == 0 ? true : false, + &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, verbose, godaemon) < 0) + exit(EXIT_FAILURE); + + if (daemonPidFilePath(geteuid() == 0 ? true : false, + &pid_file) < 0) + exit(EXIT_FAILURE); + + if (daemonUnixSocketPaths(config, + geteuid() == 0 ? true : false, + &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; + REMOTE_PID_FILE[0] != '\0') { + if (!(pid_file = strdup(REMOTE_PID_FILE))) { + ret = VIR_DAEMON_ERR_PIDFILE; + goto cleanup; + } + } /* 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) */ @@ -3213,56 +1460,87 @@ int main(int argc, char **argv) { VIR_ERROR(_("unable to create rundir %s: %s"), rundir, virStrerror(errno, ebuf, sizeof(ebuf))); ret = VIR_DAEMON_ERR_RUNDIR; - goto error; + goto cleanup; } } } + if (!(srv = virNetServerNew(config->min_workers, + config->max_workers, + config->max_clients, + 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; } - if (!(server = qemudInitialize())) { + daemonInitialize(); + + 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); /* * Call the daemon startup hook @@ -3272,9 +1550,11 @@ int main(int argc, char **argv) { 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) < 0) { ret = VIR_DAEMON_ERR_NETWORK; - goto error; + goto cleanup; } /* Tell parent of daemon that basic initialization is complete @@ -3289,52 +1569,24 @@ int main(int argc, char **argv) { 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_ERROR0(_("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_ERROR0(_("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_ERROR0(_("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 */ @@ -3345,10 +1597,13 @@ error: } VIR_FORCE_CLOSE(statuswrite); } - if (server) - qemudCleanup(server); if (pid_file) unlink (pid_file); + VIR_FREE(sock_file); + VIR_FREE(sock_file_ro); + VIR_FREE(pid_file); + VIR_FREE(remote_config_file); + daemonConfigFree(config); virLogShutdown(); return ret; } diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index af20e56..aa6560f 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -27,13 +27,6 @@ # 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 @@ -49,6 +42,8 @@ # include "logging.h" # include "threads.h" # include "network.h" +# include "virnetsaslcontext.h" +# include "virnetserverprogram.h" # if WITH_DTRACE # ifndef LIBVIRTD_PROBES_H @@ -67,231 +62,37 @@ #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 - -# define qemudDebug DEBUG - -/* 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; -# 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; + daemonClientStreamPtr streams; }; -# 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; -}; - -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; @@ -309,27 +110,6 @@ struct qemud_server { # 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); diff --git a/daemon/remote.c b/daemon/remote.c index 9dba325..de3fa7b 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -22,26 +22,6 @@ #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 @@ -50,19 +30,32 @@ #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 "network.h" #include "libvirt/libvirt-qemu.h" +#include "virnetserverservice.h" + +#include "remote_protocol.h" +#include "qemu_protocol.h" + + +#include "remote_dispatch.h" +#include "qemu_dispatch.h" -#define VIR_FROM_THIS VIR_FROM_REMOTE -#define REMOTE_DEBUG(fmt, ...) DEBUG(fmt, __VA_ARGS__) + +#define VIR_FROM_THIS VIR_FROM_RPC + +#define virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) +#define REMOTE_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__) static virDomainPtr get_nonnull_domain (virConnectPtr conn, remote_nonnull_domain domain); static virNetworkPtr get_nonnull_network (virConnectPtr conn, remote_nonnull_network network); @@ -83,43 +76,13 @@ static void make_nonnull_nwfilter (remote_nonnull_nwfilter *net_dst, virNWFilter static void make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src); -#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; - } - - return &(qemu_dispatch_table[proc]); -} - /* Prototypes */ static void -remoteDispatchDomainEventSend (struct qemud_client *client, - int procnr, - xdrproc_t proc, - void *data); +remoteDispatchDomainEventSend(virNetServerClientPtr client, + virNetServerProgramPtr program, + int procnr, + xdrproc_t proc, + void *data); static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, @@ -127,7 +90,7 @@ static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED, int detail, void *opaque) { - struct qemud_client *client = opaque; + virNetServerClientPtr client = opaque; remote_domain_event_lifecycle_msg data; if (!client) @@ -135,20 +98,16 @@ static int remoteRelayDomainEventLifecycle(virConnectPtr conn ATTRIBUTE_UNUSED, REMOTE_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; } @@ -156,7 +115,7 @@ static int remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, void *opaque) { - struct qemud_client *client = opaque; + virNetServerClientPtr client = opaque; remote_domain_event_reboot_msg data; if (!client) @@ -164,18 +123,14 @@ static int remoteRelayDomainEventReboot(virConnectPtr conn ATTRIBUTE_UNUSED, REMOTE_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; } @@ -185,7 +140,7 @@ static int remoteRelayDomainEventRTCChange(virConnectPtr conn ATTRIBUTE_UNUSED, long long offset, void *opaque) { - struct qemud_client *client = opaque; + virNetServerClientPtr client = opaque; remote_domain_event_rtc_change_msg data; if (!client) @@ -193,19 +148,15 @@ static int remoteRelayDomainEventRTCChange(virConnectPtr conn ATTRIBUTE_UNUSED, REMOTE_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; } @@ -215,7 +166,7 @@ static int remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED, int action, void *opaque) { - struct qemud_client *client = opaque; + virNetServerClientPtr client = opaque; remote_domain_event_watchdog_msg data; if (!client) @@ -223,19 +174,15 @@ static int remoteRelayDomainEventWatchdog(virConnectPtr conn ATTRIBUTE_UNUSED, REMOTE_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; } @@ -247,7 +194,7 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED, int action, void *opaque) { - struct qemud_client *client = opaque; + virNetServerClientPtr client = opaque; remote_domain_event_io_error_msg data; if (!client) @@ -255,8 +202,6 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED, REMOTE_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); @@ -264,12 +209,10 @@ static int remoteRelayDomainEventIOError(virConnectPtr conn ATTRIBUTE_UNUSED, 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; } @@ -282,7 +225,7 @@ static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUS const char *reason, void *opaque) { - struct qemud_client *client = opaque; + virNetServerClientPtr client = opaque; remote_domain_event_io_error_reason_msg data; if (!client) @@ -291,8 +234,6 @@ static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUS REMOTE_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); @@ -301,12 +242,10 @@ static int remoteRelayDomainEventIOErrorReason(virConnectPtr conn ATTRIBUTE_UNUS 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; } @@ -320,7 +259,7 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainEventGraphicsSubjectPtr subject, void *opaque) { - struct qemud_client *client = opaque; + virNetServerClientPtr client = opaque; remote_domain_event_graphics_msg data; int i; @@ -337,8 +276,6 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED, REMOTE_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); @@ -355,7 +292,7 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED, data.subject.subject_len = subject->nidentity; if (VIR_ALLOC_N(data.subject.subject_val, data.subject.subject_len) < 0) { - VIR_WARN0("cannot allocate memory for graphics event subject"); + virReportOOMError(); return -1; } for (i = 0 ; i < data.subject.subject_len ; i++) { @@ -363,14 +300,12 @@ static int remoteRelayDomainEventGraphics(virConnectPtr conn ATTRIBUTE_UNUSED, 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; } @@ -387,86 +322,134 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = { 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 elsehwere + */ +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) { + 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, + struct remote_open_args *args) { const char *name; int flags, rc; - + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + DEBUG("priv=%p conn=%p", priv, priv->conn); + virMutexLock(&priv->lock); /* Already opened? */ - if (conn) { - remoteDispatchFormatError (rerr, "%s", _("connection already open")); + if (priv->conn) { + virNetError(VIR_ERR_RPC, + "%s", _("connection already open")); return -1; } - virMutexLock(&server->lock); - virMutexLock(&client->lock); - virMutexUnlock(&server->lock); - name = args->name ? *args->name : NULL; /* If this connection arrived on a readonly socket, force * 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) - remoteDispatchConnError(rerr, NULL); + if (priv->conn) { + rc = 0; + } else { + rc = -1; + } - rc = client->conn ? 0 : -1; - virMutexUnlock(&client->lock); + virMutexUnlock(&priv->lock); return rc; } #define CHECK_CONN(client) \ - if (!client->conn) { \ - remoteDispatchFormatError (rerr, "%s", _("connection not open")); \ + struct daemonClientPrivate *priv = \ + virNetServerClientGetPrivateData(client); \ + if (!priv->conn) { \ + virNetError(VIR_ERR_RPC, "%s", _("connection not open")); \ return -1; \ } 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) { - virMutexLock(&server->lock); - virMutexLock(&client->lock); - virMutexUnlock(&server->lock); - - client->closing = 1; - - virMutexUnlock(&client->lock); + virNetServerClientClose(client); return 0; } static int -remoteDispatchSupportsFeature (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchSupportsFeature (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_supports_feature_args *args, remote_supports_feature_ret *ret) { - ret->supported = virDrvSupportsFeature (conn, args->feature); + CHECK_CONN(client); + + ret->supported = virDrvSupportsFeature (priv->conn, args->feature); if (ret->supported == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -474,18 +457,16 @@ remoteDispatchSupportsFeature (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchGetType (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, remote_get_type_ret *ret) +remoteDispatchGetType (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_get_type_ret *ret) { const char *type; + CHECK_CONN(client); - type = virConnectGetType (conn); + type = virConnectGetType (priv->conn); if (type == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -494,7 +475,7 @@ remoteDispatchGetType (struct qemud_server *server ATTRIBUTE_UNUSED, */ ret->type = strdup (type); if (!ret->type) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } @@ -502,18 +483,15 @@ remoteDispatchGetType (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchGetVersion (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, +remoteDispatchGetVersion (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_get_version_ret *ret) { unsigned long hvVer; + CHECK_CONN(client); - if (virConnectGetVersion (conn, &hvVer) == -1) { - remoteDispatchConnError(rerr, conn); + if (virConnectGetVersion (priv->conn, &hvVer) == -1) { return -1; } @@ -522,18 +500,15 @@ remoteDispatchGetVersion (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchGetLibVersion (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, +remoteDispatchGetLibVersion (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_get_lib_version_ret *ret) { unsigned long libVer; + CHECK_CONN(client); - if (virConnectGetLibVersion (conn, &libVer) == -1) { - remoteDispatchConnError(rerr, conn); + if (virConnectGetLibVersion (priv->conn, &libVer) == -1) { return -1; } @@ -542,19 +517,16 @@ remoteDispatchGetLibVersion (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchGetHostname (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, +remoteDispatchGetHostname (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_get_hostname_ret *ret) { char *hostname; + CHECK_CONN(client); - hostname = virConnectGetHostname (conn); + hostname = virConnectGetHostname (priv->conn); if (hostname == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -563,20 +535,16 @@ remoteDispatchGetHostname (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchGetUri (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, +remoteDispatchGetUri (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_get_uri_ret *ret) { char *uri; CHECK_CONN(client); - uri = virConnectGetURI (conn); + uri = virConnectGetURI (priv->conn); if (uri == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -585,20 +553,18 @@ remoteDispatchGetUri (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchGetMaxVcpus (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_get_max_vcpus_args *args, remote_get_max_vcpus_ret *ret) { char *type; + CHECK_CONN(client); type = args->type ? *args->type : NULL; - ret->max_vcpus = virConnectGetMaxVcpus (conn, type); + ret->max_vcpus = virConnectGetMaxVcpus (priv->conn, type); if (ret->max_vcpus == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -606,18 +572,15 @@ remoteDispatchGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNodeGetInfo (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, +remoteDispatchNodeGetInfo (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_get_info_ret *ret) { virNodeInfo info; + CHECK_CONN(client); - if (virNodeGetInfo (conn, &info) == -1) { - remoteDispatchConnError(rerr, conn); + if (virNodeGetInfo (priv->conn, &info) == -1) { return -1; } @@ -634,19 +597,16 @@ remoteDispatchNodeGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchGetCapabilities (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, +remoteDispatchGetCapabilities (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_get_capabilities_ret *ret) { char *caps; + CHECK_CONN(client); - caps = virConnectGetCapabilities (conn); + caps = virConnectGetCapabilities (priv->conn); if (caps == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -655,35 +615,33 @@ remoteDispatchGetCapabilities (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNodeGetCellsFreeMemory (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeGetCellsFreeMemory (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_get_cells_free_memory_args *args, remote_node_get_cells_free_memory_ret *ret) { int err; + CHECK_CONN(client); if (args->maxCells > REMOTE_NODE_MAX_CELLS) { - remoteDispatchFormatError (rerr, - "%s", _("maxCells > REMOTE_NODE_MAX_CELLS")); + virNetError(VIR_ERR_RPC, + "%s", _("maxCells > REMOTE_NODE_MAX_CELLS")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->freeMems.freeMems_val, args->maxCells) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } - err = virNodeGetCellsFreeMemory(conn, + err = virNodeGetCellsFreeMemory(priv->conn, (unsigned long long *)ret->freeMems.freeMems_val, args->startCell, args->maxCells); if (err <= 0) { VIR_FREE(ret->freeMems.freeMems_val); - remoteDispatchConnError(rerr, conn); return -1; } ret->freeMems.freeMems_len = err; @@ -693,19 +651,16 @@ remoteDispatchNodeGetCellsFreeMemory (struct qemud_server *server ATTRIBUTE_UNUS static int -remoteDispatchNodeGetFreeMemory (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, +remoteDispatchNodeGetFreeMemory (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_get_free_memory_ret *ret) { unsigned long long freeMem; + CHECK_CONN(client); - freeMem = virNodeGetFreeMemory(conn); + freeMem = virNodeGetFreeMemory(priv->conn); if (freeMem == 0) { - remoteDispatchConnError(rerr, conn); return -1; } ret->freeMem = freeMem; @@ -714,28 +669,25 @@ remoteDispatchNodeGetFreeMemory (struct qemud_server *server ATTRIBUTE_UNUSED, 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_scheduler_type_args *args, remote_domain_get_scheduler_type_ret *ret) { virDomainPtr dom; char *type; int nparams; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } type = virDomainGetSchedulerType (dom, &nparams); if (type == NULL) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -746,33 +698,32 @@ remoteDispatchDomainGetSchedulerType (struct qemud_server *server ATTRIBUTE_UNUS } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_scheduler_parameters_args *args, remote_domain_get_scheduler_parameters_ret *ret) { virDomainPtr dom; virSchedParameterPtr params; int i, r, nparams; + CHECK_CONN(client); nparams = args->nparams; if (nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) { - remoteDispatchFormatError (rerr, "%s", _("nparams too large")); + virNetError(VIR_ERR_RPC, + "%s", _("nparams too large")); return -1; } if (VIR_ALLOC_N(params, nparams) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { VIR_FREE(params); - remoteDispatchConnError(rerr, conn); return -1; } @@ -780,7 +731,6 @@ remoteDispatchDomainGetSchedulerParameters (struct qemud_server *server ATTRIBUT if (r == -1) { virDomainFree(dom); VIR_FREE(params); - remoteDispatchConnError(rerr, conn); return -1; } @@ -810,7 +760,8 @@ remoteDispatchDomainGetSchedulerParameters (struct qemud_server *server ATTRIBUT case VIR_DOMAIN_SCHED_FIELD_BOOLEAN: ret->params.params_val[i].value.remote_sched_param_value_u.b = params[i].value.b; break; default: - remoteDispatchFormatError (rerr, "%s", _("unknown type")); + virNetError(VIR_ERR_RPC, + "%s", _("unknown type")); goto cleanup; } } @@ -820,7 +771,7 @@ remoteDispatchDomainGetSchedulerParameters (struct qemud_server *server ATTRIBUT return 0; oom: - remoteDispatchOOMError(rerr); + virReportOOMError(); cleanup: virDomainFree(dom); for (i = 0 ; i < nparams ; i++) @@ -830,34 +781,34 @@ cleanup: } static int -remoteDispatchDomainSetSchedulerParameters (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_set_scheduler_parameters_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSetSchedulerParameters (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_set_scheduler_parameters_args *args) { virDomainPtr dom; int i, r, nparams; virSchedParameterPtr params; + CHECK_CONN(client); nparams = args->params.params_len; if (nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) { - remoteDispatchFormatError (rerr, "%s", _("nparams too large")); + virNetError(VIR_ERR_RPC, + "%s", _("nparams too large")); return -1; } if (VIR_ALLOC_N(params, nparams) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } /* Deserialise parameters. */ for (i = 0; i < nparams; ++i) { if (virStrcpyStatic(params[i].field, args->params.params_val[i].field) == NULL) { - remoteDispatchFormatError(rerr, _("Field %s too big for destination"), - args->params.params_val[i].field); + virNetError(VIR_ERR_RPC, + _("Field %s too big for destination"), + args->params.params_val[i].field); return -1; } params[i].type = args->params.params_val[i].value.type; @@ -877,10 +828,9 @@ remoteDispatchDomainSetSchedulerParameters (struct qemud_server *server ATTRIBUT } } - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { VIR_FREE(params); - remoteDispatchConnError(rerr, conn); return -1; } @@ -888,7 +838,6 @@ remoteDispatchDomainSetSchedulerParameters (struct qemud_server *server ATTRIBUT virDomainFree(dom); VIR_FREE(params); if (r == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -896,28 +845,25 @@ remoteDispatchDomainSetSchedulerParameters (struct qemud_server *server ATTRIBUT } static int -remoteDispatchDomainBlockStats (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainBlockStats (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_block_stats_args *args, remote_domain_block_stats_ret *ret) { virDomainPtr dom; char *path; struct _virDomainBlockStats stats; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } path = args->path; if (virDomainBlockStats (dom, path, &stats, sizeof stats) == -1) { virDomainFree (dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree (dom); @@ -932,28 +878,25 @@ remoteDispatchDomainBlockStats (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainInterfaceStats (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainInterfaceStats (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_interface_stats_args *args, remote_domain_interface_stats_ret *ret) { virDomainPtr dom; char *path; struct _virDomainInterfaceStats stats; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } path = args->path; if (virDomainInterfaceStats (dom, path, &stats, sizeof stats) == -1) { virDomainFree (dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree (dom); @@ -971,34 +914,32 @@ remoteDispatchDomainInterfaceStats (struct qemud_server *server ATTRIBUTE_UNUSED } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_memory_stats_args *args, remote_domain_memory_stats_ret *ret) { virDomainPtr dom; struct _virDomainMemoryStat *stats; unsigned int nr_stats, i; + CHECK_CONN(client); if (args->maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX) { - remoteDispatchFormatError (rerr, "%s", - _("maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX")); + virNetError(VIR_ERR_RPC, "%s", + _("maxStats > REMOTE_DOMAIN_MEMORY_STATS_MAX")); return -1; } - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } /* Allocate stats array for making dispatch call */ if (VIR_ALLOC_N(stats, args->maxStats) < 0) { + virReportOOMError(); virDomainFree (dom); - remoteDispatchOOMError(rerr); return -1; } @@ -1006,14 +947,13 @@ remoteDispatchDomainMemoryStats (struct qemud_server *server ATTRIBUTE_UNUSED, virDomainFree (dom); if (nr_stats == -1) { VIR_FREE(stats); - remoteDispatchConnError(rerr, conn); return -1; } /* Allocate return buffer */ if (VIR_ALLOC_N(ret->stats.stats_val, args->maxStats) < 0) { + virReportOOMError(); VIR_FREE(stats); - remoteDispatchOOMError(rerr); return -1; } @@ -1028,11 +968,9 @@ remoteDispatchDomainMemoryStats (struct qemud_server *server ATTRIBUTE_UNUSED, } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_block_peek_args *args, remote_domain_block_peek_ret *ret) { @@ -1041,10 +979,10 @@ remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED, unsigned long long offset; size_t size; unsigned int flags; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } path = args->path; @@ -1054,15 +992,15 @@ remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED, if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) { virDomainFree (dom); - remoteDispatchFormatError (rerr, - "%s", _("size > maximum buffer size")); + virNetError(VIR_ERR_RPC, + "%s", _("size > maximum buffer size")); return -1; } ret->buffer.buffer_len = size; if (VIR_ALLOC_N (ret->buffer.buffer_val, size) < 0) { + virReportOOMError(); virDomainFree (dom); - remoteDispatchOOMError(rerr); return -1; } @@ -1070,7 +1008,6 @@ remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED, ret->buffer.buffer_val, flags) == -1) { /* free (ret->buffer.buffer_val); - caller frees */ virDomainFree (dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree (dom); @@ -1079,11 +1016,9 @@ remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED, } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_memory_peek_args *args, remote_domain_memory_peek_ret *ret) { @@ -1091,10 +1026,10 @@ remoteDispatchDomainMemoryPeek (struct qemud_server *server ATTRIBUTE_UNUSED, unsigned long long offset; size_t size; unsigned int flags; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } offset = args->offset; @@ -1103,15 +1038,15 @@ remoteDispatchDomainMemoryPeek (struct qemud_server *server ATTRIBUTE_UNUSED, if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) { virDomainFree (dom); - remoteDispatchFormatError (rerr, - "%s", _("size > maximum buffer size")); + virNetError(VIR_ERR_RPC, + "%s", _("size > maximum buffer size")); return -1; } ret->buffer.buffer_len = size; if (VIR_ALLOC_N (ret->buffer.buffer_val, size) < 0) { + virReportOOMError(); virDomainFree (dom); - remoteDispatchOOMError(rerr); return -1; } @@ -1119,7 +1054,6 @@ remoteDispatchDomainMemoryPeek (struct qemud_server *server ATTRIBUTE_UNUSED, ret->buffer.buffer_val, flags) == -1) { /* free (ret->buffer.buffer_val); - caller frees */ virDomainFree (dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree (dom); @@ -1128,25 +1062,21 @@ remoteDispatchDomainMemoryPeek (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainAttachDevice (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_attach_device_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainAttachDevice (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_attach_device_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainAttachDevice (dom, args->xml) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1154,25 +1084,21 @@ remoteDispatchDomainAttachDevice (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainAttachDeviceFlags (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_attach_device_flags_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainAttachDeviceFlags (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_attach_device_flags_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainAttachDeviceFlags (dom, args->xml, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1180,25 +1106,21 @@ remoteDispatchDomainAttachDeviceFlags (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchDomainUpdateDeviceFlags (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_update_device_flags_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainUpdateDeviceFlags (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_update_device_flags_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainUpdateDeviceFlags (dom, args->xml, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1206,25 +1128,21 @@ remoteDispatchDomainUpdateDeviceFlags (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchDomainCreate (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_create_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainCreate (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_create_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainCreate (dom) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1232,25 +1150,22 @@ remoteDispatchDomainCreate (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainCreateWithFlags (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainCreateWithFlags (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_create_with_flags_args *args, remote_domain_create_with_flags_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainCreateWithFlags (dom, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -1260,19 +1175,17 @@ remoteDispatchDomainCreateWithFlags (struct qemud_server *server ATTRIBUTE_UNUSE } static int -remoteDispatchDomainCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainCreateXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_create_xml_args *args, remote_domain_create_xml_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = virDomainCreateXML (conn, args->xml_desc, args->flags); + dom = virDomainCreateXML (priv->conn, args->xml_desc, args->flags); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1283,19 +1196,17 @@ remoteDispatchDomainCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainDefineXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_define_xml_args *args, remote_domain_define_xml_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = virDomainDefineXML (conn, args->xml); + dom = virDomainDefineXML (priv->conn, args->xml); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1306,25 +1217,21 @@ remoteDispatchDomainDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainDestroy (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_destroy_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainDestroy (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_destroy_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainDestroy (dom) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1332,25 +1239,21 @@ remoteDispatchDomainDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainDetachDevice (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_detach_device_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainDetachDevice (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_detach_device_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainDetachDevice (dom, args->xml) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -1359,25 +1262,21 @@ remoteDispatchDomainDetachDevice (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainDetachDeviceFlags (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_detach_device_flags_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainDetachDeviceFlags (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_detach_device_flags_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainDetachDeviceFlags (dom, args->xml, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -1386,19 +1285,17 @@ remoteDispatchDomainDetachDeviceFlags (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchDomainDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainDumpXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_dump_xml_args *args, remote_domain_dump_xml_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1406,7 +1303,6 @@ remoteDispatchDomainDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, ret->xml = virDomainGetXMLDesc (dom, args->flags); if (!ret->xml) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1414,42 +1310,40 @@ remoteDispatchDomainDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainXmlFromNative (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainXmlFromNative (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_xml_from_native_args *args, remote_domain_xml_from_native_ret *ret) { + CHECK_CONN(client); + /* remoteDispatchClientRequest will free this. */ - ret->domainXml = virConnectDomainXMLFromNative (conn, + ret->domainXml = virConnectDomainXMLFromNative (priv->conn, args->nativeFormat, args->nativeConfig, args->flags); if (!ret->domainXml) { - remoteDispatchConnError(rerr, conn); return -1; } return 0; } static int -remoteDispatchDomainXmlToNative (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainXmlToNative (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_xml_to_native_args *args, remote_domain_xml_to_native_ret *ret) { + CHECK_CONN(client); + /* remoteDispatchClientRequest will free this. */ - ret->nativeConfig = virConnectDomainXMLToNative (conn, + ret->nativeConfig = virConnectDomainXMLToNative (priv->conn, args->nativeFormat, args->domainXml, args->flags); if (!ret->nativeConfig) { - remoteDispatchConnError(rerr, conn); return -1; } return 0; @@ -1457,25 +1351,22 @@ remoteDispatchDomainXmlToNative (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainGetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetAutostart (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_autostart_args *args, remote_domain_get_autostart_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainGetAutostart (dom, &ret->autostart) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1483,26 +1374,23 @@ remoteDispatchDomainGetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetInfo (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_info_args *args, remote_domain_get_info_ret *ret) { virDomainPtr dom; virDomainInfo info; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainGetInfo (dom, &info) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -1518,26 +1406,23 @@ remoteDispatchDomainGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetMaxMemory (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetMaxMemory (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_max_memory_args *args, remote_domain_get_max_memory_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } ret->memory = virDomainGetMaxMemory (dom); if (ret->memory == 0) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1545,26 +1430,23 @@ remoteDispatchDomainGetMaxMemory (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetMaxVcpus (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_max_vcpus_args *args, remote_domain_get_max_vcpus_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } ret->num = virDomainGetMaxVcpus (dom); if (ret->num == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1572,34 +1454,31 @@ remoteDispatchDomainGetMaxVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_security_label_args *args, remote_domain_get_security_label_ret *ret) { virDomainPtr dom; virSecurityLabel seclabel; + CHECK_CONN(client); - dom = get_nonnull_domain(conn, args->dom); + dom = get_nonnull_domain(priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } memset(&seclabel, 0, sizeof seclabel); if (virDomainGetSecurityLabel(dom, &seclabel) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } ret->label.label_len = strlen(seclabel.label) + 1; if (VIR_ALLOC_N(ret->label.label_val, ret->label.label_len) < 0) { + virReportOOMError(); virDomainFree(dom); - remoteDispatchOOMError(rerr); return -1; } strcpy(ret->label.label_val, seclabel.label); @@ -1610,32 +1489,29 @@ remoteDispatchDomainGetSecurityLabel(struct qemud_server *server ATTRIBUTE_UNUSE } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_get_security_model_ret *ret) { virSecurityModel secmodel; + CHECK_CONN(client); memset(&secmodel, 0, sizeof secmodel); - if (virNodeGetSecurityModel(conn, &secmodel) == -1) { - remoteDispatchConnError(rerr, conn); + if (virNodeGetSecurityModel(priv->conn, &secmodel) == -1) { return -1; } ret->model.model_len = strlen(secmodel.model) + 1; if (VIR_ALLOC_N(ret->model.model_val, ret->model.model_len) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } strcpy(ret->model.model_val, secmodel.model); ret->doi.doi_len = strlen(secmodel.doi) + 1; if (VIR_ALLOC_N(ret->doi.doi_val, ret->doi.doi_len) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } strcpy(ret->doi.doi_val, secmodel.doi); @@ -1644,19 +1520,17 @@ remoteDispatchNodeGetSecurityModel(struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainGetOsType (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetOsType (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_os_type_args *args, remote_domain_get_os_type_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1664,7 +1538,6 @@ remoteDispatchDomainGetOsType (struct qemud_server *server ATTRIBUTE_UNUSED, ret->type = virDomainGetOSType (dom); if (ret->type == NULL) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1672,11 +1545,9 @@ remoteDispatchDomainGetOsType (struct qemud_server *server ATTRIBUTE_UNUSED, } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_vcpus_args *args, remote_domain_get_vcpus_ret *ret) { @@ -1684,22 +1555,24 @@ remoteDispatchDomainGetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, virVcpuInfoPtr info = NULL; unsigned char *cpumaps = NULL; int info_len, i; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (args->maxinfo > REMOTE_VCPUINFO_MAX) { virDomainFree(dom); - remoteDispatchFormatError (rerr, "%s", _("maxinfo > REMOTE_VCPUINFO_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxinfo > REMOTE_VCPUINFO_MAX")); return -1; } if (args->maxinfo * args->maplen > REMOTE_CPUMAPS_MAX) { virDomainFree(dom); - remoteDispatchFormatError (rerr, "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxinfo * maplen > REMOTE_CPUMAPS_MAX")); return -1; } @@ -1717,7 +1590,6 @@ remoteDispatchDomainGetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, VIR_FREE(info); VIR_FREE(cpumaps); virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -1748,31 +1620,28 @@ oom: VIR_FREE(info); VIR_FREE(cpumaps); virDomainFree(dom); - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } static int -remoteDispatchDomainGetVcpusFlags (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetVcpusFlags (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_vcpus_flags_args *args, remote_domain_get_vcpus_flags_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } ret->num = virDomainGetVcpusFlags (dom, args->flags); if (ret->num == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -1780,11 +1649,9 @@ remoteDispatchDomainGetVcpusFlags (struct qemud_server *server ATTRIBUTE_UNUSED, } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_migrate_prepare_args *args, remote_domain_migrate_prepare_ret *ret) { @@ -1794,22 +1661,22 @@ remoteDispatchDomainMigratePrepare (struct qemud_server *server ATTRIBUTE_UNUSED char *uri_in; char **uri_out; char *dname; + CHECK_CONN(client); uri_in = args->uri_in == NULL ? NULL : *args->uri_in; dname = args->dname == NULL ? NULL : *args->dname; /* Wacky world of XDR ... */ if (VIR_ALLOC(uri_out) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } - r = virDomainMigratePrepare (conn, &cookie, &cookielen, + r = virDomainMigratePrepare (priv->conn, &cookie, &cookielen, uri_in, uri_out, args->flags, dname, args->resource); if (r == -1) { VIR_FREE(uri_out); - remoteDispatchConnError(rerr, conn); return -1; } @@ -1829,21 +1696,18 @@ remoteDispatchDomainMigratePrepare (struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchDomainMigratePerform (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_perform_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainMigratePerform (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_migrate_perform_args *args) { int r; virDomainPtr dom; char *dname; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1856,7 +1720,6 @@ remoteDispatchDomainMigratePerform (struct qemud_server *server ATTRIBUTE_UNUSED args->flags, dname, args->resource); virDomainFree (dom); if (r == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1864,24 +1727,21 @@ remoteDispatchDomainMigratePerform (struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchDomainMigrateFinish (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainMigrateFinish (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_migrate_finish_args *args, remote_domain_migrate_finish_ret *ret) { virDomainPtr ddom; CHECK_CONN (client); - ddom = virDomainMigrateFinish (conn, args->dname, + ddom = virDomainMigrateFinish (priv->conn, args->dname, args->cookie.cookie_val, args->cookie.cookie_len, args->uri, args->flags); if (ddom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1891,11 +1751,9 @@ remoteDispatchDomainMigrateFinish (struct qemud_server *server ATTRIBUTE_UNUSED, } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_migrate_prepare2_args *args, remote_domain_migrate_prepare2_ret *ret) { @@ -1912,16 +1770,15 @@ remoteDispatchDomainMigratePrepare2 (struct qemud_server *server ATTRIBUTE_UNUSE /* Wacky world of XDR ... */ if (VIR_ALLOC(uri_out) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } - r = virDomainMigratePrepare2 (conn, &cookie, &cookielen, + r = virDomainMigratePrepare2 (priv->conn, &cookie, &cookielen, uri_in, uri_out, args->flags, dname, args->resource, args->dom_xml); if (r == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1936,25 +1793,22 @@ remoteDispatchDomainMigratePrepare2 (struct qemud_server *server ATTRIBUTE_UNUSE } static int -remoteDispatchDomainMigrateFinish2 (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainMigrateFinish2 (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_migrate_finish2_args *args, remote_domain_migrate_finish2_ret *ret) { virDomainPtr ddom; CHECK_CONN (client); - ddom = virDomainMigrateFinish2 (conn, args->dname, + ddom = virDomainMigrateFinish2 (priv->conn, args->dname, args->cookie.cookie_val, args->cookie.cookie_len, args->uri, args->flags, args->retcode); if (ddom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -1964,75 +1818,75 @@ remoteDispatchDomainMigrateFinish2 (struct qemud_server *server ATTRIBUTE_UNUSED return 0; } + static int -remoteDispatchDomainMigratePrepareTunnel(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client, - virConnectPtr conn, - remote_message_header *hdr, - remote_error *rerr, - remote_domain_migrate_prepare_tunnel_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainMigratePrepareTunnel(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr, + remote_domain_migrate_prepare_tunnel_args *args) { int r; char *dname; - struct qemud_client_stream *stream; + daemonClientStreamPtr stream; CHECK_CONN (client); + virStreamPtr st; dname = args->dname == NULL ? NULL : *args->dname; - stream = remoteCreateClientStream(conn, hdr); + st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK); + if (!st) { + return -1; + } + + stream = daemonCreateClientStream(client, st, remoteProgram, hdr); if (!stream) { - remoteDispatchOOMError(rerr); return -1; } - r = virDomainMigratePrepareTunnel(conn, stream->st, + r = virDomainMigratePrepareTunnel(priv->conn, st, args->flags, dname, args->resource, args->dom_xml); if (r == -1) { - remoteFreeClientStream(client, stream); - remoteDispatchConnError(rerr, conn); + daemonFreeClientStream(client, stream); return -1; } - if (remoteAddClientStream(client, stream, 0) < 0) { - remoteDispatchConnError(rerr, conn); - virStreamAbort(stream->st); - remoteFreeClientStream(client, stream); + if (daemonAddClientStream(client, stream, 0) < 0) { + virStreamAbort(st); + daemonFreeClientStream(client, stream); return -1; } return 0; } + static int -remoteDispatchListDefinedDomains (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListDefinedDomains (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_defined_domains_args *args, remote_list_defined_domains_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_DOMAIN_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_DOMAIN_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_DOMAIN_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListDefinedDomains (conn, + virConnectListDefinedDomains (priv->conn, ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_val); - remoteDispatchConnError(rerr, conn); return -1; } @@ -2040,19 +1894,17 @@ remoteDispatchListDefinedDomains (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainLookupById (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainLookupById (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = virDomainLookupByID (conn, args->id); + dom = virDomainLookupByID (priv->conn, args->id); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2062,19 +1914,17 @@ remoteDispatchDomainLookupById (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_lookup_by_name_args *args, remote_domain_lookup_by_name_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = virDomainLookupByName (conn, args->name); + dom = virDomainLookupByName (priv->conn, args->name); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2084,19 +1934,17 @@ remoteDispatchDomainLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainLookupByUuid (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_lookup_by_uuid_args *args, remote_domain_lookup_by_uuid_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = virDomainLookupByUUID (conn, (unsigned char *) args->uuid); + dom = virDomainLookupByUUID (priv->conn, (unsigned char *) args->uuid); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2106,18 +1954,15 @@ remoteDispatchDomainLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNumOfDefinedDomains (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, +remoteDispatchNumOfDefinedDomains (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_defined_domains_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfDefinedDomains (conn); + ret->num = virConnectNumOfDefinedDomains (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2125,26 +1970,24 @@ remoteDispatchNumOfDefinedDomains (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainPinVcpu (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_pin_vcpu_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainPinVcpu (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_pin_vcpu_args *args) { virDomainPtr dom; int rv; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (args->cpumap.cpumap_len > REMOTE_CPUMAP_MAX) { virDomainFree(dom); - remoteDispatchFormatError (rerr, "%s", _("cpumap_len > REMOTE_CPUMAP_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("cpumap_len > REMOTE_CPUMAP_MAX")); return -1; } @@ -2153,7 +1996,6 @@ remoteDispatchDomainPinVcpu (struct qemud_server *server ATTRIBUTE_UNUSED, args->cpumap.cpumap_len); if (rv == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2161,25 +2003,21 @@ remoteDispatchDomainPinVcpu (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainReboot (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_reboot_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainReboot (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_reboot_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainReboot (dom, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2187,17 +2025,14 @@ remoteDispatchDomainReboot (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainRestore (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_restore_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainRestore (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_restore_args *args) { + CHECK_CONN(client); - if (virDomainRestore (conn, args->from) == -1) { - remoteDispatchConnError(rerr, conn); + if (virDomainRestore (priv->conn, args->from) == -1) { return -1; } @@ -2205,25 +2040,21 @@ remoteDispatchDomainRestore (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainResume (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_resume_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainResume (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_resume_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainResume (dom) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2231,25 +2062,21 @@ remoteDispatchDomainResume (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSave (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_save_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSave (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_save_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainSave (dom, args->to) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2257,25 +2084,21 @@ remoteDispatchDomainSave (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainCoreDump (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_core_dump_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainCoreDump (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_core_dump_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainCoreDump (dom, args->to, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2283,25 +2106,21 @@ remoteDispatchDomainCoreDump (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSetAutostart (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_set_autostart_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSetAutostart (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_set_autostart_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainSetAutostart (dom, args->autostart) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2309,25 +2128,21 @@ remoteDispatchDomainSetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSetMaxMemory (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_set_max_memory_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSetMaxMemory (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_set_max_memory_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainSetMaxMemory (dom, args->memory) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2335,25 +2150,21 @@ remoteDispatchDomainSetMaxMemory (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSetMemory (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_set_memory_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSetMemory (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_set_memory_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainSetMemory (dom, args->memory) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2361,31 +2172,27 @@ remoteDispatchDomainSetMemory (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSetMemoryParameters(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_set_memory_parameters_args - * args, void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSetMemoryParameters(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_set_memory_parameters_args *args) { virDomainPtr dom; int i, r, nparams; virMemoryParameterPtr params; unsigned int flags; + CHECK_CONN(client); nparams = args->params.params_len; flags = args->flags; if (nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) { - remoteDispatchFormatError(rerr, "%s", _("nparams too large")); + virNetError(VIR_ERR_RPC, + "%s", _("nparams too large")); return -1; } if (VIR_ALLOC_N(params, nparams) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } @@ -2393,10 +2200,9 @@ remoteDispatchDomainSetMemoryParameters(struct qemud_server *server for (i = 0; i < nparams; ++i) { if (virStrcpyStatic (params[i].field, args->params.params_val[i].field) == NULL) { - remoteDispatchFormatError(rerr, - _ - ("Field %s too big for destination"), - args->params.params_val[i].field); + virNetError(VIR_ERR_RPC, + _("Field %s too big for destination"), + args->params.params_val[i].field); return -1; } params[i].type = args->params.params_val[i].value.type; @@ -2434,10 +2240,9 @@ remoteDispatchDomainSetMemoryParameters(struct qemud_server *server } } - dom = get_nonnull_domain(conn, args->dom); + dom = get_nonnull_domain(priv->conn, args->dom); if (dom == NULL) { VIR_FREE(params); - remoteDispatchConnError(rerr, conn); return -1; } @@ -2445,7 +2250,6 @@ remoteDispatchDomainSetMemoryParameters(struct qemud_server *server virDomainFree(dom); VIR_FREE(params); if (r == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2453,40 +2257,34 @@ remoteDispatchDomainSetMemoryParameters(struct qemud_server *server } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_get_memory_parameters_args *args, + remote_domain_get_memory_parameters_ret *ret) { virDomainPtr dom; virMemoryParameterPtr params; int i, r, nparams; unsigned int flags; + CHECK_CONN(client); nparams = args->nparams; flags = args->flags; if (nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) { - remoteDispatchFormatError(rerr, "%s", _("nparams too large")); + virNetError(VIR_ERR_RPC, + "%s", _("nparams too large")); return -1; } if (VIR_ALLOC_N(params, nparams) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } - dom = get_nonnull_domain(conn, args->dom); + dom = get_nonnull_domain(priv->conn, args->dom); if (dom == NULL) { VIR_FREE(params); - remoteDispatchConnError(rerr, conn); return -1; } @@ -2494,7 +2292,6 @@ remoteDispatchDomainGetMemoryParameters(struct qemud_server *server if (r == -1) { virDomainFree(dom); VIR_FREE(params); - remoteDispatchConnError(rerr, conn); return -1; } /* In this case, we need to send back the number of parameters @@ -2549,7 +2346,7 @@ remoteDispatchDomainGetMemoryParameters(struct qemud_server *server params[i].value.b; break; default: - remoteDispatchFormatError(rerr, "%s", _("unknown type")); + virNetError(VIR_ERR_RPC, "%s", _("unknown type")); goto cleanup; } } @@ -2561,7 +2358,7 @@ remoteDispatchDomainGetMemoryParameters(struct qemud_server *server return 0; oom: - remoteDispatchOOMError(rerr); + virReportOOMError(); cleanup: virDomainFree(dom); for (i = 0; i < nparams; i++) @@ -2571,25 +2368,21 @@ remoteDispatchDomainGetMemoryParameters(struct qemud_server *server } static int -remoteDispatchDomainSetVcpus (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_set_vcpus_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSetVcpus (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_set_vcpus_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainSetVcpus (dom, args->nvcpus) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2597,25 +2390,21 @@ remoteDispatchDomainSetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSetVcpusFlags (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_set_vcpus_flags_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSetVcpusFlags (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_set_vcpus_flags_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainSetVcpusFlags (dom, args->nvcpus, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2623,25 +2412,21 @@ remoteDispatchDomainSetVcpusFlags (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainShutdown (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_shutdown_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainShutdown (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_shutdown_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainShutdown (dom) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2649,25 +2434,21 @@ remoteDispatchDomainShutdown (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSuspend (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_suspend_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSuspend (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_suspend_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainSuspend (dom) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2675,25 +2456,21 @@ remoteDispatchDomainSuspend (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainUndefine (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_undefine_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainUndefine (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_undefine_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainUndefine (dom) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2701,33 +2478,31 @@ remoteDispatchDomainUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchListDefinedNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListDefinedNetworks (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_defined_networks_args *args, remote_list_defined_networks_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_NETWORK_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_NETWORK_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_NETWORK_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListDefinedNetworks (conn, + virConnectListDefinedNetworks (priv->conn, ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_val); - remoteDispatchConnError(rerr, conn); return -1; } @@ -2735,32 +2510,30 @@ remoteDispatchListDefinedNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchListDomains (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListDomains (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_domains_args *args, remote_list_domains_ret *ret) { + CHECK_CONN(client); if (args->maxids > REMOTE_DOMAIN_ID_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxids > REMOTE_DOMAIN_ID_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxids > REMOTE_DOMAIN_ID_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->ids.ids_val, args->maxids) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } - ret->ids.ids_len = virConnectListDomains (conn, + ret->ids.ids_len = virConnectListDomains (priv->conn, ret->ids.ids_val, args->maxids); if (ret->ids.ids_len == -1) { VIR_FREE(ret->ids.ids_val); - remoteDispatchConnError(rerr, conn); return -1; } @@ -2768,25 +2541,21 @@ remoteDispatchListDomains (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainManagedSave (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_managed_save_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainManagedSave (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_managed_save_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainManagedSave (dom, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2794,26 +2563,23 @@ remoteDispatchDomainManagedSave (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainHasManagedSaveImage (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainHasManagedSaveImage (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_has_managed_save_image_args *args, remote_domain_has_managed_save_image_ret *ret) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } ret->ret = virDomainHasManagedSaveImage (dom, args->flags); if (ret->ret == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2821,25 +2587,21 @@ remoteDispatchDomainHasManagedSaveImage (struct qemud_server *server ATTRIBUTE_U } static int -remoteDispatchDomainManagedSaveRemove (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_managed_save_remove_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainManagedSaveRemove (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_managed_save_remove_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainManagedSaveRemove (dom, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } virDomainFree(dom); @@ -2847,33 +2609,31 @@ remoteDispatchDomainManagedSaveRemove (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchListNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListNetworks (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_networks_args *args, remote_list_networks_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_NETWORK_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_NETWORK_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_NETWORK_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListNetworks (conn, + virConnectListNetworks (priv->conn, ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_len); - remoteDispatchConnError(rerr, conn); return -1; } @@ -2881,25 +2641,21 @@ remoteDispatchListNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkCreate (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_network_create_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNetworkCreate (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_network_create_args *args) { virNetworkPtr net; + CHECK_CONN(client); - net = get_nonnull_network (conn, args->net); + net = get_nonnull_network (priv->conn, args->net); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNetworkCreate (net) == -1) { virNetworkFree(net); - remoteDispatchConnError(rerr, conn); return -1; } virNetworkFree(net); @@ -2907,19 +2663,17 @@ remoteDispatchNetworkCreate (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNetworkCreateXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_create_xml_args *args, remote_network_create_xml_ret *ret) { virNetworkPtr net; + CHECK_CONN(client); - net = virNetworkCreateXML (conn, args->xml); + net = virNetworkCreateXML (priv->conn, args->xml); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2929,19 +2683,17 @@ remoteDispatchNetworkCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNetworkDefineXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_define_xml_args *args, remote_network_define_xml_ret *ret) { virNetworkPtr net; + CHECK_CONN(client); - net = virNetworkDefineXML (conn, args->xml); + net = virNetworkDefineXML (priv->conn, args->xml); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2951,25 +2703,21 @@ remoteDispatchNetworkDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_network_destroy_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNetworkDestroy (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_network_destroy_args *args) { virNetworkPtr net; + CHECK_CONN(client); - net = get_nonnull_network (conn, args->net); + net = get_nonnull_network (priv->conn, args->net); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNetworkDestroy (net) == -1) { virNetworkFree(net); - remoteDispatchConnError(rerr, conn); return -1; } virNetworkFree(net); @@ -2977,19 +2725,17 @@ remoteDispatchNetworkDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNetworkDumpXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_dump_xml_args *args, remote_network_dump_xml_ret *ret) { virNetworkPtr net; + CHECK_CONN(client); - net = get_nonnull_network (conn, args->net); + net = get_nonnull_network (priv->conn, args->net); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -2997,7 +2743,6 @@ remoteDispatchNetworkDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, ret->xml = virNetworkGetXMLDesc (net, args->flags); if (!ret->xml) { virNetworkFree(net); - remoteDispatchConnError(rerr, conn); return -1; } virNetworkFree(net); @@ -3005,25 +2750,22 @@ remoteDispatchNetworkDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkGetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNetworkGetAutostart (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_get_autostart_args *args, remote_network_get_autostart_ret *ret) { virNetworkPtr net; + CHECK_CONN(client); - net = get_nonnull_network (conn, args->net); + net = get_nonnull_network (priv->conn, args->net); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNetworkGetAutostart (net, &ret->autostart) == -1) { virNetworkFree(net); - remoteDispatchConnError(rerr, conn); return -1; } virNetworkFree(net); @@ -3031,19 +2773,17 @@ remoteDispatchNetworkGetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkGetBridgeName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNetworkGetBridgeName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_get_bridge_name_args *args, remote_network_get_bridge_name_ret *ret) { virNetworkPtr net; + CHECK_CONN(client); - net = get_nonnull_network (conn, args->net); + net = get_nonnull_network (priv->conn, args->net); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3051,7 +2791,6 @@ remoteDispatchNetworkGetBridgeName (struct qemud_server *server ATTRIBUTE_UNUSED ret->name = virNetworkGetBridgeName (net); if (!ret->name) { virNetworkFree(net); - remoteDispatchConnError(rerr, conn); return -1; } virNetworkFree(net); @@ -3059,19 +2798,17 @@ remoteDispatchNetworkGetBridgeName (struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchNetworkLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNetworkLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_lookup_by_name_args *args, remote_network_lookup_by_name_ret *ret) { virNetworkPtr net; + CHECK_CONN(client); - net = virNetworkLookupByName (conn, args->name); + net = virNetworkLookupByName (priv->conn, args->name); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3081,19 +2818,17 @@ remoteDispatchNetworkLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNetworkLookupByUuid (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_lookup_by_uuid_args *args, remote_network_lookup_by_uuid_ret *ret) { virNetworkPtr net; + CHECK_CONN(client); - net = virNetworkLookupByUUID (conn, (unsigned char *) args->uuid); + net = virNetworkLookupByUUID (priv->conn, (unsigned char *) args->uuid); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3103,25 +2838,21 @@ remoteDispatchNetworkLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkSetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_network_set_autostart_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNetworkSetAutostart (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_network_set_autostart_args *args) { virNetworkPtr net; + CHECK_CONN(client); - net = get_nonnull_network (conn, args->net); + net = get_nonnull_network (priv->conn, args->net); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNetworkSetAutostart (net, args->autostart) == -1) { virNetworkFree(net); - remoteDispatchConnError(rerr, conn); return -1; } virNetworkFree(net); @@ -3129,25 +2860,21 @@ remoteDispatchNetworkSetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNetworkUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_network_undefine_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNetworkUndefine (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_network_undefine_args *args) { virNetworkPtr net; + CHECK_CONN(client); - net = get_nonnull_network (conn, args->net); + net = get_nonnull_network (priv->conn, args->net); if (net == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNetworkUndefine (net) == -1) { virNetworkFree(net); - remoteDispatchConnError(rerr, conn); return -1; } virNetworkFree(net); @@ -3155,18 +2882,15 @@ remoteDispatchNetworkUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNumOfDefinedNetworks (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, +remoteDispatchNumOfDefinedNetworks (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_defined_networks_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfDefinedNetworks (conn); + ret->num = virConnectNumOfDefinedNetworks (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3174,18 +2898,15 @@ remoteDispatchNumOfDefinedNetworks (struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchNumOfDomains (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, +remoteDispatchNumOfDomains (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_domains_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfDomains (conn); + ret->num = virConnectNumOfDomains (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3193,18 +2914,15 @@ remoteDispatchNumOfDomains (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNumOfNetworks (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, +remoteDispatchNumOfNetworks (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_networks_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfNetworks (conn); + ret->num = virConnectNumOfNetworks (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3214,18 +2932,15 @@ remoteDispatchNumOfNetworks (struct qemud_server *server ATTRIBUTE_UNUSED, /*-------------------------------------------------------------*/ static int -remoteDispatchNumOfInterfaces (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, +remoteDispatchNumOfInterfaces (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_interfaces_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfInterfaces (conn); + ret->num = virConnectNumOfInterfaces (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3233,33 +2948,31 @@ remoteDispatchNumOfInterfaces (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchListInterfaces (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListInterfaces (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_interfaces_args *args, remote_list_interfaces_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_INTERFACE_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_INTERFACE_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_INTERFACE_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListInterfaces (conn, + virConnectListInterfaces (priv->conn, ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_len); - remoteDispatchConnError(rerr, conn); return -1; } @@ -3267,18 +2980,15 @@ remoteDispatchListInterfaces (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNumOfDefinedInterfaces (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, +remoteDispatchNumOfDefinedInterfaces (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_defined_interfaces_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfDefinedInterfaces (conn); + ret->num = virConnectNumOfDefinedInterfaces (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3286,33 +2996,31 @@ remoteDispatchNumOfDefinedInterfaces (struct qemud_server *server ATTRIBUTE_UNUS } static int -remoteDispatchListDefinedInterfaces (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListDefinedInterfaces (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_defined_interfaces_args *args, remote_list_defined_interfaces_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_DEFINED_INTERFACE_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_DEFINED_INTERFACE_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_DEFINED_INTERFACE_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListDefinedInterfaces (conn, + virConnectListDefinedInterfaces (priv->conn, ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_len); - remoteDispatchConnError(rerr, conn); return -1; } @@ -3320,19 +3028,17 @@ remoteDispatchListDefinedInterfaces (struct qemud_server *server ATTRIBUTE_UNUSE } static int -remoteDispatchInterfaceLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchInterfaceLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_interface_lookup_by_name_args *args, remote_interface_lookup_by_name_ret *ret) { virInterfacePtr iface; + CHECK_CONN(client); - iface = virInterfaceLookupByName (conn, args->name); + iface = virInterfaceLookupByName (priv->conn, args->name); if (iface == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3342,19 +3048,17 @@ remoteDispatchInterfaceLookupByName (struct qemud_server *server ATTRIBUTE_UNUSE } static int -remoteDispatchInterfaceLookupByMacString (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchInterfaceLookupByMacString (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_interface_lookup_by_mac_string_args *args, remote_interface_lookup_by_mac_string_ret *ret) { virInterfacePtr iface; + CHECK_CONN(client); - iface = virInterfaceLookupByMACString (conn, args->mac); + iface = virInterfaceLookupByMACString (priv->conn, args->mac); if (iface == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3364,19 +3068,17 @@ remoteDispatchInterfaceLookupByMacString (struct qemud_server *server ATTRIBUTE_ } static int -remoteDispatchInterfaceGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchInterfaceGetXmlDesc (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_interface_get_xml_desc_args *args, remote_interface_get_xml_desc_ret *ret) { virInterfacePtr iface; + CHECK_CONN(client); - iface = get_nonnull_interface (conn, args->iface); + iface = get_nonnull_interface (priv->conn, args->iface); if (iface == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3384,7 +3086,6 @@ remoteDispatchInterfaceGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, ret->xml = virInterfaceGetXMLDesc (iface, args->flags); if (!ret->xml) { virInterfaceFree(iface); - remoteDispatchConnError(rerr, conn); return -1; } virInterfaceFree(iface); @@ -3392,19 +3093,17 @@ remoteDispatchInterfaceGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchInterfaceDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchInterfaceDefineXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_interface_define_xml_args *args, remote_interface_define_xml_ret *ret) { virInterfacePtr iface; + CHECK_CONN(client); - iface = virInterfaceDefineXML (conn, args->xml, args->flags); + iface = virInterfaceDefineXML (priv->conn, args->xml, args->flags); if (iface == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -3414,25 +3113,21 @@ remoteDispatchInterfaceDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchInterfaceUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_interface_undefine_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchInterfaceUndefine (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_interface_undefine_args *args) { virInterfacePtr iface; + CHECK_CONN(client); - iface = get_nonnull_interface (conn, args->iface); + iface = get_nonnull_interface (priv->conn, args->iface); if (iface == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virInterfaceUndefine (iface) == -1) { virInterfaceFree(iface); - remoteDispatchConnError(rerr, conn); return -1; } virInterfaceFree(iface); @@ -3440,25 +3135,21 @@ remoteDispatchInterfaceUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchInterfaceCreate (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_interface_create_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchInterfaceCreate (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_interface_create_args *args) { virInterfacePtr iface; + CHECK_CONN(client); - iface = get_nonnull_interface (conn, args->iface); + iface = get_nonnull_interface (priv->conn, args->iface); if (iface == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virInterfaceCreate (iface, args->flags) == -1) { virInterfaceFree(iface); - remoteDispatchConnError(rerr, conn); return -1; } virInterfaceFree(iface); @@ -3466,25 +3157,21 @@ remoteDispatchInterfaceCreate (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchInterfaceDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_interface_destroy_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchInterfaceDestroy (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_interface_destroy_args *args) { virInterfacePtr iface; + CHECK_CONN(client); - iface = get_nonnull_interface (conn, args->iface); + iface = get_nonnull_interface (priv->conn, args->iface); if (iface == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virInterfaceDestroy (iface, args->flags) == -1) { virInterfaceFree(iface); - remoteDispatchConnError(rerr, conn); return -1; } virInterfaceFree(iface); @@ -3494,30 +3181,37 @@ remoteDispatchInterfaceDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, /*-------------------------------------------------------------*/ 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, remote_auth_list_ret *ret) { + int auth = virNetServerClientGetAuth(client); + ret->types.types_len = 1; if (VIR_ALLOC_N(ret->types.types_val, ret->types.types_len) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } - 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; + } return 0; } -#if HAVE_SASL /* * Initializes the SASL session in prepare for authentication * and gives the client a list of allowed mechanisms to choose @@ -3525,324 +3219,166 @@ remoteDispatchAuthList (struct qemud_server *server, * XXX callbacks for stuff like password verification ? */ static int -remoteDispatchAuthSaslInit (struct qemud_server *server, - struct qemud_client *client, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - void *args ATTRIBUTE_UNUSED, +remoteDispatchAuthSaslInit (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, 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); - REMOTE_DEBUG("Initialize SASL auth %d", client->fd); - if (client->auth != REMOTE_AUTH_SASL || - client->saslconn != NULL) { + REMOTE_DEBUG("Initialize SASL auth %d", virNetServerClientGetFD(client)); + if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL || + priv->sasl != NULL) { VIR_ERROR0(_("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]; - remoteDispatchFormatError(rerr, - _("failed to get sock address: %s"), - virStrerror(errno, ebuf, sizeof ebuf)); - goto error; - } - if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL) { - remoteDispatchConnError(rerr, conn); - 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]; - remoteDispatchFormatError(rerr, _("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); - remoteDispatchConnError(rerr, conn); - 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_ERROR0(_("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 */ + + 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; + if (!(ret->mechlist = virNetSASLSessionListMechanisms(sasl))) goto authfail; - } - REMOTE_DEBUG("Available mechanisms for client: '%s'", mechlist); - ret->mechlist = strdup(mechlist); - if (!ret->mechlist) { - VIR_ERROR0(_("cannot allocate mechlist")); - sasl_dispose(&client->saslconn); - client->saslconn = NULL; - goto authfail; - } + REMOTE_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")); + 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; - } - ssf = *(const int *)val; - REMOTE_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; - return -2; - } +remoteSASLFinish(virNetServerClientPtr client) +{ + const char *identity; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + int ssf; - /* 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; + /* TLS or UNIX domain sockets trivially OK */ + if (!virNetServerClientIsSecure(client)) { + if ((ssf = virNetSASLSessionGetKeySize(priv->sasl)) < 0) + return -1; - /* We have a SSF !*/ - return 0; -} + REMOTE_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; + } + } -/* - * 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; + if (!(identity = virNetSASLSessionGetIdentity(priv->sasl))) + return -2; - 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_ERROR0(_("no client username was found")); - remoteDispatchAuthError(rerr); - sasl_dispose(&client->saslconn); - client->saslconn = NULL; - return -1; - } - REMOTE_DEBUG("SASL client username %s", (const char *)val); + if (!virNetSASLContextCheckIdentity(saslCtxt, identity)) + return -2; - client->saslUsername = strdup((const char*)val); - if (client->saslUsername == NULL) { - VIR_ERROR0(_("out of memory copying username")); - remoteDispatchAuthError(rerr); - sasl_dispose(&client->saslconn); - client->saslconn = NULL; + if (virNetServerClientSetIdentity(client, identity) < 0) return -1; - } - /* If the list is not set, allow any DN. */ - wildcards = server->saslUsernameWhitelist; - if (!wildcards) - return 0; /* No ACL, allow all */ - while (*wildcards) { - if (fnmatch (*wildcards, client->saslUsername, 0) == 0) - return 0; /* Allowed */ - wildcards++; - } + virNetServerClientSetSASLSession(client, priv->sasl); - /* Denied */ - VIR_ERROR(_("SASL client %s not allowed in whitelist"), client->saslUsername); - remoteDispatchAuthError(rerr); - sasl_dispose(&client->saslconn); - client->saslconn = NULL; - return -2; -} + REMOTE_DEBUG("Authentication successful %d", virNetServerClientGetFD(client)); + PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s", + virNetServerClientGetFD(client), REMOTE_AUTH_SASL, + virNetSASLSessionGetIdentity(priv->sasl)); + virNetSASLSessionFree(priv->sasl); + priv->sasl = NULL; + + return 0; +} /* * 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, remote_auth_sasl_start_args *args, remote_auth_sasl_start_ret *ret) { const char *serverout; - unsigned int serveroutlen; + size_t serveroutlen; int err; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); - virMutexLock(&server->lock); - virMutexLock(&client->lock); - virMutexUnlock(&server->lock); + virMutexLock(&priv->lock); - REMOTE_DEBUG("Start SASL auth %d", client->fd); - if (client->auth != REMOTE_AUTH_SASL || - client->saslconn == NULL) { + REMOTE_DEBUG("Start SASL auth %d", virNetServerClientGetFD(client)); + if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL || + priv->sasl == NULL) { VIR_ERROR0(_("client tried invalid SASL start request")); goto authfail; } REMOTE_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) { - remoteDispatchOOMError(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; @@ -3851,99 +3387,90 @@ remoteDispatchAuthSaslStart (struct qemud_server *server, ret->data.data_len = serveroutlen; REMOTE_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; } - REMOTE_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")); + 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, remote_auth_sasl_step_args *args, remote_auth_sasl_step_ret *ret) { const char *serverout; - unsigned int serveroutlen; + size_t serveroutlen; int err; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); - virMutexLock(&server->lock); - virMutexLock(&client->lock); - virMutexUnlock(&server->lock); - REMOTE_DEBUG("Step SASL auth %d", client->fd); - if (client->auth != REMOTE_AUTH_SASL || - client->saslconn == NULL) { + virMutexLock(&priv->lock); + + REMOTE_DEBUG("Step SASL auth %d", virNetServerClientGetFD(client)); + if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_SASL || + priv->sasl == NULL) { VIR_ERROR0(_("client tried invalid SASL start request")); goto authfail; } - REMOTE_DEBUG("Using SASL Data %d bytes, nil: %d", + REMOTE_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) { - remoteDispatchOOMError(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; @@ -3952,100 +3479,51 @@ remoteDispatchAuthSaslStep (struct qemud_server *server, ret->data.data_len = serveroutlen; REMOTE_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; } - REMOTE_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")); + virMutexUnlock(&priv->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_ERROR0(_("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_ERROR0(_("client tried unsupported SASL start request")); - PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL); - remoteDispatchAuthError(rerr); - 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_ERROR0(_("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, remote_auth_polkit_ret *ret) { pid_t callerPid = -1; @@ -4055,14 +3533,14 @@ remoteDispatchAuthPolkit (struct qemud_server *server, char pidbuf[50]; char ident[100]; int rv; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); - memset(ident, 0, sizeof ident); - virMutexLock(&server->lock); - virMutexLock(&client->lock); - virMutexUnlock(&server->lock); + memset(ident, 0, sizeof ident); - action = client->readonly ? + virMutexLock(&priv->lock); + action = virNetServerClientGetReadonly(client) ? "org.libvirt.unix.monitor" : "org.libvirt.unix.manage"; @@ -4074,13 +3552,13 @@ remoteDispatchAuthPolkit (struct qemud_server *server, NULL }; - REMOTE_DEBUG("Start PolicyKit auth %d", client->fd); - if (client->auth != REMOTE_AUTH_POLKIT) { + REMOTE_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client)); + if (virNetServerClientGetAuth(client) != VIR_NET_SERVER_SERVICE_AUTH_POLKIT) { VIR_ERROR0(_("client tried invalid PolicyKit init request")); goto authfail; } - if (qemudGetSocketIdentity(client->fd, &callerUid, &callerPid) < 0) { + if (qemudGetSocketIdentity(virNetServerClientGetFD(client), &callerUid, &callerPid) < 0) { VIR_ERROR0(_("cannot get peer socket identity")); goto authfail; } @@ -4109,37 +3587,38 @@ remoteDispatchAuthPolkit (struct qemud_server *server, 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; 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); + virResetLastError(); + virNetError(VIR_ERR_AUTH_FAILED, "%s", + _("authentication failed")); + virMutexUnlock(&priv->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, remote_auth_polkit_ret *ret) { pid_t callerPid; @@ -4153,6 +3632,9 @@ remoteDispatchAuthPolkit (struct qemud_server *server, const char *action; char ident[100]; int rv; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + memset(ident, 0, sizeof ident); @@ -4164,13 +3646,13 @@ remoteDispatchAuthPolkit (struct qemud_server *server, "org.libvirt.unix.monitor" : "org.libvirt.unix.manage"; - REMOTE_DEBUG("Start PolicyKit auth %d", client->fd); + REMOTE_DEBUG("Start PolicyKit auth %d", virNetServerClientGetFD(client)); if (client->auth != REMOTE_AUTH_POLKIT) { VIR_ERROR0(_("client tried invalid PolicyKit init request")); goto authfail; } - if (qemudGetSocketIdentity(client->fd, &callerUid, &callerPid) < 0) { + if (qemudGetSocketIdentity(virNetServerClientGetFD(client), &callerUid, &callerPid) < 0) { VIR_ERROR0(_("cannot get peer socket identity")); goto authfail; } @@ -4240,7 +3722,7 @@ remoteDispatchAuthPolkit (struct qemud_server *server, 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)); @@ -4251,16 +3733,19 @@ remoteDispatchAuthPolkit (struct qemud_server *server, return 0; 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); + virResetLastError(); + virNetError(VIR_ERR_AUTH_FAILED, "%s", + _("authentication failed")); virMutexUnlock(&client->lock); return -1; } @@ -4268,12 +3753,9 @@ error: #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, remote_auth_polkit_ret *ret ATTRIBUTE_UNUSED) { VIR_ERROR0(_("client tried unsupported PolicyKit init request")); @@ -4289,33 +3771,31 @@ remoteDispatchAuthPolkit (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchListDefinedStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListDefinedStoragePools (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_defined_storage_pools_args *args, remote_list_defined_storage_pools_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_NETWORK_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, "%s", - _("maxnames > REMOTE_NETWORK_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, "%s", + _("maxnames > REMOTE_NETWORK_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListDefinedStoragePools (conn, + virConnectListDefinedStoragePools (priv->conn, ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_val); - remoteDispatchConnError(rerr, conn); return -1; } @@ -4323,33 +3803,31 @@ remoteDispatchListDefinedStoragePools (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchListStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListStoragePools (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_storage_pools_args *args, remote_list_storage_pools_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, "%s", + _("maxnames > REMOTE_STORAGE_POOL_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListStoragePools (conn, - ret->names.names_val, args->maxnames); + virConnectListStoragePools (priv->conn, + ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_val); - remoteDispatchConnError(rerr, conn); return -1; } @@ -4357,21 +3835,20 @@ remoteDispatchListStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchFindStoragePoolSources (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchFindStoragePoolSources (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_find_storage_pool_sources_args *args, remote_find_storage_pool_sources_ret *ret) { + CHECK_CONN(client); + ret->xml = - virConnectFindStoragePoolSources (conn, + virConnectFindStoragePoolSources (priv->conn, args->type, args->srcSpec ? *args->srcSpec : NULL, args->flags); if (ret->xml == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4380,25 +3857,21 @@ remoteDispatchFindStoragePoolSources (struct qemud_server *server ATTRIBUTE_UNUS static int -remoteDispatchStoragePoolCreate (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_pool_create_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStoragePoolCreate (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_pool_create_args *args) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolCreate (pool, args->flags) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4406,19 +3879,17 @@ remoteDispatchStoragePoolCreate (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStoragePoolCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolCreateXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_create_xml_args *args, remote_storage_pool_create_xml_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = virStoragePoolCreateXML (conn, args->xml, args->flags); + pool = virStoragePoolCreateXML (priv->conn, args->xml, args->flags); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4428,19 +3899,17 @@ remoteDispatchStoragePoolCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchStoragePoolDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolDefineXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_define_xml_args *args, remote_storage_pool_define_xml_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = virStoragePoolDefineXML (conn, args->xml, args->flags); + pool = virStoragePoolDefineXML (priv->conn, args->xml, args->flags); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4450,25 +3919,21 @@ remoteDispatchStoragePoolDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchStoragePoolBuild (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_pool_build_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStoragePoolBuild (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_pool_build_args *args) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolBuild (pool, args->flags) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4477,25 +3942,21 @@ remoteDispatchStoragePoolBuild (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchStoragePoolDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_pool_destroy_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStoragePoolDestroy (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_pool_destroy_args *args) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolDestroy (pool) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4503,25 +3964,21 @@ remoteDispatchStoragePoolDestroy (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStoragePoolDelete (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_pool_delete_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStoragePoolDelete (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_pool_delete_args *args) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolDelete (pool, args->flags) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4529,25 +3986,21 @@ remoteDispatchStoragePoolDelete (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStoragePoolRefresh (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_pool_refresh_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStoragePoolRefresh (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_pool_refresh_args *args) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolRefresh (pool, args->flags) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4555,26 +4008,23 @@ remoteDispatchStoragePoolRefresh (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStoragePoolGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolGetInfo (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_get_info_args *args, remote_storage_pool_get_info_ret *ret) { virStoragePoolPtr pool; virStoragePoolInfo info; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolGetInfo (pool, &info) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } @@ -4589,19 +4039,17 @@ remoteDispatchStoragePoolGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStoragePoolDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolDumpXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_dump_xml_args *args, remote_storage_pool_dump_xml_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4609,7 +4057,6 @@ remoteDispatchStoragePoolDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, ret->xml = virStoragePoolGetXMLDesc (pool, args->flags); if (!ret->xml) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4617,25 +4064,22 @@ remoteDispatchStoragePoolDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStoragePoolGetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolGetAutostart (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_get_autostart_args *args, remote_storage_pool_get_autostart_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolGetAutostart (pool, &ret->autostart) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4644,19 +4088,17 @@ remoteDispatchStoragePoolGetAutostart (struct qemud_server *server ATTRIBUTE_UNU static int -remoteDispatchStoragePoolLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_lookup_by_name_args *args, remote_storage_pool_lookup_by_name_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = virStoragePoolLookupByName (conn, args->name); + pool = virStoragePoolLookupByName (priv->conn, args->name); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4666,19 +4108,17 @@ remoteDispatchStoragePoolLookupByName (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchStoragePoolLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolLookupByUuid (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_lookup_by_uuid_args *args, remote_storage_pool_lookup_by_uuid_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = virStoragePoolLookupByUUID (conn, (unsigned char *) args->uuid); + pool = virStoragePoolLookupByUUID (priv->conn, (unsigned char *) args->uuid); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4688,27 +4128,24 @@ remoteDispatchStoragePoolLookupByUuid (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchStoragePoolLookupByVolume (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolLookupByVolume (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_lookup_by_volume_args *args, remote_storage_pool_lookup_by_volume_ret *ret) { virStoragePoolPtr pool; virStorageVolPtr vol; + CHECK_CONN(client); - vol = get_nonnull_storage_vol (conn, args->vol); + vol = get_nonnull_storage_vol (priv->conn, args->vol); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } pool = virStoragePoolLookupByVolume (vol); virStorageVolFree(vol); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4718,25 +4155,21 @@ remoteDispatchStoragePoolLookupByVolume (struct qemud_server *server ATTRIBUTE_U } static int -remoteDispatchStoragePoolSetAutostart (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_pool_set_autostart_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStoragePoolSetAutostart (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_pool_set_autostart_args *args) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolSetAutostart (pool, args->autostart) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4744,25 +4177,21 @@ remoteDispatchStoragePoolSetAutostart (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchStoragePoolUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_pool_undefine_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStoragePoolUndefine (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_pool_undefine_args *args) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStoragePoolUndefine (pool) == -1) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } virStoragePoolFree(pool); @@ -4770,18 +4199,15 @@ remoteDispatchStoragePoolUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNumOfStoragePools (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, +remoteDispatchNumOfStoragePools (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_storage_pools_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfStoragePools (conn); + ret->num = virConnectNumOfStoragePools (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4789,18 +4215,15 @@ remoteDispatchNumOfStoragePools (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchNumOfDefinedStoragePools (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, +remoteDispatchNumOfDefinedStoragePools (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_defined_storage_pools_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfDefinedStoragePools (conn); + ret->num = virConnectNumOfDefinedStoragePools (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4808,32 +4231,30 @@ remoteDispatchNumOfDefinedStoragePools (struct qemud_server *server ATTRIBUTE_UN } static int -remoteDispatchStoragePoolListVolumes (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolListVolumes (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_list_volumes_args *args, remote_storage_pool_list_volumes_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); if (args->maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_STORAGE_VOL_NAME_LIST_MAX")); return -1; } - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { + virReportOOMError(); virStoragePoolFree(pool); - remoteDispatchOOMError(rerr); return -1; } @@ -4843,7 +4264,6 @@ remoteDispatchStoragePoolListVolumes (struct qemud_server *server ATTRIBUTE_UNUS virStoragePoolFree(pool); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_val); - remoteDispatchConnError(rerr, conn); return -1; } @@ -4852,26 +4272,23 @@ remoteDispatchStoragePoolListVolumes (struct qemud_server *server ATTRIBUTE_UNUS static int -remoteDispatchStoragePoolNumOfVolumes (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStoragePoolNumOfVolumes (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_num_of_volumes_args *args, remote_storage_pool_num_of_volumes_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } ret->num = virStoragePoolNumOfVolumes (pool); virStoragePoolFree(pool); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4886,27 +4303,24 @@ remoteDispatchStoragePoolNumOfVolumes (struct qemud_server *server ATTRIBUTE_UNU static int -remoteDispatchStorageVolCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolCreateXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_create_xml_args *args, remote_storage_vol_create_xml_ret *ret) { virStoragePoolPtr pool; virStorageVolPtr vol; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } vol = virStorageVolCreateXML (pool, args->xml, args->flags); virStoragePoolFree(pool); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4916,27 +4330,24 @@ remoteDispatchStorageVolCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStorageVolCreateXmlFrom (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolCreateXmlFrom (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_create_xml_from_args *args, remote_storage_vol_create_xml_from_ret *ret) { virStoragePoolPtr pool; virStorageVolPtr clonevol, newvol; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } - clonevol = get_nonnull_storage_vol (conn, args->clonevol); + clonevol = get_nonnull_storage_vol (priv->conn, args->clonevol); if (clonevol == NULL) { virStoragePoolFree(pool); - remoteDispatchConnError(rerr, conn); return -1; } @@ -4945,7 +4356,6 @@ remoteDispatchStorageVolCreateXmlFrom (struct qemud_server *server ATTRIBUTE_UNU virStorageVolFree(clonevol); virStoragePoolFree(pool); if (newvol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -4955,25 +4365,21 @@ remoteDispatchStorageVolCreateXmlFrom (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchStorageVolDelete (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_vol_delete_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStorageVolDelete (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_vol_delete_args *args) { virStorageVolPtr vol; + CHECK_CONN(client); - vol = get_nonnull_storage_vol (conn, args->vol); + vol = get_nonnull_storage_vol (priv->conn, args->vol); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStorageVolDelete (vol, args->flags) == -1) { virStorageVolFree(vol); - remoteDispatchConnError(rerr, conn); return -1; } virStorageVolFree(vol); @@ -4981,25 +4387,21 @@ remoteDispatchStorageVolDelete (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStorageVolWipe(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_storage_vol_wipe_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchStorageVolWipe(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_storage_vol_wipe_args *args) { int retval = -1; virStorageVolPtr vol; + CHECK_CONN(client); - vol = get_nonnull_storage_vol(conn, args->vol); + vol = get_nonnull_storage_vol(priv->conn, args->vol); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); goto out; } if (virStorageVolWipe(vol, args->flags) == -1) { - remoteDispatchConnError(rerr, conn); goto out; } @@ -5013,26 +4415,23 @@ out: } static int -remoteDispatchStorageVolGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolGetInfo (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_get_info_args *args, remote_storage_vol_get_info_ret *ret) { virStorageVolPtr vol; virStorageVolInfo info; + CHECK_CONN(client); - vol = get_nonnull_storage_vol (conn, args->vol); + vol = get_nonnull_storage_vol (priv->conn, args->vol); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virStorageVolGetInfo (vol, &info) == -1) { virStorageVolFree(vol); - remoteDispatchConnError(rerr, conn); return -1; } @@ -5046,19 +4445,17 @@ remoteDispatchStorageVolGetInfo (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchStorageVolDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolDumpXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_dump_xml_args *args, remote_storage_vol_dump_xml_ret *ret) { virStorageVolPtr vol; + CHECK_CONN(client); - vol = get_nonnull_storage_vol (conn, args->vol); + vol = get_nonnull_storage_vol (priv->conn, args->vol); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5066,7 +4463,6 @@ remoteDispatchStorageVolDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, ret->xml = virStorageVolGetXMLDesc (vol, args->flags); if (!ret->xml) { virStorageVolFree(vol); - remoteDispatchConnError(rerr, conn); return -1; } virStorageVolFree(vol); @@ -5075,19 +4471,17 @@ remoteDispatchStorageVolDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchStorageVolGetPath (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolGetPath (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_get_path_args *args, remote_storage_vol_get_path_ret *ret) { virStorageVolPtr vol; + CHECK_CONN(client); - vol = get_nonnull_storage_vol (conn, args->vol); + vol = get_nonnull_storage_vol (priv->conn, args->vol); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5095,7 +4489,6 @@ remoteDispatchStorageVolGetPath (struct qemud_server *server ATTRIBUTE_UNUSED, ret->name = virStorageVolGetPath (vol); if (!ret->name) { virStorageVolFree(vol); - remoteDispatchConnError(rerr, conn); return -1; } virStorageVolFree(vol); @@ -5104,27 +4497,24 @@ remoteDispatchStorageVolGetPath (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchStorageVolLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_lookup_by_name_args *args, remote_storage_vol_lookup_by_name_ret *ret) { virStoragePoolPtr pool; virStorageVolPtr vol; + CHECK_CONN(client); - pool = get_nonnull_storage_pool (conn, args->pool); + pool = get_nonnull_storage_pool (priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } vol = virStorageVolLookupByName (pool, args->name); virStoragePoolFree(pool); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5134,19 +4524,17 @@ remoteDispatchStorageVolLookupByName (struct qemud_server *server ATTRIBUTE_UNUS } static int -remoteDispatchStorageVolLookupByKey (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolLookupByKey (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_lookup_by_key_args *args, remote_storage_vol_lookup_by_key_ret *ret) { virStorageVolPtr vol; + CHECK_CONN(client); - vol = virStorageVolLookupByKey (conn, args->key); + vol = virStorageVolLookupByKey (priv->conn, args->key); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5157,19 +4545,17 @@ remoteDispatchStorageVolLookupByKey (struct qemud_server *server ATTRIBUTE_UNUSE static int -remoteDispatchStorageVolLookupByPath (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchStorageVolLookupByPath (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_vol_lookup_by_path_args *args, remote_storage_vol_lookup_by_path_ret *ret) { virStorageVolPtr vol; + CHECK_CONN(client); - vol = virStorageVolLookupByPath (conn, args->path); + vol = virStorageVolLookupByPath (priv->conn, args->path); if (vol == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5184,21 +4570,18 @@ remoteDispatchStorageVolLookupByPath (struct qemud_server *server ATTRIBUTE_UNUS **************************************************************/ static int -remoteDispatchNodeNumOfDevices (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeNumOfDevices (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_num_of_devices_args *args, remote_node_num_of_devices_ret *ret) { CHECK_CONN(client); - ret->num = virNodeNumOfDevices (conn, + ret->num = virNodeNumOfDevices (priv->conn, args->cap ? *args->cap : NULL, args->flags); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5207,34 +4590,31 @@ remoteDispatchNodeNumOfDevices (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeListDevices (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeListDevices (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_list_devices_args *args, remote_node_list_devices_ret *ret) { CHECK_CONN(client); if (args->maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { - remoteDispatchFormatError(rerr, - "%s", _("maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virNodeListDevices (conn, + virNodeListDevices (priv->conn, args->cap ? *args->cap : NULL, ret->names.names_val, args->maxnames, args->flags); if (ret->names.names_len == -1) { - remoteDispatchConnError(rerr, conn); VIR_FREE(ret->names.names_val); return -1; } @@ -5244,11 +4624,9 @@ remoteDispatchNodeListDevices (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeDeviceLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_device_lookup_by_name_args *args, remote_node_device_lookup_by_name_ret *ret) { @@ -5256,9 +4634,8 @@ remoteDispatchNodeDeviceLookupByName (struct qemud_server *server ATTRIBUTE_UNUS CHECK_CONN(client); - dev = virNodeDeviceLookupByName (conn, args->name); + dev = virNodeDeviceLookupByName (priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5269,27 +4646,23 @@ remoteDispatchNodeDeviceLookupByName (struct qemud_server *server ATTRIBUTE_UNUS static int -remoteDispatchNodeDeviceDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeDeviceDumpXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_device_dump_xml_args *args, remote_node_device_dump_xml_ret *ret) { virNodeDevicePtr dev; CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); + dev = virNodeDeviceLookupByName(priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } /* remoteDispatchClientRequest will free this. */ ret->xml = virNodeDeviceGetXMLDesc (dev, args->flags); if (!ret->xml) { - remoteDispatchConnError(rerr, conn); virNodeDeviceFree(dev); return -1; } @@ -5299,11 +4672,9 @@ remoteDispatchNodeDeviceDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_device_get_parent_args *args, remote_node_device_get_parent_ret *ret) { @@ -5311,9 +4682,8 @@ remoteDispatchNodeDeviceGetParent (struct qemud_server *server ATTRIBUTE_UNUSED, const char *parent; CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); + dev = virNodeDeviceLookupByName(priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5325,14 +4695,14 @@ remoteDispatchNodeDeviceGetParent (struct qemud_server *server ATTRIBUTE_UNUSED, /* remoteDispatchClientRequest will free this. */ char **parent_p; if (VIR_ALLOC(parent_p) < 0) { + virReportOOMError(); virNodeDeviceFree(dev); - remoteDispatchOOMError(rerr); return -1; } *parent_p = strdup(parent); if (*parent_p == NULL) { + virReportOOMError(); virNodeDeviceFree(dev); - remoteDispatchOOMError(rerr); return -1; } ret->parent = parent_p; @@ -5344,27 +4714,23 @@ remoteDispatchNodeDeviceGetParent (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceNumOfCaps (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeDeviceNumOfCaps (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_device_num_of_caps_args *args, remote_node_device_num_of_caps_ret *ret) { virNodeDevicePtr dev; CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); + dev = virNodeDeviceLookupByName(priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } ret->num = virNodeDeviceNumOfCaps(dev); if (ret->num < 0) { virNodeDeviceFree(dev); - remoteDispatchConnError(rerr, conn); return -1; } @@ -5374,34 +4740,30 @@ remoteDispatchNodeDeviceNumOfCaps (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceListCaps (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeDeviceListCaps (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_device_list_caps_args *args, remote_node_device_list_caps_ret *ret) { - virNodeDevicePtr dev; + virNodeDevicePtr dev = NULL; CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); - if (dev == NULL) { - remoteDispatchConnError(rerr, conn); + if (args->maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX")); return -1; } - if (args->maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX) { - virNodeDeviceFree(dev); - remoteDispatchFormatError(rerr, - "%s", _("maxnames > REMOTE_NODE_DEVICE_NAME_LIST_MAX")); + dev = virNodeDeviceLookupByName(priv->conn, args->name); + if (dev == NULL) { return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { + virReportOOMError(); virNodeDeviceFree(dev); - remoteDispatchOOMError(rerr); return -1; } @@ -5410,7 +4772,6 @@ remoteDispatchNodeDeviceListCaps (struct qemud_server *server ATTRIBUTE_UNUSED, args->maxnames); if (ret->names.names_len == -1) { virNodeDeviceFree(dev); - remoteDispatchConnError(rerr, conn); VIR_FREE(ret->names.names_val); return -1; } @@ -5421,26 +4782,21 @@ remoteDispatchNodeDeviceListCaps (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceDettach (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_device_dettach_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNodeDeviceDettach (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_node_device_dettach_args *args) { virNodeDevicePtr dev; CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); + dev = virNodeDeviceLookupByName(priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNodeDeviceDettach(dev) == -1) { virNodeDeviceFree(dev); - remoteDispatchConnError(rerr, conn); return -1; } @@ -5450,26 +4806,21 @@ remoteDispatchNodeDeviceDettach (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceReAttach (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_device_re_attach_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNodeDeviceReAttach (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_node_device_re_attach_args *args) { virNodeDevicePtr dev; CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); + dev = virNodeDeviceLookupByName(priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNodeDeviceReAttach(dev) == -1) { virNodeDeviceFree(dev); - remoteDispatchConnError(rerr, conn); return -1; } @@ -5479,26 +4830,21 @@ remoteDispatchNodeDeviceReAttach (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceReset (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_device_reset_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNodeDeviceReset (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_node_device_reset_args *args) { virNodeDevicePtr dev; CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); + dev = virNodeDeviceLookupByName(priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNodeDeviceReset(dev) == -1) { virNodeDeviceFree(dev); - remoteDispatchConnError(rerr, conn); return -1; } @@ -5508,19 +4854,17 @@ remoteDispatchNodeDeviceReset (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceCreateXml(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNodeDeviceCreateXml(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_node_device_create_xml_args *args, remote_node_device_create_xml_ret *ret) { virNodeDevicePtr dev; + CHECK_CONN(client); - dev = virNodeDeviceCreateXML (conn, args->xml_desc, args->flags); + dev = virNodeDeviceCreateXML (priv->conn, args->xml_desc, args->flags); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -5532,25 +4876,21 @@ remoteDispatchNodeDeviceCreateXml(struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNodeDeviceDestroy(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_device_destroy_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNodeDeviceDestroy(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_node_device_destroy_args *args) { virNodeDevicePtr dev; + CHECK_CONN(client); - dev = virNodeDeviceLookupByName(conn, args->name); + dev = virNodeDeviceLookupByName(priv->conn, args->name); if (dev == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNodeDeviceDestroy(dev) == -1) { virNodeDeviceFree(dev); - remoteDispatchConnError(rerr, conn); return -1; } @@ -5564,136 +4904,109 @@ remoteDispatchNodeDeviceDestroy(struct qemud_server *server ATTRIBUTE_UNUSED, * 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_events_register_ret *ret ATTRIBUTE_UNUSED) { CHECK_CONN(client); int callbackID; - if (client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] != -1) { - remoteDispatchFormatError(rerr, _("domain event %d already registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE); + virMutexLock(&priv->lock); + if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] != -1) { + virNetError(VIR_ERR_RPC, + _("domain event %d already registered"), + VIR_DOMAIN_EVENT_ID_LIFECYCLE); + virMutexUnlock(&priv->lock); return -1; } - if ((callbackID = virConnectDomainEventRegisterAny(conn, + if ((callbackID = virConnectDomainEventRegisterAny(priv->conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle), client, NULL)) < 0) { - remoteDispatchConnError(rerr, conn); + virMutexUnlock(&priv->lock); return -1; } - client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = callbackID; + priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = callbackID; + virMutexUnlock(&priv->lock); return 0; } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_events_deregister_ret *ret ATTRIBUTE_UNUSED) { CHECK_CONN(client); - if (client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] == -1) { - remoteDispatchFormatError(rerr, _("domain event %d not registered"), VIR_DOMAIN_EVENT_ID_LIFECYCLE); + virMutexLock(&priv->lock); + if (priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] == -1) { + virNetError(VIR_ERR_RPC, + _("domain event %d not registered"), + VIR_DOMAIN_EVENT_ID_LIFECYCLE); + virMutexUnlock(&priv->lock); return -1; } - if (virConnectDomainEventDeregisterAny(conn, - client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE]) < 0) { - remoteDispatchConnError(rerr, conn); + if (virConnectDomainEventDeregisterAny(priv->conn, + priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE]) < 0) { + virMutexUnlock(&priv->lock); return -1; } - client->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = -1; + priv->domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LIFECYCLE] = -1; + virMutexUnlock(&priv->lock); return 0; } static void -remoteDispatchDomainEventSend (struct qemud_client *client, - int procnr, - xdrproc_t proc, - void *data) +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 error; - /* 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_error; - - if (!(proc)(&xdr, data)) { - VIR_WARN("Failed to serialize domain event %d", procnr); - goto xdr_error; - } - - /* Update length word to include payload*/ - len = msg->bufferOffset = xdr_getpos (&xdr); - if (xdr_setpos (&xdr, 0) == 0) - goto xdr_error; - - if (!xdr_u_int (&xdr, &len)) - goto xdr_error; + if (virNetMessageEncodePayload(msg, proc, data) < 0) + goto error; - /* Send it. */ - msg->async = 1; - msg->bufferLength = len; - msg->bufferOffset = 0; - qemudClientMessageQueuePush(&client->tx, msg); - qemudUpdateClientEvent(client); + virNetServerClientSendMessage(client, msg); - xdr_destroy (&xdr); return; -xdr_error: - xdr_destroy(&xdr); error: - VIR_FREE(msg); + virNetMessageFree(msg); } static int -remoteDispatchNumOfSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, - void *args ATTRIBUTE_UNUSED, +remoteDispatchNumOfSecrets (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_secrets_ret *ret) { - ret->num = virConnectNumOfSecrets (conn); + CHECK_CONN(client); + + ret->num = virConnectNumOfSecrets (priv->conn); if (ret->num == -1) { - remoteDispatchConnError (err, conn); return -1; } @@ -5701,30 +5014,29 @@ remoteDispatchNumOfSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchListSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +remoteDispatchListSecrets (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_secrets_args *args, remote_list_secrets_ret *ret) { + CHECK_CONN(client); + if (args->maxuuids > REMOTE_SECRET_UUID_LIST_MAX) { - remoteDispatchFormatError (err, "%s", - _("maxuuids > REMOTE_SECRET_UUID_LIST_MAX")); + virNetError(VIR_ERR_RPC, "%s", + _("maxuuids > REMOTE_SECRET_UUID_LIST_MAX")); return -1; } if (VIR_ALLOC_N (ret->uuids.uuids_val, args->maxuuids) < 0) { - remoteDispatchOOMError (err); + virReportOOMError(); return -1; } - ret->uuids.uuids_len = virConnectListSecrets (conn, ret->uuids.uuids_val, + ret->uuids.uuids_len = virConnectListSecrets (priv->conn, ret->uuids.uuids_val, args->maxuuids); if (ret->uuids.uuids_len == -1) { VIR_FREE (ret->uuids.uuids_val); - remoteDispatchConnError (err, conn); return -1; } @@ -5732,19 +5044,17 @@ remoteDispatchListSecrets (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchSecretDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +remoteDispatchSecretDefineXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_secret_define_xml_args *args, remote_secret_define_xml_ret *ret) { virSecretPtr secret; + CHECK_CONN(client); - secret = virSecretDefineXML (conn, args->xml, args->flags); + secret = virSecretDefineXML (priv->conn, args->xml, args->flags); if (secret == NULL) { - remoteDispatchConnError (err, conn); return -1; } @@ -5754,27 +5064,24 @@ remoteDispatchSecretDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, } 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 *err, +remoteDispatchSecretGetValue (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_secret_get_value_args *args, remote_secret_get_value_ret *ret) { virSecretPtr secret; size_t value_size; unsigned char *value; + CHECK_CONN(client); - secret = get_nonnull_secret (conn, args->secret); + secret = get_nonnull_secret (priv->conn, args->secret); if (secret == NULL) { - remoteDispatchConnError (err, conn); return -1; } value = virSecretGetValue (secret, &value_size, args->flags); if (value == NULL) { - remoteDispatchConnError (err, conn); virSecretFree(secret); return -1; } @@ -5786,24 +5093,21 @@ remoteDispatchSecretGetValue (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchSecretGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +remoteDispatchSecretGetXmlDesc (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_secret_get_xml_desc_args *args, remote_secret_get_xml_desc_ret *ret) { virSecretPtr secret; + CHECK_CONN(client); - secret = get_nonnull_secret (conn, args->secret); + secret = get_nonnull_secret (priv->conn, args->secret); if (secret == NULL) { - remoteDispatchConnError (err, conn); return -1; } ret->xml = virSecretGetXMLDesc (secret, args->flags); if (ret->xml == NULL) { - remoteDispatchConnError (err, conn); virSecretFree(secret); return -1; } @@ -5812,19 +5116,17 @@ remoteDispatchSecretGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchSecretLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +remoteDispatchSecretLookupByUuid (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_secret_lookup_by_uuid_args *args, remote_secret_lookup_by_uuid_ret *ret) { virSecretPtr secret; + CHECK_CONN(client); - secret = virSecretLookupByUUID (conn, (unsigned char *)args->uuid); + secret = virSecretLookupByUUID (priv->conn, (unsigned char *)args->uuid); if (secret == NULL) { - remoteDispatchConnError (err, conn); return -1; } @@ -5834,24 +5136,20 @@ remoteDispatchSecretLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchSecretSetValue (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, - remote_secret_set_value_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchSecretSetValue (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_secret_set_value_args *args) { virSecretPtr secret; + CHECK_CONN(client); - secret = get_nonnull_secret (conn, args->secret); + secret = get_nonnull_secret (priv->conn, args->secret); if (secret == NULL) { - remoteDispatchConnError (err, conn); return -1; } if (virSecretSetValue (secret, (const unsigned char *)args->value.value_val, args->value.value_len, args->flags) < 0) { - remoteDispatchConnError (err, conn); virSecretFree(secret); return -1; } @@ -5861,23 +5159,19 @@ remoteDispatchSecretSetValue (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchSecretUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, - remote_secret_undefine_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchSecretUndefine (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_secret_undefine_args *args) { virSecretPtr secret; + CHECK_CONN(client); - secret = get_nonnull_secret (conn, args->secret); + secret = get_nonnull_secret (priv->conn, args->secret); if (secret == NULL) { - remoteDispatchConnError (err, conn); return -1; } if (virSecretUndefine (secret) < 0) { - remoteDispatchConnError (err, conn); virSecretFree(secret); return -1; } @@ -5887,19 +5181,17 @@ remoteDispatchSecretUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchSecretLookupByUsage (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +remoteDispatchSecretLookupByUsage (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_secret_lookup_by_usage_args *args, remote_secret_lookup_by_usage_ret *ret) { virSecretPtr secret; + CHECK_CONN(client); - secret = virSecretLookupByUsage (conn, args->usageType, args->usageID); + secret = virSecretLookupByUsage (priv->conn, args->usageType, args->usageID); if (secret == NULL) { - remoteDispatchConnError (err, conn); return -1; } @@ -5909,19 +5201,17 @@ remoteDispatchSecretLookupByUsage (struct qemud_server *server ATTRIBUTE_UNUSED, } -static int remoteDispatchDomainIsActive(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchDomainIsActive(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_is_active_args *args, remote_domain_is_active_ret *ret) { virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->dom); + domain = get_nonnull_domain(priv->conn, args->dom); if (domain == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -5929,7 +5219,6 @@ static int remoteDispatchDomainIsActive(struct qemud_server *server ATTRIBUTE_UN if (ret->active < 0) { virDomainFree(domain); - remoteDispatchConnError(err, conn); return -1; } @@ -5937,19 +5226,17 @@ static int remoteDispatchDomainIsActive(struct qemud_server *server ATTRIBUTE_UN return 0; } -static int remoteDispatchDomainIsPersistent(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchDomainIsPersistent(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_is_persistent_args *args, remote_domain_is_persistent_ret *ret) { virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->dom); + domain = get_nonnull_domain(priv->conn, args->dom); if (domain == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -5957,7 +5244,6 @@ static int remoteDispatchDomainIsPersistent(struct qemud_server *server ATTRIBUT if (ret->persistent < 0) { virDomainFree(domain); - remoteDispatchConnError(err, conn); return -1; } @@ -5965,19 +5251,17 @@ static int remoteDispatchDomainIsPersistent(struct qemud_server *server ATTRIBUT return 0; } -static int remoteDispatchDomainIsUpdated(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchDomainIsUpdated(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_is_updated_args *args, remote_domain_is_updated_ret *ret) { virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->dom); + domain = get_nonnull_domain(priv->conn, args->dom); if (domain == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -5985,7 +5269,6 @@ static int remoteDispatchDomainIsUpdated(struct qemud_server *server ATTRIBUTE_U if (ret->updated < 0) { virDomainFree(domain); - remoteDispatchConnError(err, conn); return -1; } @@ -5993,19 +5276,17 @@ static int remoteDispatchDomainIsUpdated(struct qemud_server *server ATTRIBUTE_U return 0; } -static int remoteDispatchInterfaceIsActive(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchInterfaceIsActive(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_interface_is_active_args *args, remote_interface_is_active_ret *ret) { virInterfacePtr iface; + CHECK_CONN(client); - iface = get_nonnull_interface(conn, args->iface); + iface = get_nonnull_interface(priv->conn, args->iface); if (iface == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -6013,7 +5294,6 @@ static int remoteDispatchInterfaceIsActive(struct qemud_server *server ATTRIBUTE if (ret->active < 0) { virInterfaceFree(iface); - remoteDispatchConnError(err, conn); return -1; } @@ -6021,19 +5301,17 @@ static int remoteDispatchInterfaceIsActive(struct qemud_server *server ATTRIBUTE return 0; } -static int remoteDispatchNetworkIsActive(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchNetworkIsActive(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_is_active_args *args, remote_network_is_active_ret *ret) { virNetworkPtr network; + CHECK_CONN(client); - network = get_nonnull_network(conn, args->net); + network = get_nonnull_network(priv->conn, args->net); if (network == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -6041,7 +5319,6 @@ static int remoteDispatchNetworkIsActive(struct qemud_server *server ATTRIBUTE_U if (ret->active < 0) { virNetworkFree(network); - remoteDispatchConnError(err, conn); return -1; } @@ -6049,19 +5326,17 @@ static int remoteDispatchNetworkIsActive(struct qemud_server *server ATTRIBUTE_U return 0; } -static int remoteDispatchNetworkIsPersistent(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchNetworkIsPersistent(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_network_is_persistent_args *args, remote_network_is_persistent_ret *ret) { virNetworkPtr network; + CHECK_CONN(client); - network = get_nonnull_network(conn, args->net); + network = get_nonnull_network(priv->conn, args->net); if (network == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -6069,7 +5344,6 @@ static int remoteDispatchNetworkIsPersistent(struct qemud_server *server ATTRIBU if (ret->persistent < 0) { virNetworkFree(network); - remoteDispatchConnError(err, conn); return -1; } @@ -6077,19 +5351,17 @@ static int remoteDispatchNetworkIsPersistent(struct qemud_server *server ATTRIBU return 0; } -static int remoteDispatchStoragePoolIsActive(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchStoragePoolIsActive(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_is_active_args *args, remote_storage_pool_is_active_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool(conn, args->pool); + pool = get_nonnull_storage_pool(priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -6097,7 +5369,6 @@ static int remoteDispatchStoragePoolIsActive(struct qemud_server *server ATTRIBU if (ret->active < 0) { virStoragePoolFree(pool); - remoteDispatchConnError(err, conn); return -1; } @@ -6105,19 +5376,17 @@ static int remoteDispatchStoragePoolIsActive(struct qemud_server *server ATTRIBU return 0; } -static int remoteDispatchStoragePoolIsPersistent(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +static int remoteDispatchStoragePoolIsPersistent(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_storage_pool_is_persistent_args *args, remote_storage_pool_is_persistent_ret *ret) { virStoragePoolPtr pool; + CHECK_CONN(client); - pool = get_nonnull_storage_pool(conn, args->pool); + pool = get_nonnull_storage_pool(priv->conn, args->pool); if (pool == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -6125,7 +5394,6 @@ static int remoteDispatchStoragePoolIsPersistent(struct qemud_server *server ATT if (ret->persistent < 0) { virStoragePoolFree(pool); - remoteDispatchConnError(err, conn); return -1; } @@ -6134,18 +5402,16 @@ static int remoteDispatchStoragePoolIsPersistent(struct qemud_server *server ATT } -static int remoteDispatchIsSecure(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, - void *args ATTRIBUTE_UNUSED, +static int remoteDispatchIsSecure(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_is_secure_ret *ret) { - ret->secure = virConnectIsSecure(conn); + CHECK_CONN(client); + + ret->secure = virConnectIsSecure(priv->conn); if (ret->secure < 0) { - remoteDispatchConnError(err, conn); return -1; } @@ -6154,19 +5420,17 @@ static int remoteDispatchIsSecure(struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchCpuCompare(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +remoteDispatchCpuCompare(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_cpu_compare_args *args, remote_cpu_compare_ret *ret) { int result; + CHECK_CONN(client); - result = virConnectCompareCPU(conn, args->xml, args->flags); + result = virConnectCompareCPU(priv->conn, args->xml, args->flags); if (result == VIR_CPU_COMPARE_ERROR) { - remoteDispatchConnError(err, conn); return -1; } @@ -6176,22 +5440,20 @@ remoteDispatchCpuCompare(struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchCpuBaseline(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *err, +remoteDispatchCpuBaseline(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_cpu_baseline_args *args, remote_cpu_baseline_ret *ret) { char *cpu; + CHECK_CONN(client); - cpu = virConnectBaselineCPU(conn, + cpu = virConnectBaselineCPU(priv->conn, (const char **) args->xmlCPUs.xmlCPUs_val, args->xmlCPUs.xmlCPUs_len, args->flags); if (cpu == NULL) { - remoteDispatchConnError(err, conn); return -1; } @@ -6202,26 +5464,23 @@ remoteDispatchCpuBaseline(struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainGetJobInfo (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetJobInfo (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_job_info_args *args, remote_domain_get_job_info_ret *ret) { virDomainPtr dom; virDomainJobInfo info; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainGetJobInfo (dom, &info) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6245,25 +5504,21 @@ remoteDispatchDomainGetJobInfo (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainAbortJob (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_abort_job_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainAbortJob (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_abort_job_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainAbortJob (dom) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6274,25 +5529,21 @@ remoteDispatchDomainAbortJob (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainMigrateSetMaxDowntime(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_set_max_downtime_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainMigrateSetMaxDowntime(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_migrate_set_max_downtime_args *args) { virDomainPtr dom; + CHECK_CONN(client); - dom = get_nonnull_domain(conn, args->dom); + dom = get_nonnull_domain(priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainMigrateSetMaxDowntime(dom, args->downtime, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6302,27 +5553,24 @@ remoteDispatchDomainMigrateSetMaxDowntime(struct qemud_server *server ATTRIBUTE_ } static int -remoteDispatchDomainSnapshotCreateXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainSnapshotCreateXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_snapshot_create_xml_args *args, remote_domain_snapshot_create_xml_ret *ret) { virDomainSnapshotPtr snapshot; virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->domain); + domain = get_nonnull_domain(priv->conn, args->domain); if (domain == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } snapshot = virDomainSnapshotCreateXML(domain, args->xml_desc, args->flags); if (snapshot == NULL) { virDomainFree(domain); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6335,19 +5583,18 @@ remoteDispatchDomainSnapshotCreateXml (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchDomainSnapshotDumpXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainSnapshotDumpXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_snapshot_dump_xml_args *args, remote_domain_snapshot_dump_xml_ret *ret) { virDomainPtr domain = NULL; virDomainSnapshotPtr snapshot = NULL; int rc = -1; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->snap.domain); + domain = get_nonnull_domain(priv->conn, args->snap.domain); if (domain == NULL) goto cleanup; @@ -6367,33 +5614,28 @@ cleanup: virDomainSnapshotFree(snapshot); if (domain) virDomainFree(domain); - if (rc < 0) - remoteDispatchConnError(rerr, conn); return rc; } static int -remoteDispatchDomainSnapshotNum (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainSnapshotNum (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_snapshot_num_args *args, remote_domain_snapshot_num_ret *ret) { virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->domain); + domain = get_nonnull_domain(priv->conn, args->domain); if (domain == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } ret->num = virDomainSnapshotNum(domain, args->flags); if (ret->num == -1) { virDomainFree(domain); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6403,32 +5645,30 @@ remoteDispatchDomainSnapshotNum (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchDomainSnapshotListNames (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainSnapshotListNames (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_snapshot_list_names_args *args, remote_domain_snapshot_list_names_ret *ret) { virDomainPtr domain; + CHECK_CONN(client); if (args->nameslen > REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX) { - remoteDispatchFormatError (rerr, "%s", - _("nameslen > REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX")); + virNetError(VIR_ERR_RPC, "%s", + _("nameslen > REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX")); return -1; } - domain = get_nonnull_domain(conn, args->domain); + domain = get_nonnull_domain(priv->conn, args->domain); if (domain == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->nameslen) < 0) { + virReportOOMError(); virDomainFree(domain); - remoteDispatchOOMError(rerr); return -1; } @@ -6439,7 +5679,6 @@ remoteDispatchDomainSnapshotListNames (struct qemud_server *server ATTRIBUTE_UNU if (ret->names.names_len == -1) { virDomainFree(domain); VIR_FREE(ret->names.names_val); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6449,27 +5688,24 @@ remoteDispatchDomainSnapshotListNames (struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchDomainSnapshotLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainSnapshotLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_snapshot_lookup_by_name_args *args, remote_domain_snapshot_lookup_by_name_ret *ret) { virDomainSnapshotPtr snapshot; virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->domain); + domain = get_nonnull_domain(priv->conn, args->domain); if (domain == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } snapshot = virDomainSnapshotLookupByName(domain, args->name, args->flags); if (snapshot == NULL) { virDomainFree(domain); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6482,27 +5718,24 @@ remoteDispatchDomainSnapshotLookupByName (struct qemud_server *server ATTRIBUTE_ } static int -remoteDispatchDomainHasCurrentSnapshot(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainHasCurrentSnapshot(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_has_current_snapshot_args *args, remote_domain_has_current_snapshot_ret *ret) { virDomainPtr domain; int result; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->domain); + domain = get_nonnull_domain(priv->conn, args->domain); if (domain == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } result = virDomainHasCurrentSnapshot(domain, args->flags); if (result < 0) { virDomainFree(domain); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6514,27 +5747,24 @@ remoteDispatchDomainHasCurrentSnapshot(struct qemud_server *server ATTRIBUTE_UNU } static int -remoteDispatchDomainSnapshotCurrent(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainSnapshotCurrent(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_snapshot_current_args *args, remote_domain_snapshot_current_ret *ret) { virDomainSnapshotPtr snapshot; virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->domain); + domain = get_nonnull_domain(priv->conn, args->domain); if (domain == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } snapshot = virDomainSnapshotCurrent(domain, args->flags); if (snapshot == NULL) { virDomainFree(domain); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6547,19 +5777,17 @@ remoteDispatchDomainSnapshotCurrent(struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchDomainRevertToSnapshot (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_revert_to_snapshot_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainRevertToSnapshot (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_revert_to_snapshot_args *args) { virDomainPtr domain = NULL; virDomainSnapshotPtr snapshot = NULL; int rc = -1; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->snap.domain); + domain = get_nonnull_domain(priv->conn, args->snap.domain); if (domain == NULL) goto cleanup; @@ -6577,26 +5805,22 @@ cleanup: virDomainSnapshotFree(snapshot); if (domain) virDomainFree(domain); - if (rc < 0) - remoteDispatchConnError(rerr, conn); return rc; } static int -remoteDispatchDomainSnapshotDelete (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_snapshot_delete_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainSnapshotDelete (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_snapshot_delete_args *args) { virDomainPtr domain = NULL; virDomainSnapshotPtr snapshot = NULL; int rc = -1; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->snap.domain); + domain = get_nonnull_domain(priv->conn, args->snap.domain); if (domain == NULL) goto cleanup; @@ -6614,100 +5838,99 @@ cleanup: virDomainSnapshotFree(snapshot); if (domain) virDomainFree(domain); - if (rc < 0) - remoteDispatchConnError(rerr, conn); return rc; } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_events_register_any_args *args) { CHECK_CONN(client); int callbackID; if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST || args->eventID < 0) { - remoteDispatchFormatError(rerr, _("unsupported event ID %d"), args->eventID); + virNetError(VIR_ERR_RPC, + _("unsupported event ID %d"), args->eventID); return -1; } - if (client->domainEventCallbackID[args->eventID] != -1) { - remoteDispatchFormatError(rerr, _("domain event %d already registered"), args->eventID); + virMutexLock(&priv->lock); + if (priv->domainEventCallbackID[args->eventID] != -1) { + virNetError(VIR_ERR_RPC, + _("domain event %d already registered"), args->eventID); + virMutexUnlock(&priv->lock); return -1; } - if ((callbackID = virConnectDomainEventRegisterAny(conn, + if ((callbackID = virConnectDomainEventRegisterAny(priv->conn, NULL, args->eventID, domainEventCallbacks[args->eventID], client, NULL)) < 0) { - remoteDispatchConnError(rerr, conn); + virMutexUnlock(&priv->lock); return -1; } - client->domainEventCallbackID[args->eventID] = callbackID; + priv->domainEventCallbackID[args->eventID] = callbackID; + virMutexUnlock(&priv->lock); return 0; } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_domain_events_deregister_any_args *args) { CHECK_CONN(client); int callbackID = -1; if (args->eventID >= VIR_DOMAIN_EVENT_ID_LAST || args->eventID < 0) { - remoteDispatchFormatError(rerr, _("unsupported event ID %d"), args->eventID); + virNetError(VIR_ERR_RPC, + _("unsupported event ID %d"), args->eventID); return -1; } - callbackID = client->domainEventCallbackID[args->eventID]; + virMutexLock(&priv->lock); + callbackID = priv->domainEventCallbackID[args->eventID]; if (callbackID < 0) { - remoteDispatchFormatError(rerr, _("domain event %d not registered"), args->eventID); + virNetError(VIR_ERR_RPC, + _("domain event %d not registered"), args->eventID); + virMutexUnlock(&priv->lock); return -1; } - if (virConnectDomainEventDeregisterAny(conn, callbackID) < 0) { - remoteDispatchConnError(rerr, conn); + if (virConnectDomainEventDeregisterAny(priv->conn, callbackID) < 0) { return -1; } - client->domainEventCallbackID[args->eventID] = -1; + priv->domainEventCallbackID[args->eventID] = -1; + virMutexUnlock(&priv->lock); return 0; } static int -remoteDispatchNwfilterLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNwfilterLookupByName (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_nwfilter_lookup_by_name_args *args, remote_nwfilter_lookup_by_name_ret *ret) { virNWFilterPtr nwfilter; + CHECK_CONN(client); - nwfilter = virNWFilterLookupByName (conn, args->name); + nwfilter = virNWFilterLookupByName (priv->conn, args->name); if (nwfilter == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -6717,19 +5940,17 @@ remoteDispatchNwfilterLookupByName (struct qemud_server *server ATTRIBUTE_UNUSED } static int -remoteDispatchNwfilterLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNwfilterLookupByUuid (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_nwfilter_lookup_by_uuid_args *args, remote_nwfilter_lookup_by_uuid_ret *ret) { virNWFilterPtr nwfilter; + CHECK_CONN(client); - nwfilter = virNWFilterLookupByUUID (conn, (unsigned char *) args->uuid); + nwfilter = virNWFilterLookupByUUID (priv->conn, (unsigned char *) args->uuid); if (nwfilter == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -6740,19 +5961,17 @@ remoteDispatchNwfilterLookupByUuid (struct qemud_server *server ATTRIBUTE_UNUSED static int -remoteDispatchNwfilterDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchNwfilterDefineXml (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_nwfilter_define_xml_args *args, remote_nwfilter_define_xml_ret *ret) { virNWFilterPtr nwfilter; + CHECK_CONN(client); - nwfilter = virNWFilterDefineXML (conn, args->xml); + nwfilter = virNWFilterDefineXML (priv->conn, args->xml); if (nwfilter == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -6763,25 +5982,21 @@ remoteDispatchNwfilterDefineXml (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNwfilterUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_nwfilter_undefine_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchNwfilterUndefine (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_nwfilter_undefine_args *args) { virNWFilterPtr nwfilter; + CHECK_CONN(client); - nwfilter = get_nonnull_nwfilter (conn, args->nwfilter); + nwfilter = get_nonnull_nwfilter (priv->conn, args->nwfilter); if (nwfilter == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virNWFilterUndefine (nwfilter) == -1) { virNWFilterFree(nwfilter); - remoteDispatchConnError(rerr, conn); return -1; } virNWFilterFree(nwfilter); @@ -6789,33 +6004,31 @@ remoteDispatchNwfilterUndefine (struct qemud_server *server ATTRIBUTE_UNUSED, } static int -remoteDispatchListNwfilters (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchListNwfilters (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_list_nwfilters_args *args, remote_list_nwfilters_ret *ret) { + CHECK_CONN(client); if (args->maxnames > REMOTE_NWFILTER_NAME_LIST_MAX) { - remoteDispatchFormatError (rerr, - "%s", _("maxnames > REMOTE_NWFILTER_NAME_LIST_MAX")); + virNetError(VIR_ERR_RPC, + "%s", _("maxnames > REMOTE_NWFILTER_NAME_LIST_MAX")); return -1; } /* Allocate return buffer. */ if (VIR_ALLOC_N(ret->names.names_val, args->maxnames) < 0) { - remoteDispatchOOMError(rerr); + virReportOOMError(); return -1; } ret->names.names_len = - virConnectListNWFilters (conn, + virConnectListNWFilters (priv->conn, ret->names.names_val, args->maxnames); if (ret->names.names_len == -1) { VIR_FREE(ret->names.names_len); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6824,19 +6037,17 @@ remoteDispatchListNwfilters (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNwfilterGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, - remote_nwfilter_get_xml_desc_args *args, - remote_nwfilter_get_xml_desc_ret *ret) +remoteDispatchNwfilterGetXmlDesc (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, + remote_nwfilter_get_xml_desc_args *args, + remote_nwfilter_get_xml_desc_ret *ret) { virNWFilterPtr nwfilter; + CHECK_CONN(client); - nwfilter = get_nonnull_nwfilter (conn, args->nwfilter); + nwfilter = get_nonnull_nwfilter (priv->conn, args->nwfilter); if (nwfilter == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -6844,7 +6055,6 @@ remoteDispatchNwfilterGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, ret->xml = virNWFilterGetXMLDesc (nwfilter, args->flags); if (!ret->xml) { virNWFilterFree(nwfilter); - remoteDispatchConnError(rerr, conn); return -1; } virNWFilterFree(nwfilter); @@ -6853,18 +6063,15 @@ remoteDispatchNwfilterGetXmlDesc (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchNumOfNwfilters (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, +remoteDispatchNumOfNwfilters (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_num_of_nwfilters_ret *ret) { + CHECK_CONN(client); - ret->num = virConnectNumOfNWFilters (conn); + ret->num = virConnectNumOfNWFilters (priv->conn); if (ret->num == -1) { - remoteDispatchConnError(rerr, conn); return -1; } @@ -6873,26 +6080,23 @@ remoteDispatchNumOfNwfilters (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainGetBlockInfo (struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client ATTRIBUTE_UNUSED, - virConnectPtr conn, - remote_message_header *hdr ATTRIBUTE_UNUSED, - remote_error *rerr, +remoteDispatchDomainGetBlockInfo (virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, remote_domain_get_block_info_args *args, remote_domain_get_block_info_ret *ret) { virDomainPtr dom; virDomainBlockInfo info; + CHECK_CONN(client); - dom = get_nonnull_domain (conn, args->dom); + dom = get_nonnull_domain (priv->conn, args->dom); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainGetBlockInfo (dom, args->path, &info, args->flags) == -1) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6906,26 +6110,23 @@ remoteDispatchDomainGetBlockInfo (struct qemud_server *server ATTRIBUTE_UNUSED, } 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, + virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED, qemu_monitor_command_args *args, qemu_monitor_command_ret *ret) { virDomainPtr domain; + CHECK_CONN(client); - domain = get_nonnull_domain(conn, args->domain); + domain = get_nonnull_domain(priv->conn, args->domain); if (domain == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } if (virDomainQemuMonitorCommand(domain, args->cmd, &ret->result, args->flags) == -1) { virDomainFree(domain); - remoteDispatchConnError(rerr, conn); return -1; } @@ -6936,49 +6137,49 @@ qemuDispatchMonitorCommand (struct qemud_server *server ATTRIBUTE_UNUSED, static int -remoteDispatchDomainOpenConsole(struct qemud_server *server ATTRIBUTE_UNUSED, - struct qemud_client *client, - virConnectPtr conn, - remote_message_header *hdr, - remote_error *rerr, - remote_domain_open_console_args *args, - void *ret ATTRIBUTE_UNUSED) +remoteDispatchDomainOpenConsole(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessageHeaderPtr hdr, + remote_domain_open_console_args *args) { int r; - struct qemud_client_stream *stream; + daemonClientStreamPtr stream; virDomainPtr dom; + virStreamPtr st; CHECK_CONN (client); - dom = get_nonnull_domain (conn, args->domain); + dom = get_nonnull_domain (priv->conn, args->domain); if (dom == NULL) { - remoteDispatchConnError(rerr, conn); return -1; } - stream = remoteCreateClientStream(conn, hdr); + st = virStreamNew(priv->conn, VIR_STREAM_NONBLOCK); + if (!st) { + return -1; + } + + stream = daemonCreateClientStream(client, st, remoteProgram, hdr); if (!stream) { + virStreamFree(st); virDomainFree(dom); - remoteDispatchOOMError(rerr); return -1; } r = virDomainOpenConsole(dom, args->devname ? *args->devname : NULL, - stream->st, + st, args->flags); if (r == -1) { virDomainFree(dom); - remoteFreeClientStream(client, stream); - remoteDispatchConnError(rerr, conn); + daemonFreeClientStream(client, stream); return -1; } - if (remoteAddClientStream(client, stream, 1) < 0) { + if (daemonAddClientStream(client, stream, 1) < 0) { virDomainFree(dom); - remoteDispatchConnError(rerr, conn); - virStreamAbort(stream->st); - remoteFreeClientStream(client, stream); + virStreamAbort(st); + daemonFreeClientStream(client, stream); return -1; } @@ -7117,3 +6318,4 @@ make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virD snapshot_dst->name = strdup(snapshot_src->name); make_nonnull_domain(&snapshot_dst->domain, snapshot_src->domain); } + diff --git a/daemon/remote.h b/daemon/remote.h index 1eb8386..c9bf5d7 100644 --- a/daemon/remote.h +++ b/daemon/remote.h @@ -24,62 +24,20 @@ #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__ */ diff --git a/daemon/stream.c b/daemon/stream.c index cac54ea..a946026 100644 --- a/daemon/stream.c +++ b/daemon/stream.c @@ -24,29 +24,56 @@ #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 virNetError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_RPC, 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) @@ -62,19 +89,15 @@ remoteStreamUpdateEvents(struct qemud_client_stream *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 = daemonFindClientStream(client, st); if (!stream) { VIR_WARN("event for client=%p stream st=%p, but missing stream state", client, st); @@ -85,9 +108,9 @@ remoteStreamEvent(virStreamPtr st, int events, void *opaque) DEBUG("st=%p events=%d", st, events); 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; } } @@ -95,9 +118,9 @@ remoteStreamEvent(virStreamPtr st, int events, void *opaque) 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; } } @@ -105,30 +128,41 @@ remoteStreamEvent(virStreamPtr st, int events, void *opaque) if (!stream->closed && (events & (VIR_STREAM_EVENT_ERROR | VIR_STREAM_EVENT_HANGUP))) { int ret; - remote_error rerr; - memset(&rerr, 0, sizeof rerr); + virNetMessagePtr msg; 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, + 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); } @@ -141,88 +175,68 @@ cleanup: * -1 on fatal client error */ static int -remoteStreamFilter(struct qemud_client *client, - struct qemud_client_message *msg, void *opaque) +daemonStreamFilter(virNetServerClientPtr client ATTRIBUTE_UNUSED, + 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) { - 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; - } - - if (ret < 0) - return -1; - } - return 1; - } - return 0; + daemonClientStream *stream = opaque; + int ret = 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; + + DEBUG("Incoming rx=%p serial=%d proc=%d status=%d", + 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 stram * * 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); - DEBUG("proc=%d serial=%d", hdr->proc, hdr->serial); + DEBUG("proc=%d serial=%d", header->proc, header->serial); if (VIR_ALLOC(stream) < 0) 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; } @@ -233,25 +247,36 @@ remoteCreateClientStream(virConnectPtr conn, * 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; 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; } @@ -259,33 +284,32 @@ void remoteFreeClientStream(struct qemud_client *client, * @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 daemonAddClientStream(virNetServerClientPtr client, + daemonClientStream *stream, int transmit) { - struct qemud_client_stream *tmp = client->streams; - 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); + daemonStreamUpdateEvents(stream); return 0; } @@ -300,11 +324,12 @@ int remoteAddClientStream(struct qemud_client *client, * * Returns a stream object matching the procedure+serial number, or NULL */ -struct qemud_client_stream * -remoteFindClientStream(struct qemud_client *client, +daemonClientStream * +daemonFindClientStream(virNetServerClientPtr client, virStreamPtr st) { - struct qemud_client_stream *stream = client->streams; + daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client); + daemonClientStream *stream = priv->streams; while (stream) { if (stream->st == st) @@ -325,25 +350,18 @@ remoteFindClientStream(struct qemud_client *client, * 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) { 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; - } - } + 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) { @@ -356,9 +374,8 @@ remoteRemoveClientStream(struct qemud_client *client, 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; @@ -374,17 +391,15 @@ remoteRemoveClientStream(struct qemud_client *client, * 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; - 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); + DEBUG("stream=%p proc=%d serial=%d len=%zu offset=%zu", + stream, msg->header.proc, msg->header.serial, + msg->bufferLength, msg->bufferOffset); ret = virStreamSend(stream->st, msg->buffer + msg->bufferOffset, @@ -396,14 +411,20 @@ remoteStreamHandleWriteData(struct qemud_client *client, /* 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 { VIR_INFO0("Stream send failed"); stream->closed = 1; - remoteDispatchConnError(&rerr, client->conn); - return remoteSerializeReplyError(client, &rerr, &msg->hdr); + return virNetServerProgramSendReplyError(stream->prog, + client, + msg, + &msg->header); } return 0; @@ -413,38 +434,39 @@ remoteStreamHandleWriteData(struct qemud_client *client, /* * 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; DEBUG("stream=%p proc=%d serial=%d", - stream, msg->hdr.proc, msg->hdr.serial); - - memset(&rerr, 0, sizeof rerr); + stream, msg->header.proc, msg->header.serial); stream->closed = 1; virStreamEventRemoveCallback(stream->st); ret = virStreamFinish(stream->st); if (ret < 0) { - remoteDispatchConnError(&rerr, client->conn); - return remoteSerializeReplyError(client, &rerr, &msg->hdr); + return virNetServerProgramSendReplyError(stream->prog, + client, + msg, + &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; } @@ -454,30 +476,31 @@ remoteStreamHandleFinish(struct qemud_client *client, * 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; - DEBUG("stream=%p proc=%d serial=%d", - stream, msg->hdr.proc, msg->hdr.serial); - - memset(&rerr, 0, sizeof rerr); + stream, msg->header.proc, msg->header.serial); 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, + &msg->header); } @@ -490,41 +513,39 @@ remoteStreamHandleAbort(struct qemud_client *client, * 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; - DEBUG("stream=%p", 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; @@ -543,11 +564,11 @@ remoteStreamHandleWrite(struct qemud_client *client, * 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; DEBUG("stream=%p", stream); @@ -566,16 +587,29 @@ remoteStreamHandleRead(struct qemud_client *client, * we're readable, but hey things change... */ ret = 0; } else if (ret < 0) { - remote_error rerr; - memset(&rerr, 0, sizeof rerr); - remoteDispatchConnError(&rerr, NULL); - - ret = remoteSerializeStreamError(client, &rerr, stream->procedure, stream->serial); + virNetMessagePtr msg; + if (!(msg = virNetMessageNew())) + ret = -1; + else + ret = virNetServerProgramSendStreamError(remoteProgram, + client, + msg, + 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; + else + ret = virNetServerProgramSendStreamData(remoteProgram, + client, + msg, + stream->procedure, + stream->serial, + buffer, ret); } VIR_FREE(buffer); @@ -591,22 +625,23 @@ remoteStreamHandleRead(struct qemud_client *client, * fast stream, but slow client */ void -remoteStreamMessageFinished(struct qemud_client *client, - struct qemud_client_message *msg) +daemonStreamMessageFinished(virNetServerClientPtr client, + virNetMessagePtr msg) { - struct qemud_client_stream *stream = client->streams; + daemonClientPrivatePtr priv = virNetServerClientGetPrivateData(client); + daemonClientStream *stream = priv->streams; while (stream) { - if (msg->hdr.proc == stream->procedure && - msg->hdr.serial == stream->serial) + if (msg->header.proc == stream->procedure && + msg->header.serial == stream->serial) break; stream = stream->next; } - DEBUG("Message client=%p stream=%p proc=%d serial=%d", client, stream, msg->hdr.proc, msg->hdr.serial); + DEBUG("Message client=%p stream=%p proc=%d serial=%d", client, stream, msg->header.proc, msg->header.serial); if (stream) { stream->tx = 1; - remoteStreamUpdateEvents(stream); + daemonStreamUpdateEvents(stream); } } diff --git a/daemon/stream.h b/daemon/stream.h index 767a763..3855c89 100644 --- a/daemon/stream.h +++ b/daemon/stream.h @@ -28,27 +28,29 @@ -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 daemonAddClientStream(virNetServerClientPtr client, + daemonClientStream *stream, int transmit); -struct qemud_client_stream * -remoteFindClientStream(struct qemud_client *client, +daemonClientStream * +daemonFindClientStream(virNetServerClientPtr client, virStreamPtr stream); int -remoteRemoveClientStream(struct qemud_client *client, - struct qemud_client_stream *stream); +daemonRemoveClientStream(virNetServerClientPtr client, + daemonClientStream *stream); void -remoteStreamMessageFinished(struct qemud_client *client, - struct qemud_client_message *msg); +daemonStreamMessageFinished(virNetServerClientPtr client, + virNetMessagePtr msg); #endif /* __LIBVIRTD_STREAM_H__ */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 0595adf..0c1e887 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,4 +1,3 @@ -daemon/dispatch.c daemon/libvirtd.c daemon/remote.c daemon/stream.c -- 1.7.2.3
participants (3)
-
Daniel P. Berrange
-
Eric Blake
-
Wen Congyang