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 <rjo...@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 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list