[libvirt] [PATCH 12/12] New generic script for generating RPC dispatcher

Daniel P. Berrange berrange at redhat.com
Fri Mar 18 18:54:27 UTC 2011


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 |  232 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 236 insertions(+), 0 deletions(-)
 create mode 100644 src/rpc/gendispatch.pl

diff --git a/src/Makefile.am b/src/Makefile.am
index e389839..763d19e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1225,6 +1225,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 = \
 	rpc/virnetmessage.h rpc/virnetmessage.c \
 	rpc/virnetprotocol.h rpc/virnetprotocol.c \
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
new file mode 100644
index 0000000..e5181c9
--- /dev/null
+++ b/src/rpc/gendispatch.pl
@@ -0,0 +1,232 @@
+#!/usr/bin/perl -w
+#
+# 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
+#
+# 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:
+#
+# gendispatch.pl -c -t remote ../src/remote/remote_protocol.x
+# gendispatch.pl -t qemu ../src/remote/qemu_protocol.x
+#
+# By Richard Jones <rjones at 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,\n";
+    print "    virNetMessageErrorPtr rerr";
+    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 "    virNetMessageErrorPtr rerr,\n";
+    print "    void *args$argann,\n";
+    print "    void *ret$retann)\n";
+    print "{\n";
+    print "  VIR_DEBUG(\"server=%p client=%p hdr=%p rerr=%p args=%p ret=%p\", server, client, hdr, rerr, args, ret);\n";
+    print "  return $name(server, client, hdr, rerr";
+    if ($argtype) {
+	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.4




More information about the libvir-list mailing list