From 980a132a24309a054049c881bf81b74f344daf4f Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 6 Dec 2010 17:03:10 +0000 Subject: [PATCH] Defines the basics of a generic RPC protocol in XDR 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 --- .gitignore | 1 + src/Makefile.am | 19 +++- src/rpc/virnetprotocol.x | 217 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 src/rpc/virnetprotocol.x diff --git a/.gitignore b/.gitignore index a4d3ea1fd0..0628732d30 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ /src/libvirt_iohelper /src/remote/*_client_bodies.h /src/remote/*_protocol.[ch] +/src/rpc/virnetprotocol.[ch] /tests/*.log /tests/cputest /tests/hashtest diff --git a/src/Makefile.am b/src/Makefile.am index b292f9f284..adfc785b68 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -571,13 +571,11 @@ $(srcdir)/remote/remote_driver.c: $(REMOTE_DRIVER_GENERATED) endif WITH_REMOTE -$(srcdir)/remote/%_protocol.c: $(srcdir)/remote/%_protocol.x \ - $(srcdir)/remote/%_protocol.h $(srcdir)/remote/rpcgen_fix.pl +%protocol.c: %protocol.x %protocol.h $(srcdir)/remote/rpcgen_fix.pl $(AM_V_GEN)perl -w $(srcdir)/remote/rpcgen_fix.pl $(RPCGEN) -c \ $< $@ -$(srcdir)/remote/%_protocol.h: $(srcdir)/remote/%_protocol.x \ - $(srcdir)/remote/rpcgen_fix.pl +%protocol.h: %protocol.x $(srcdir)/remote/rpcgen_fix.pl $(AM_V_GEN)perl -w $(srcdir)/remote/rpcgen_fix.pl $(RPCGEN) -h \ $< $@ @@ -1190,6 +1188,19 @@ else EXTRA_DIST += $(LOCK_DRIVER_SANLOCK_SOURCES) endif +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_LIBVIRTD diff --git a/src/rpc/virnetprotocol.x b/src/rpc/virnetprotocol.x new file mode 100644 index 0000000000..306fafad50 --- /dev/null +++ b/src/rpc/virnetprotocol.x @@ -0,0 +1,217 @@ +/* -*- c -*- + * virnetprotocol.x: basic protocol for all RPC services. + * + * Copyright (C) 2006-2011 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 + */ + +%#include "internal.h" +%#include + +/* 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 + * + */ +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 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; + +/* 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 (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 */ +};