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
---
cfg.mk | 2 +-
src/Makefile.am | 34 +++++++-
src/rpc/virnetprotocol.c | 207 +++++++++++++++++++++++++++++++++++++++++++
src/rpc/virnetprotocol.h | 137 +++++++++++++++++++++++++++++
src/rpc/virnetprotocol.x | 217 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 595 insertions(+), 2 deletions(-)
create mode 100644 src/rpc/virnetprotocol.c
create mode 100644 src/rpc/virnetprotocol.h
create mode 100644 src/rpc/virnetprotocol.x
diff --git a/cfg.mk b/cfg.mk
index 2076173..a7120e2 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -454,7 +454,7 @@ sc_prohibit_newline_at_end_of_diagnostic:
exit 1; } || :
# Regex for grep -E that exempts generated files from style rules.
-preprocessor_exempt = ((qemu|remote)_(driver|protocol)\.h)$$
+preprocessor_exempt = ((qemu_|remote_|virnet)(protocol)\.h)$$
# Enforce recommended preprocessor indentation style.
sc_preprocessor_indentation:
@if cppi --version >/dev/null 2>&1; then \
diff --git a/src/Makefile.am b/src/Makefile.am
index 1d8115b..e575a61 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -577,6 +577,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.
@@ -587,7 +605,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
@@ -1204,6 +1222,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 =
libexec_PROGRAMS += libvirt_iohelper
diff --git a/src/rpc/virnetprotocol.c b/src/rpc/virnetprotocol.c
new file mode 100644
index 0000000..0484267
--- /dev/null
+++ b/src/rpc/virnetprotocol.c
@@ -0,0 +1,207 @@
+#include <config.h>
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "./rpc/virnetprotocol.h"
+#include "internal.h"
+#include <arpa/inet.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..4f4c331
--- /dev/null
+++ b/src/rpc/virnetprotocol.h
@@ -0,0 +1,137 @@
+/*
+ * 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"
+#include <arpa/inet.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..15066b8
--- /dev/null
+++ b/src/rpc/virnetprotocol.x
@@ -0,0 +1,217 @@
+/* -*- 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(a)redhat.com>
+ */
+
+%#include "internal.h"
+%#include <arpa/inet.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 (serialised)*/
+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;
+
+/* 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.
+ */
+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_msg for event 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.4