[Xorp-cvs] SF.net SVN: xorp:[11685] trunk/xorp/xrl/scripts
bms_fbsd at users.sourceforge.net
bms_fbsd at users.sourceforge.net
Mon Dec 7 11:22:56 PST 2009
Revision: 11685
http://xorp.svn.sourceforge.net/xorp/?rev=11685&view=rev
Author: bms_fbsd
Date: 2009-12-07 19:22:56 +0000 (Mon, 07 Dec 2009)
Log Message:
-----------
Import the Thrift versions of the clnt-gen and tgt-gen stub
generators for XRL, but do not yet connect to the build.
They are intended to be invoked in exactly the same way, and turn
XRL stub/proxy methods into calls into the Thrift libraries (and
the XORP specific XRL bits), which are not yet implemented.
Added Paths:
-----------
trunk/xorp/xrl/scripts/thrift-clnt-gen
trunk/xorp/xrl/scripts/thrift-tgt-gen
Added: trunk/xorp/xrl/scripts/thrift-clnt-gen
===================================================================
--- trunk/xorp/xrl/scripts/thrift-clnt-gen (rev 0)
+++ trunk/xorp/xrl/scripts/thrift-clnt-gen 2009-12-07 19:22:56 UTC (rev 11685)
@@ -0,0 +1,445 @@
+#! /usr/bin/env python
+# vim:set sts=4 ts=8 sw=4:
+
+"""Program to generate Xrl Interface Client related files"""
+
+from optparse import OptionParser
+import os, sys
+
+# This is a bit of mess as this code was split into separate files
+import Xif.util
+
+from Xif.util import \
+ joining_csv, csv, cpp_name, cpp_classname, caps_cpp_classname, \
+ cpp_version, xorp_indent_string, xorp_indent
+
+from Xif.xiftypes import \
+ XrlArg, XrlMethod, XrlInterface, XrlTarget
+
+from Xif.parse import \
+ XifParser
+
+from Xif.thrifttypes import \
+ wire_type, send_arg, recv_arg
+
+# -----------------------------------------------------------------------------
+# Client Interface file output related
+# -----------------------------------------------------------------------------
+
+def declare_send_xrl(method_no, method):
+ rtypes = []
+ for r in method.rargs():
+ rtypes.append("const " + r.cpp_type() + "*")
+ cb_name = "%sCB" % (caps_cpp_classname(method.name()))
+ s = " typedef XorpCallback%s<void, const XrlError&%s>::RefPtr %s;\n" \
+ % (1 + len(rtypes), joining_csv(rtypes), cb_name)
+
+ atypes = ["\n\tconst char*\tdst_xrl_target_name"]
+ for a in method.args():
+ atypes.append("\n\tconst %s&\t%s" % (a.cpp_type(), a.name()))
+ atypes.append("\n\tconst %s&\tcb" % cb_name)
+ s += " bool send_%s(%s\n );\n\n" \
+ % (cpp_name(method.name()), csv(atypes))
+ return s
+
+def implement_send_argument(a, fid):
+ lines = []
+ lines.append("nout += outp->writeFieldBegin(\"%s\", %s, %d);" % \
+ (a.name(), wire_type(a), fid))
+ lines += send_arg(a)
+ lines.append("nout += outp->writeFieldEnd();")
+ return lines
+
+def implement_send_xrl(cls, method_no, method, ifqname):
+ cpp_method_name = cpp_name(method.name())
+ cb_name = "%sCB" % (caps_cpp_classname(method.name()))
+ atypes = ["\n\tconst char*\tdst_xrl_target_name"]
+ for a in method.args():
+ atypes.append("\n\tconst %s&\t%s" % (a.cpp_type(), a.name()))
+ atypes.append("\n\tconst %s&\tcb" % cb_name)
+ s = "\nbool\n%s::send_%s(%s\n)\n" \
+ % (cls, cpp_method_name, csv(atypes))
+ # TODO: call TMessenger interface which bumps cseqid for outgoing.
+ s += "{\n"
+ s += " using namespace apache::thrift::protocol;\n"
+ s += "\n"
+ s += " TProtocol *outp = 0;\n"
+ s += " uint32_t nout = 0;\n"
+ s += " int32_t cseqid = 0;\n"
+ s += "\n"
+ s += " // Begin Thrift RPC message\n"
+ s += " nout += outp->writeMessageBegin(\"%s\", T_CALL, cseqid);\n" % \
+ (cpp_method_name)
+ #
+ # Generate the marshal-out code for each argument as a list of strings;
+ # collate them, and append to the output file with correct indentation.
+ #
+ # Stay compatible with Thrift generated stubs; always write
+ # passed arguments out as a struct, even if we don't use them.
+ # This exists mainly to allow us to later change the protocol
+ # using field IDs.
+ # XifMethod.args() are inputs, XifMethod.rargs() are outputs.
+ #
+ s += " // Begin arguments\n"
+ s += " nout += outp->writeStructBegin(\"%s\");\n" % \
+ (cpp_method_name + "_args")
+ fid = 0
+ for a in method.args():
+ fid += 1
+ lines = implement_send_argument(a, fid)
+ for l in lines:
+ s += xorp_indent(1) + l + "\n"
+ s += " nout += outp->writeFieldStop();\n"
+ s += " nout += outp->writeStructEnd();\n"
+ s += " // End arguments\n"
+
+ s += " nout += outp->writeMessageEnd();\n"
+ s += " // End Thrift RPC message\n"
+ s += "\n"
+ s += " // Flush transport and mark end of message\n"
+ s += " outp->getTransport()->flush();\n"
+ s += " outp->getTransport()->writeEnd();\n"
+ s += "\n"
+ # TODO: Mark as sent with TMessenger.
+ s += " return true;\n"
+ # XXX
+ s += " UNUSED(dst_xrl_target_name);\n"
+ s += " UNUSED(cb);\n"
+ # end function
+ s += "}\n\n"
+ # nout now contains # of bytes in transport buffer for this IPC
+ return s
+
+# -----------------------------------------------------------------------------
+# Unmarshalling callbacks
+# -----------------------------------------------------------------------------
+
+# XXX XrlError is preserved and should be passed in from
+# the libxipc thrifted transport to record any transport error
+# whilst remaining compatible with legacy XORP code base
+# XXX ctx will change to be TMessenger or similar.
+
+def declare_unmarshall(method_name):
+ s = xorp_indent_string(1, "static void ")
+ s += "unmarshall_%s(" % method_name
+ cb_name = "%sCB" % (caps_cpp_classname(method_name))
+ args = [ "const XrlError&\te", "void\t*ctx", "%s\t\tcb" % cb_name]
+ for i in range(0, len(args)):
+ args[i] = "\n\t" + args[i]
+ s += csv(args)
+ s += "\n%s);\n\n" % xorp_indent(1)
+ return s
+
+# Generate code intended to:
+# Transform an incoming Thrift RPC T_REPLY message into an XRL method
+# return callback at the client.
+#
+# When this routine is called, the T_REPLY/T_EXCEPTION part of
+# the message has already been parsed. We will only need to parse
+# the return value if it's a T_REPLY. If it is a T_EXCEPTION, then
+# this function will be called to ensure the client's callback is
+# invoked with an appropriate XrlError.
+#
+# XRL callbacks must always be invoked, with XrlError set to an
+# appropriate value, to indicate an error. Otherwise, they should
+# eventually time out (we have yet to implement that part).
+#
+# Implementation note:
+#
+# Thrift RPC methods always return their results in a struct, usually
+# named "success", although this is never exposed to the stubs --
+# except when declared 'oneway'.
+#
+# Now, in XIF, we always expect a reply to an RPC; there is no
+# equivalent of Thrift's 'oneway' method. In this case, the
+# structure returned (according to the XIF) should be empty.
+# We can skip this, or attempt to parse it.
+#
+# However, to facilitate interworking between XIF code and Thrift code,
+# the thrift-gen translator will define another struct to be returned
+# as the real return value; so we need to unmarshall 2 layers of struct.
+#
+# TODO: Handle T_EXCEPTION passed to this function further up.
+#
+def implement_unmarshall(cls, method_no, method):
+ s = ""
+ arg_checks_enabled = True
+
+ nargs = []
+ for r in method.rargs():
+ nargs.append("0")
+ fail_args = joining_csv(nargs)
+
+ s += "void\n%s::unmarshall_%s(" % (cls, method.name())
+ cb_name = "%sCB" % (caps_cpp_classname(method.name()))
+ args = [ "const XrlError&\te", "void\t*ctx", "%s\t\tcb" % cb_name]
+ for i in range(0, len(args)):
+ args[i] = "\n\t" + args[i]
+ s += csv(args)
+ s += "\n)\n"
+ s += "{\n"
+ s += " using namespace apache::thrift::protocol;\n"
+ s += "\n"
+ s += " if (e != XrlError::OKAY()) {\n"
+ s += " cb->dispatch(e%s);\n" % fail_args
+ s += " return;\n"
+ s += " }\n"
+ s += "\n"
+ s += " TProtocol *inp = 0;\n"
+ s += " uint32_t nin = 0;\n"
+ s += "\n"
+
+ if len(method.rargs()) == 0:
+ s += " /* Ignore void result for XIF method call.*/\n"
+ s += " nin += inp->skip(T_STRUCT);\n"
+ else:
+ if arg_checks_enabled:
+ s += "#ifndef XIF_DISABLE_CLIENT_INPUT_CHECKS\n"
+ s += " bitset<%d> argf;\n" % len(method.rargs())
+ s += "#endif\n"
+ s += " /* Return value declarations */\n"
+ for r in method.rargs():
+ s += " %s %s;\n" % (r.cpp_type(), cpp_name(r.name()))
+ s += "\n"
+ s += " /* Begin parsing outer \"success\" struct. */\n"
+ s += " string fname;\n"
+ s += " TType ftype;\n"
+ s += " int16_t fid;\n"
+ s += "\n"
+ s += " nin += inp->readStructBegin(fname);\n"
+ s += " for (;;) {\n"
+ s += " nin += inp->readFieldBegin(fname, ftype, fid);\n"
+ s += " if (ftype == T_STOP) {\n"
+ s += " break;\n"
+ s += " } else if (fid == 0 && ftype == T_STRUCT) {\n"
+ s += " /* Begin parsing inner method_result struct. */\n"
+ s += " nin += inp->readStructBegin(fname);\n"
+ s += " for (;;) {\n"
+ s += " nin += inp->readFieldBegin(fname, ftype, fid);\n"
+ s += " if (ftype == T_STOP)\n"
+ s += " break;\n"
+ s += " switch (fid) {\n"
+ # Parse each field expected in this struct.
+ rfid = 0
+ for r in method.rargs():
+ rfid += 1
+ s += " case %d:\n" % rfid
+ s += " if (ftype == %s) {\n" % wire_type(r)
+ for l in recv_arg(r):
+ s += xorp_indent(6) + l + "\n"
+ if arg_checks_enabled:
+ s += "#ifndef XIF_DISABLE_CLIENT_INPUT_CHECKS\n"
+ s += xorp_indent(6) + "argf.set(%d);\n" % (rfid - 1)
+ s += "#endif\n"
+ s += " }\n"
+ s += " break;\n"
+ s += " default:\n"
+ s += " nin += inp->skip(ftype);\n"
+ s += " break;\n"
+ s += " }\n"
+ s += " nin += inp->readFieldEnd();\n"
+ s += " }\n"
+ s += " nin += inp->readStructEnd();\n"
+ s += " /* End parsing inner method_result struct. */\n"
+ s += " } else {\n"
+ s += " nin += inp->skip(ftype);\n"
+ s += " }\n"
+ s += " }\n"
+ s += " nin += inp->readStructEnd();\n"
+ s += " /* End parsing outer \"success\" struct. */\n"
+ # end of return argument parsing
+ s += " nin += inp->readMessageEnd();\n"
+ s += "\n"
+ s += " inp->getTransport()->readEnd();\n"
+ s += "\n"
+
+ # final argument count check.
+ if len(method.rargs()) > 0 and arg_checks_enabled:
+ s += "#ifndef XIF_DISABLE_CLIENT_INPUT_CHECKS\n"
+ s += " if (argf.count() != %d) {\n" % len(method.rargs())
+ s += "#if 0\n"
+ s += " XLOG_ERROR(\"Wrong number of arguments (%%u != %%u)\",\n"
+ s += " XORP_UINT_CAST(argf.count()),\n"
+ s += " XORP_UINT_CAST(%d));\n" % len(method.rargs())
+ s += "#endif // no XLOG in here just yet.\n"
+ s += " cb->dispatch(XrlError::BAD_ARGS()%s);\n" % fail_args
+ s += " }\n"
+ s += "#endif\n"
+ s += "\n"
+
+ # now dispatch a successful XRL return.
+ v = []
+ for r in method.rargs():
+ v.append("&%s" % cpp_name(r.name()))
+ s += " cb->dispatch(e%s);\n" % (joining_csv(v))
+
+ s += " UNUSED(ctx);\n" # XXX
+ s += "}\n"
+
+ return s
+
+# -----------------------------------------------------------------------------
+# Boilerplate code
+# -----------------------------------------------------------------------------
+
+def protect(file):
+ # remove direcory component
+ r = file.rfind("/") + 1
+ return "__XRL_INTERFACES_%s__" % file[r:].upper().replace(".", "_")
+
+def prepare_client_if_hh(modulename, hh_file):
+
+ s = Xif.util.standard_preamble(1, hh_file)
+ s += \
+"""#ifndef %s
+#define %s
+
+#undef XORP_LIBRARY_NAME
+#define XORP_LIBRARY_NAME "%s"
+
+#include "libxorp/xlog.h"
+#include "libxorp/callback.hh"
+
+#include "libxipc/xrl_error.hh"
+#include "libxipc/xrl_atom.hh"
+#include "libxipc/xrl_atom_list.hh"
+#include "libxipc/xrl_sender.hh"
+
+#include <boost/scoped_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/static_assert.hpp>
+
+#include <Thrift.h>
+
+#include <transport/TTransport.h>
+
+#include <protocol/TProtocol.h>
+#include <protocol/TBinaryProtocol.h>
+
+#include "libxipc/xif_thrift.hh" // XXX for xif_read_*()
+
+#include <bitset> // for argument checks
+
+""" % (protect(hh_file), protect(hh_file), modulename)
+ return s
+
+def client_if_hh(cls, methods):
+ s = """
+class %s {
+public:
+ %s(XrlSender* s) : _sender(s) {}
+ virtual ~%s() {}
+
+""" % (cls, cls, cls)
+ for i in range(0, len(methods)):
+ s += declare_send_xrl(i, methods[i])
+
+ s += """protected:
+ XrlSender* _sender;
+
+private:
+"""
+ for i in range(0, len(methods)):
+ s += declare_unmarshall(methods[i].name())
+ s += "};\n"
+ return s
+
+def finish_client_if_hh(hh_file):
+ return "\n#endif /* %s */\n" % protect(hh_file)
+
+def prepare_client_if_cc(hh_file, cc_file):
+ s = Xif.util.standard_preamble(0, cc_file)
+ s += "#include \"%s\"\n" % hh_file
+ return s
+
+def client_if_cc(cls, ifname, ifversion, methods):
+ s = ""
+ for i in range(0, len(methods)):
+ # Interface qualified name
+ ifqname = "%s/%s/%s" % (ifname, ifversion, methods[i].name())
+ s += implement_send_xrl(cls, i, methods[i], ifqname)
+ s += implement_unmarshall(cls, i, methods[i])
+ return s
+
+def main():
+ usage = "usage: %prog [options] arg"
+ parser = OptionParser(usage)
+ parser.add_option("-o", "--output-dir",
+ action="store",
+ type="string",
+ dest="output_dir",
+ metavar="DIR")
+ parser.add_option("-I",
+ action="append",
+ type="string",
+ dest="includes",
+ metavar="DIR")
+ (options,args) = parser.parse_args()
+
+ if len(args) != 1:
+ parser_error("incorrect number of arguments")
+
+ # Command line arguments passed on to cpp
+ pipe_string = "cpp -C "
+ if options.includes:
+ for a in options.includes:
+ pipe_string += "-I%s " % a
+ pipe_string += args[0]
+
+ cpp_pipe = os.popen(pipe_string, 'r')
+
+ xp = XifParser(cpp_pipe)
+
+ if len(xp.targets()):
+ print "Found targets (used a .ent rather than .xif input?)"
+ sys.exit(1)
+
+ xifs = xp.interfaces()
+ if len(xifs) == 0:
+ print "No interface definitions provided"
+ sys.exit(1)
+
+ # Check all interface definitions come from same source file.
+ # Although we've done the hard part (parsing), generating from
+ # here is still painful if we have to output multiple interface files.
+ sourcefile = xifs[0].sourcefile()
+ for xif in xifs:
+ if (xif.sourcefile() != sourcefile):
+ print "Multiple .xif files presented, expected one."
+ sys.exit(1)
+
+ # basename transformation - this is a lame test
+ if sourcefile[-4:] != ".xif":
+ print "Source file does not end in .xif suffix - basename transform failure."
+ sys.exit(1)
+
+ basename = sourcefile[:-4]
+ basename = basename[basename.rfind("/") + 1:]
+
+ modulename = "Xif%s" % cpp_classname(basename)
+ hh_file = "%s_xif.hh" % basename
+ cc_file = "%s_xif.cc" % basename
+
+ if options.output_dir:
+ hh_file = os.path.join(options.output_dir, hh_file)
+ cc_file = os.path.join(options.output_dir, cc_file)
+
+ # Generate header file
+ hh_txt = prepare_client_if_hh(modulename, hh_file)
+ for xif in xifs:
+ cls = "Xrl%s%sClient" % (cpp_classname(xif.name()), \
+ cpp_version(xif.version()))
+ hh_txt += client_if_hh(cls, xif.methods())
+ hh_txt += finish_client_if_hh(hh_file)
+ Xif.util.file_write_string(hh_file, hh_txt)
+
+ # Generate implementation file
+ cc_txt = prepare_client_if_cc(hh_file[hh_file.rfind("/") + 1 : ], cc_file)
+ for xif in xifs:
+ cls = "Xrl%s%sClient" % (cpp_classname(xif.name()), \
+ cpp_version(xif.version()))
+ cc_txt += client_if_cc(cls, xif.name(), xif.version(), xif.methods())
+ Xif.util.file_write_string(cc_file, cc_txt)
+
+if __name__ == '__main__':
+ main()
Property changes on: trunk/xorp/xrl/scripts/thrift-clnt-gen
___________________________________________________________________
Added: svn:executable
+ *
Added: trunk/xorp/xrl/scripts/thrift-tgt-gen
===================================================================
--- trunk/xorp/xrl/scripts/thrift-tgt-gen (rev 0)
+++ trunk/xorp/xrl/scripts/thrift-tgt-gen 2009-12-07 19:22:56 UTC (rev 11685)
@@ -0,0 +1,525 @@
+#! /usr/bin/env python
+# vim:set sts=4 ts=8 sw=4:
+
+"""Program to generate Xrl Target related files"""
+
+from optparse import OptionParser
+import os, sys
+
+# This is a bit of mess as this code was split into separate files
+import Xif.util
+
+from Xif.util import \
+ joining_csv, csv, cpp_name, cpp_classname, xorp_indent_string, \
+ xorp_indent, method_name_of_xrl, service_name_of_xrl, \
+ xrl_method_name
+
+from Xif.xiftypes import \
+ XrlArg, XrlMethod, XrlInterface, XrlTarget
+
+from Xif.parse import \
+ XifParser
+
+from Xif.thrifttypes import \
+ wire_type, send_arg, recv_arg
+
+# -----------------------------------------------------------------------------
+# Target file output related
+# -----------------------------------------------------------------------------
+
+def target_declare_service_tables(cls, interfaces):
+ s = """
+ // Thrift method table for each service in this XRL target
+ struct method_entry {
+ const char *name;
+ const XrlCmdError (%s::*method)(const int32_t);
+ };
+
+""" % cls
+
+ for i in interfaces.itervalues():
+ s += " static const struct method_entry %s_methods[];\n" % i.name()
+
+ s += """
+ // Thrift service table for this XRL target
+ struct service_entry {
+ const char *name;
+ const struct method_entry * const methods;
+ };
+
+ static const struct service_entry services[];
+"""
+ s += "\n"
+ return s
+
+def target_define_method_table(cls, interface):
+ s = ""
+ s += "const struct %s::method_entry\n" % cls
+ s += "%s::%s_methods[] = {\n" % (cls, interface.name())
+ for m in interface.methods():
+ s += " { \"%s\",\n" % m.name()
+ s += " &%s::handle_%s_%s },\n" % \
+ (cls, interface.name(), cpp_name(m.name()))
+ s += " { 0, 0 }\n"
+ s += "};\n\n"
+ return s
+
+# thrift tables are used by per-endpoint dispatch, in place
+# of the centralized XrlDispatcher (service dispatch is now local to
+# the endpoint and doesn't cross endpoint boundaries).
+
+def target_define_service_tables(cls, interfaces):
+ s = ""
+ s += "// Thrift method tables\n"
+ for i in interfaces.itervalues():
+ s += target_define_method_table(cls, i)
+ # Define service table containing all service interfaces.
+ s += "\n"
+ s += "// Thrift service tables\n"
+ s += "const struct %s::service_entry\n" % cls
+ s += "%s::services[] = {\n" % cls
+ for i in interfaces.itervalues():
+ s += " { \"%s\",\n" % i.name()
+ s += " %s::%s_methods },\n" % (cls, i.name())
+ s += " { 0, 0 }\n"
+ s += "};\n\n"
+ return s
+
+def target_declare_virtual_fns(tgt, interfaces):
+ r = ""
+ for i in interfaces.itervalues():
+ for m in i.methods():
+ # Use fully-qualified XRL-style method name to avoid
+ # rewriting legacy code which uses these RPC stubs.
+ fqm = xrl_method_name(i.name(), i.version(), m.name())
+ r += " virtual XrlCmdError %s("% cpp_name(fqm)
+ # input args
+ args = []
+ if len(m.args()):
+ args.append("\n%s// Input values" % xorp_indent(2))
+ for a in m.args():
+ cpa = "\n%sconst %s&\t%s" % \
+ (xorp_indent(2), a.cpp_type(), cpp_name(a.name()))
+ args.append(cpa)
+ # output args
+ if len(m.rargs()):
+ args.append("\n%s// Output values" % xorp_indent(2))
+ for a in m.rargs():
+ cpa = "\n%s%s&\t%s" % \
+ (xorp_indent(2), a.cpp_type(), cpp_name(a.name()))
+ args.append(cpa)
+ r += csv(args)
+ r += ") = 0;\n\n"
+ # next method in interface
+ # next interface in target
+ return r
+
+def target_declare_services(interfaces):
+ s = ""
+ for i in interfaces.itervalues():
+ for m in i.methods():
+ s += " const XrlCmdError handle_%s_%s(" % \
+ (i.name(), cpp_name(m.name()))
+ args = [ "const int32_t\trseqid" ]
+ for n in range(0, len(args)):
+ args[n] = "\n\t" + args[n]
+ s += csv(args)
+ s += ");\n\n"
+ return s;
+
+def target_declare_service_hooks():
+ s = ""
+ s += " void add_services();\n"
+ s += " void remove_services();\n"
+ return s
+
+def target_define_service_hooks(cls, service_name):
+ s = "void\n%s::add_services()\n{\n" % cls
+ s += " for (const service_entry * sp = &services[0]; sp != 0; sp++) {\n"
+ s += " MethodTable* mt = _st->add_service(sp->name);\n"
+ s += " if (0 == mt) {\n"
+ s += " // raise an exception\n"
+ s += " }\n"
+ s += " for (const method_entry * mp = sp->methods; mp != 0; mp++) {\n"
+ s += " if (! mt->add_method(mp->name,\n"
+ s += " callback(this, mp->method))) {\n"
+ s += " // raise an exception\n"
+ s += " }\n"
+ s += " }\n"
+ s += " //_st->finalize();\n"
+ s += " }\n"
+ s += "}\n"
+ s += "\n"
+ s += "void\n%s::remove_services()\n{\n" % cls
+ s += " for (const service_entry * sp = &services[0]; sp != 0; sp++) {\n"
+ s += " MethodTable* mt = _st->method_table(sp->name);\n"
+ s += " for (const method_entry * mp = sp->methods; mp != 0; mp++) {\n"
+ s += " if (! mt->remove_method(mp->name)) {\n"
+ s += " // raise an exception\n"
+ s += " }\n"
+ s += " }\n"
+ s += " if (! _st->remove_service(sp->name)) {\n"
+ s += " // raise an exception\n"
+ s += " }\n"
+ s += " }\n"
+ s += "}\n"
+ return s;
+
+#
+# Generate Thrift input code for XRL target method.
+# Assumes message header for a T_CALL was read on inp already.
+#
+# TODO: Check for duplicate field IDs.
+#
+def service_method_input(cls, service_name, method):
+ s = ""
+ arg_checks_enabled = True
+ if len(method.args()) == 0:
+ s += " /* This method has no input arguments, skip input. */\n"
+ s += " nin += inp->skip(T_STRUCT);\n"
+ else:
+ if arg_checks_enabled:
+ s += "#ifndef XIF_DISABLE_TARGET_INPUT_CHECKS\n"
+ s += " bitset<%d> argf;\n" % len(method.args())
+ s += "#endif\n"
+ s += "\n"
+ s += " /* Input value declarations */\n"
+ for a in method.args():
+ s += " %s %s;\n" % (a.cpp_type(), cpp_name(a.name()))
+ s += "\n"
+ s += " /* Begin parsing method input struct */\n"
+ s += " string fname;\n"
+ s += " TType ftype;\n"
+ s += " int16_t fid;\n"
+ s += "\n"
+ s += " nin += inp->readStructBegin(fname);\n"
+ s += " for (;;) {\n"
+ s += " nin += inp->readFieldBegin(fname, ftype, fid);\n"
+ s += " if (ftype == T_STOP)\n"
+ s += " break;\n"
+ s += " switch (fid) {\n"
+ # Parse each field expected in this struct.
+ rfid = 0
+ for a in method.args():
+ rfid += 1
+ s += " case %d:\n" % rfid
+ s += " if (ftype == %s) {\n" % wire_type(a)
+ for l in recv_arg(a):
+ s += xorp_indent(4) + l + "\n"
+ if arg_checks_enabled:
+ s += "#ifndef XIF_DISABLE_TARGET_INPUT_CHECKS\n"
+ s += " argf.set(%d);\n" % (rfid - 1)
+ s += "#endif\n"
+ s += " }\n"
+ s += " break;\n"
+ # Default is to skip unknown fields.
+ s += " default:\n"
+ s += " nin += inp->skip(ftype);\n"
+ s += " break;\n"
+ s += " }\n"
+ s += " nin += inp->readFieldEnd();\n"
+ s += " }\n"
+ s += " /* End parsing method input struct */\n"
+ s += "\n"
+ s += " nin += inp->readStructEnd();\n"
+ # end of return argument parsing
+ s += " nin += inp->readMessageEnd();\n"
+ s += " inp->getTransport()->readEnd();\n"
+ s += "\n"
+ # final argument count check
+ if len(method.args()) > 0 and arg_checks_enabled:
+ s += "#ifndef XIF_DISABLE_TARGET_INPUT_CHECKS\n"
+ s += " if (argf.count() != %d) {\n" % len(method.args())
+ s += " return XrlCmdError::BAD_ARGS();\n"
+ s += " }\n"
+ s += "#endif\n"
+ s += "\n"
+ return s
+
+def service_method_dispatch(cls, interface, method):
+ s = ""
+ fqm = xrl_method_name(interface.name(), interface.version(), method.name())
+ tab = xorp_indent(1)
+ s += tab + "/* Return value declarations */\n"
+ for r in method.rargs():
+ s += tab + "%s %s;\n" % (r.cpp_type(), cpp_name(r.name()))
+ s += tab + "XrlCmdError e = %s(" % cpp_name(fqm)
+ params = []
+ for a in method.args():
+ params.append(a.name())
+ for r in method.rargs():
+ params.append(r.name())
+ s += csv(params, ", ") + ");\n"
+ s += "\n"
+ s += tab + "if (e != XrlCmdError::OKAY()) {\n"
+ s += tab + " //XLOG_WARNING(\"Handling method for %%s failed: %%s\",\n"
+ s += tab + " // \"%s\", e.str().c_str());\n" % method.name()
+ s += tab + " return e;\n"
+ s += tab + "}\n"
+ s += "\n"
+ return s
+
+#
+# Generate return value generator for Thrifted XIF method.
+# These are always wrapped up as a struct, implicitly. We go one
+# step further and we always wrap up the result in *another*
+# struct if there are any return values.
+#
+def service_method_output(cls, service_name, method):
+ s = ""
+ tab = xorp_indent(1)
+ mname = method_name_of_xrl(method.name())
+ rname = mname + "_result"
+ srname = service_name_of_xrl(method.name()) + "_" + rname
+ s += tab + "/* Marshall return values */\n"
+ s += tab + "nout += outp->writeMessageBegin(\"%s\", T_REPLY, rseqid);\n" % \
+ (mname)
+ s += tab + "nout += outp->writeStructBegin(\"%s\");\n" % srname
+ if len(method.rargs()) > 0:
+ s += tab + "nout += outp->writeFieldBegin(\"success\", T_STRUCT, 0);\n"
+ # At this point, we start spoofing up a struct. This could in
+ # fact be a single field, but we force XIF->Thrift translated IDL
+ # to always wrap return values in a real struct.
+ s += tab + "nout += outp->writeStructBegin(\"%s\");\n" % rname
+ fid = 0
+ for r in method.rargs():
+ fid += 1
+ lines = []
+ lines.append("nout += outp->writeFieldBegin(\"%s\", %s, %d);" % \
+ (r.name(), wire_type(r), fid))
+ lines += send_arg(r)
+ lines.append("nout += outp->writeFieldEnd();")
+ for l in lines:
+ s += tab + l + "\n"
+ s += tab + "nout += outp->writeFieldStop();\n"
+ s += tab + "nout += outp->writeStructEnd();\n"
+ s += tab + "nout += outp->writeFieldStop();\n"
+ s += tab + "nout += outp->writeStructEnd();\n"
+ s += tab + "nout += outp->writeMessageEnd();\n"
+ s += "\n"
+ s += tab + "outp->getTransport()->flush();\n"
+ s += tab + "outp->getTransport()->writeEnd();\n"
+ s += "\n"
+ return s
+
+#
+# Generate a Thrift-based target method from XIF method definition.
+#
+def service_method(cls, interface, method):
+ s = ""
+ s += "const XrlCmdError\n%s::handle_%s_%s(" % \
+ (cls, interface.name(), cpp_name(method.name()))
+ args = [ "const int32_t\trseqid" ]
+ for i in range(0, len(args)):
+ args[i] = "\n\t" + args[i]
+ s += csv(args)
+ s += "\n)\n"
+ s += "{\n"
+ s += " using namespace apache::thrift::protocol;\n"
+ s += "\n"
+ s += " TProtocol *inp = 0;\n"
+ s += " TProtocol *outp = 0;\n"
+ s += " uint32_t nin = 0;\n"
+ s += " uint32_t nout = 0;\n"
+ s += "\n"
+ s += service_method_input(cls, interface.name(), method)
+ s += service_method_dispatch(cls, interface, method)
+ s += service_method_output(cls, interface.name(), method)
+ s += " return XrlCmdError::OKAY();\n"
+ s += "}\n\n"
+ return s
+
+def target_define_service_methods(cls, interfaces):
+ s = ""
+ for i in interfaces.itervalues():
+ for m in i.methods():
+ s += service_method(cls, i, m)
+ return s
+
+def protect(file):
+ # remove direcory component
+ r = file.rfind("/") + 1
+ return "__XRL_TARGETS_%s__" % file[r:].upper().replace(".", "_")
+
+def prepare_target_hh(modulename, hh_file):
+ s = Xif.util.standard_preamble(1, hh_file)
+ s += \
+"""
+#ifndef %s
+#define %s
+
+#undef XORP_LIBRARY_NAME
+#define XORP_LIBRARY_NAME "%s"
+
+//#include "libxorp/xlog.h"
+
+class XrlRouter;
+class ServiceTable;
+
+""" % (protect(hh_file), protect(hh_file), modulename)
+ return s
+
+def output_target_hh(cls, tgt, interfaces):
+ s = """
+class %s {
+private:
+ ServiceTable* _st;
+ string _name;
+
+public:
+ %s(ServiceTable* st = 0);
+
+ virtual ~%s();
+
+ const string& name() const { return _name; }
+ const char* version() const { return "%s/%s"; }
+
+protected:
+""" % (cls, cls, cls, tgt.name(), tgt.version())
+
+ s += target_declare_virtual_fns(tgt, interfaces)
+ s += "private:\n"
+ s += target_declare_services(interfaces)
+ s += target_declare_service_hooks()
+ s += target_declare_service_tables(cls, interfaces)
+ s += "};\n"
+ return s
+
+def finish_target_hh(hh_file):
+ return "\n#endif // %s\n" % protect(hh_file)
+
+def prepare_target_cc(target_hh, target_cc):
+ r = target_hh.rfind("/") + 1
+ s = Xif.util.standard_preamble(0, target_cc)
+ s += \
+"""
+
+//#include "libxorp/xlog.h"
+#include "libxorp/callback.hh"
+
+#include "libxipc/xrl_error.hh"
+#include "libxipc/xrl_atom.hh"
+#include "libxipc/xrl_atom_list.hh"
+#include "libxipc/xrl_router.hh"
+#include "libxipc/xrl_sender.hh" // XXX needed?
+
+#include "libxipc/service_table.hh"
+
+#include <boost/scoped_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/static_assert.hpp>
+
+#include <Thrift.h>
+#include <transport/TTransport.h>
+#include <protocol/TProtocol.h>
+#include <protocol/TBinaryProtocol.h>
+
+#include "libxipc/xif_thrift.hh" // XXX for xif_read_*()
+
+#include <bitset> // for argument counts
+
+"""
+ s += "\n#include \"%s\"\n\n" % target_hh[r:]
+ return s
+
+def output_target_cc(cls, tgt, interfaces):
+ s = target_define_service_tables(cls, interfaces)
+ s += """
+// Begin class definitions
+
+%s::%s(ServiceTable* st)
+ : _st(st), _name(\"%s\")
+{
+ if (_st)
+ add_services();
+}
+
+%s::~%s()
+{
+ if (_st)
+ remove_services();
+}
+
+""" % (cls, cls, tgt.name(), cls, cls)
+ s += target_define_service_methods(cls, interfaces)
+ s += target_define_service_hooks(cls, tgt)
+
+ return s
+
+def main():
+ usage = "usage: %prog [options] arg"
+ parser = OptionParser(usage)
+ parser.add_option("-o", "--output-dir",
+ action="store",
+ type="string",
+ dest="output_dir",
+ metavar="DIR")
+ parser.add_option("-I",
+ action="append",
+ type="string",
+ dest="includes",
+ metavar="DIR")
+ (options,args) = parser.parse_args()
+
+ if len(args) != 1:
+ parser_error("incorrect number of arguments")
+
+ # Command line arguments passed on to cpp
+ pipe_string = "cpp -C "
+ if options.includes:
+ for a in options.includes:
+ pipe_string += "-I%s " % a
+ pipe_string += args[0]
+
+ cpp_pipe = os.popen(pipe_string, 'r')
+
+ xp = XifParser(cpp_pipe)
+
+ tgts = xp.targets()
+ if len(tgts) == 0:
+ print "Not targets found in input files."
+ sys.exit(1)
+
+ sourcefile = tgts[0].sourcefile()
+ for tgt in tgts:
+ if (tgt.sourcefile() != sourcefile):
+ print "Multiple .tgt files presented, expected just one."
+ sys.exit(1)
+
+ # basename transformation - this is a lame test
+ if sourcefile[-4:] != ".tgt":
+ print "Source file does not end in .tgt suffix - basename transform failure."
+ sys.exit(1)
+
+ basename = sourcefile[:-4]
+ basename = basename[basename.rfind("/") + 1:]
+
+ modulename = "Xrl%sTarget" % cpp_classname(basename)
+ hh_file = "%s_base.hh" % basename
+ cc_file = "%s_base.cc" % basename
+
+ if options.output_dir:
+ hh_file = os.path.join(options.output_dir, hh_file)
+ cc_file = os.path.join(options.output_dir, cc_file)
+
+ hh_txt = prepare_target_hh(modulename, hh_file)
+ cc_txt = prepare_target_cc(hh_file, cc_file)
+
+ for tgt in xp.targets():
+ # Because interfaces are loaded and parsed separately from targets,
+ # XrlTarget.interfaces is a list of tuples ("interface_name",
+ # "interface_version").
+ # Produce a dictionary of interfaces actually referenced by this
+ # XRL target, from everything that has been parsed.
+ interfaces = dict((i.name(), i) for i in filter(lambda i: i.name() in \
+ map(lambda x: x[0], tgt.interfaces()), xp.interfaces()))
+ cls = "Xrl%sTargetBase" % cpp_classname(tgt.name())
+ hh_txt += output_target_hh(cls, tgt, interfaces)
+ hh_txt += finish_target_hh(hh_file)
+ cc_txt += output_target_cc(cls, tgt, interfaces)
+
+ Xif.util.file_write_string(hh_file, hh_txt)
+ Xif.util.file_write_string(cc_file, cc_txt)
+
+if __name__ == '__main__':
+ main()
Property changes on: trunk/xorp/xrl/scripts/thrift-tgt-gen
___________________________________________________________________
Added: svn:executable
+ *
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Xorp-cvs
mailing list