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