[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