Thrift-1454:Better handling of write on a closed TSocket
Client: cpp
Patch: Dave Watson

TSocket.send() was expecting a send() on the underlying socket
to fail by returning zero, but the actual behavior is to raise
an exception.



git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1211736 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index db86587..4eb8236 100755
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -1498,10 +1498,10 @@
       "}}}" << endl;
   }
   f_header_ <<
-    "#include <TProcessor.h>" << endl;
+    "#include <TDispatchProcessor.h>" << endl;
   if (gen_cob_style_) {
     f_header_ <<
-      "#include <async/TAsyncProcessor.h>" << endl;
+      "#include <async/TAsyncDispatchProcessor.h>" << endl;
   }
   f_header_ <<
     "#include \"" << get_include_prefix(*get_program()) << program_name_ <<
@@ -2565,10 +2565,13 @@
 
   void run() {
     generate_class_definition();
-    // Generate the process() function
-    generate_process();
-    // Generate the process_fn() function
-    generate_process_fn();
+
+    // Generate the dispatchCall() function
+    generate_dispatch_call(false);
+    if (generator_->gen_templates_) {
+      generate_dispatch_call(true);
+    }
+
     // Generate all of the process subfunctions
     generate_process_functions();
 
@@ -2576,8 +2579,7 @@
   }
 
   void generate_class_definition();
-  void generate_process();
-  void generate_process_fn();
+  void generate_dispatch_call(bool template_protocol);
   void generate_process_functions();
   void generate_factory();
 
@@ -2622,7 +2624,6 @@
   string typename_str_;
   string class_suffix_;
   string extends_;
-  string extends_processor_;
 };
 
 ProcessorGenerator::ProcessorGenerator(t_cpp_generator* generator,
@@ -2672,9 +2673,6 @@
       // parent services were also generated with templates enabled.
       extends_ += "T<Protocol_>";
     }
-    extends_processor_ = extends_;
-  } else {
-    extends_processor_ = "::apache::thrift::T" + pstyle_ + "Processor";
   }
 }
 
@@ -2683,11 +2681,25 @@
   vector<t_function*> functions = service_->get_functions();
   vector<t_function*>::iterator f_iter;
 
+  string parent_class;
+  if (service_->get_extends() != NULL) {
+    parent_class = extends_;
+  } else {
+    if (style_ == "Cob") {
+      parent_class = "::apache::thrift::async::TAsyncDispatchProcessor";
+    } else {
+      parent_class = "::apache::thrift::TDispatchProcessor";
+    }
+
+    if (generator_->gen_templates_) {
+      parent_class += "T<Protocol_>";
+    }
+  }
+
   // Generate the header portion
   f_header_ <<
     template_header_ <<
-    "class " << class_name_ <<
-    " : public " << extends_processor_ << " {" << endl;
+    "class " << class_name_ << " : public " << parent_class << " {" << endl;
 
   // Protected data members
   f_header_ <<
@@ -2696,19 +2708,58 @@
   f_header_ <<
     indent() << "boost::shared_ptr<" << if_name_ << "> iface_;" << endl;
   f_header_ <<
-    indent() << "virtual " << ret_type_ << "process_fn(" << finish_cob_ << "apache::thrift::protocol::TProtocol* iprot, apache::thrift::protocol::TProtocol* oprot, std::string& fname, int32_t seqid" << call_context_ << ");" << endl;
+    indent() << "virtual " << ret_type_ << "dispatchCall(" << finish_cob_ <<
+      "apache::thrift::protocol::TProtocol* iprot, " <<
+      "apache::thrift::protocol::TProtocol* oprot, " <<
+      "const std::string& fname, int32_t seqid" << call_context_ << ");" <<
+      endl;
+  if (generator_->gen_templates_) {
+    f_header_ <<
+      indent() << "virtual " << ret_type_ << "dispatchCallTemplated(" <<
+        finish_cob_ << "Protocol_* iprot, Protocol_* oprot, " <<
+        "const std::string& fname, int32_t seqid" << call_context_ << ");" <<
+        endl;
+  }
   indent_down();
 
   // Process function declarations
   f_header_ <<
     " private:" << endl;
   indent_up();
+
+  // Declare processMap_
   f_header_ <<
-    indent() << "std::map<std::string, void (" <<
-    class_name_ << "::*)(" << finish_cob_decl_ <<
-    "int32_t, apache::thrift::protocol::TProtocol*, " <<
-    "apache::thrift::protocol::TProtocol*" << call_context_decl_ <<
-    ")> processMap_;" << endl;
+    indent() << "typedef  void (" << class_name_ << "::*" <<
+      "ProcessFunction)(" << finish_cob_decl_ << "int32_t, " <<
+      "apache::thrift::protocol::TProtocol*, " <<
+      "apache::thrift::protocol::TProtocol*" << call_context_decl_ << ");" <<
+      endl;
+  if (generator_->gen_templates_) {
+    f_header_ <<
+      indent() << "typedef void (" << class_name_ << "::*" <<
+        "SpecializedProcessFunction)(" << finish_cob_decl_ << "int32_t, " <<
+        "Protocol_*, Protocol_*" << call_context_decl_ << ");" <<
+        endl <<
+      indent() << "struct ProcessFunctions {" << endl <<
+      indent() << "  ProcessFunction generic;" << endl <<
+      indent() << "  SpecializedProcessFunction specialized;" << endl <<
+      indent() << "  ProcessFunctions(ProcessFunction g, " <<
+        "SpecializedProcessFunction s) :" << endl <<
+      indent() << "    generic(g)," << endl <<
+      indent() << "    specialized(s) {}" << endl <<
+      indent() << "  ProcessFunctions() : generic(NULL), specialized(NULL) " <<
+        "{}" << endl <<
+      indent() << "};" << endl <<
+      indent() << "typedef std::map<std::string, ProcessFunctions> " <<
+        "ProcessMap;" << endl;
+  } else {
+    f_header_ <<
+      indent() << "typedef std::map<std::string, ProcessFunction> " <<
+        "ProcessMap;" << endl;
+  }
+  f_header_ <<
+    indent() << "ProcessMap processMap_;" << endl;
+
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
     indent(f_header_) <<
       "void process_" << (*f_iter)->get_name() << "(" << finish_cob_ << "int32_t seqid, apache::thrift::protocol::TProtocol* iprot, apache::thrift::protocol::TProtocol* oprot" << call_context_ << ");" << endl;
@@ -2749,43 +2800,40 @@
       }
     }
   }
-  indent_down();
-
-  indent_up();
-  string declare_map = "";
-  indent_up();
-
-  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
-    declare_map += indent();
-    declare_map += "processMap_[\"";
-    declare_map += (*f_iter)->get_name();
-    declare_map += "\"] = &";
-    declare_map += class_name_;
-    declare_map += "::process_";
-    declare_map += (*f_iter)->get_name();
-    declare_map += ";\n";
-  }
-  indent_down();
 
   f_header_ <<
     " public:" << endl <<
     indent() << class_name_ <<
     "(boost::shared_ptr<" << if_name_ << "> iface) :" << endl;
-  if (extends_.empty()) {
+  if (!extends_.empty()) {
     f_header_ <<
-      indent() << "  iface_(iface) {" << endl;
-  } else {
-    f_header_ <<
-      indent() << "  " << extends_ << "(iface)," << endl <<
-      indent() << "  iface_(iface) {" << endl;
+      indent() << "  " << extends_ << "(iface)," << endl;
   }
   f_header_ <<
-    declare_map <<
+    indent() << "  iface_(iface) {" << endl;
+  indent_up();
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    f_header_ <<
+      indent() << "processMap_[\"" << (*f_iter)->get_name() << "\"] = ";
+    if (generator_->gen_templates_) {
+      f_header_ << "ProcessFunctions(" << endl <<
+        indent() << "  &" << class_name_ << "::process_" <<
+          (*f_iter)->get_name() << "," << endl <<
+        indent() << "  &" << class_name_ << "::process_" <<
+          (*f_iter)->get_name() << ")";
+    } else {
+      f_header_ << "&" << class_name_ << "::process_" << (*f_iter)->get_name();
+    }
+    f_header_ <<
+      ";" << endl;
+  }
+
+  indent_down();
+  f_header_ <<
     indent() << "}" << endl <<
     endl <<
-    indent() << "virtual " << ret_type_ << "process(" << finish_cob_ << "boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot, boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot" << call_context_ << ");" << endl <<
-    indent() << "virtual ~" << class_name_ <<
-    "() {}" << endl;
+    indent() << "virtual ~" << class_name_ << "() {}" << endl;
   indent_down();
   f_header_ <<
     "};" << endl << endl;
@@ -2807,65 +2855,33 @@
   }
 }
 
-void ProcessorGenerator::generate_process() {
+void ProcessorGenerator::generate_dispatch_call(bool template_protocol) {
+  string protocol = "::apache::thrift::protocol::TProtocol";
+  string function_suffix;
+  if (template_protocol) {
+    protocol = "Protocol_";
+    // We call the generic version dispatchCall(), and the specialized
+    // version dispatchCallTemplated().  We can't call them both
+    // dispatchCall(), since this will cause the compiler to issue a warning if
+    // a service that doesn't use templates inherits from a service that does
+    // use templates: the compiler complains that the subclass only implements
+    // the generic version of dispatchCall(), and hides the templated version.
+    // Using different names for the two functions prevents this.
+    function_suffix = "Templated";
+  }
+
   f_out_ <<
     template_header_ <<
     ret_type_ << class_name_ <<
-    template_suffix_ << "::process(" << finish_cob_ <<
-    "boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot, " <<
-    "boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot" <<
-    call_context_ << ") {" << endl;
-  indent_up();
-
-  f_out_ <<
-    endl <<
-    indent() << "::apache::thrift::protocol::TProtocol* iprot = piprot.get();" << endl <<
-    indent() << "::apache::thrift::protocol::TProtocol* oprot = poprot.get();" << endl <<
-    indent() << "std::string fname;" << endl <<
-    indent() << "::apache::thrift::protocol::TMessageType mtype;" << endl <<
-    indent() << "int32_t seqid;" << endl <<
-    endl <<
-    indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
-    endl <<
-    indent() << "if (mtype != ::apache::thrift::protocol::T_CALL && mtype != ::apache::thrift::protocol::T_ONEWAY) {" << endl <<
-    indent() << "  iprot->skip(::apache::thrift::protocol::T_STRUCT);" << endl <<
-    indent() << "  iprot->readMessageEnd();" << endl <<
-    indent() << "  iprot->getTransport()->readEnd();" << endl <<
-    indent() << "  ::apache::thrift::TApplicationException x(::apache::thrift::TApplicationException::INVALID_MESSAGE_TYPE);" << endl <<
-    indent() << "  oprot->writeMessageBegin(fname, ::apache::thrift::protocol::T_EXCEPTION, seqid);" << endl <<
-    indent() << "  x.write(oprot);" << endl <<
-    indent() << "  oprot->writeMessageEnd();" << endl <<
-    indent() << "  oprot->getTransport()->writeEnd();" << endl <<
-    indent() << "  oprot->getTransport()->flush();" << endl <<
-    indent() << (style_ == "Cob" ? "  return cob(true);" : "  return true;") << endl <<
-    indent() << "}" << endl <<
-    endl <<
-    indent() << "return process_fn(" << (style_ == "Cob" ? "cob, " : "")
-             << "iprot, oprot, fname, seqid" << call_context_arg_ << ");" <<
+    template_suffix_ << "::dispatchCall" << function_suffix << "(" <<
+    finish_cob_ << protocol << "* iprot, " << protocol << "* oprot, " <<
+    "const std::string& fname, int32_t seqid" << call_context_ << ") {" <<
     endl;
-
-  indent_down();
-  f_out_ <<
-    indent() << "}" << endl <<
-    endl;
-}
-
-void ProcessorGenerator::generate_process_fn() {
-  f_out_ <<
-    template_header_ <<
-    ret_type_ << class_name_ <<
-    template_suffix_ << "::process_fn(" << finish_cob_ <<
-    "apache::thrift::protocol::TProtocol* iprot, " <<
-    "apache::thrift::protocol::TProtocol* oprot, " <<
-    "std::string& fname, int32_t seqid" << call_context_ << ") {" << endl;
   indent_up();
 
   // HOT: member function pointer map
   f_out_ <<
-    indent() << typename_str_ << "std::map<std::string, void (" <<
-    class_name_ << "::*)(" << finish_cob_decl_ <<
-    "int32_t, apache::thrift::protocol::TProtocol*, " <<
-    "apache::thrift::protocol::TProtocol*" << call_context_decl_ << ")>::iterator pfn;" << endl <<
+    indent() << typename_str_ << "ProcessMap::iterator pfn;" << endl <<
     indent() << "pfn = processMap_.find(fname);" << endl <<
     indent() << "if (pfn == processMap_.end()) {" << endl;
   if (extends_.empty()) {
@@ -2883,13 +2899,26 @@
   } else {
     f_out_ <<
       indent() << "  return "
-               << extends_ << "::process_fn("
+               << extends_ << "::dispatchCall("
                << (style_ == "Cob" ? "cob, " : "")
                << "iprot, oprot, fname, seqid" << call_context_arg_ << ");" << endl;
   }
   f_out_ <<
-    indent() << "}" << endl <<
-    indent() << "(this->*(pfn->second))(" << cob_arg_ << "seqid, iprot, oprot" << call_context_arg_ << ");" << endl;
+    indent() << "}" << endl;
+  if (template_protocol) {
+    f_out_ <<
+      indent() << "(this->*(pfn->second.specialized))";
+  } else {
+    if (generator_->gen_templates_) {
+      f_out_ <<
+        indent() << "(this->*(pfn->second.generic))";
+    } else {
+      f_out_ <<
+        indent() << "(this->*(pfn->second))";
+    }
+  }
+  f_out_ << "(" << cob_arg_ << "seqid, iprot, oprot" <<
+    call_context_arg_ << ");" << endl;
 
   // TODO(dreiss): return pfn ret?
   if (style_ == "Cob") {
@@ -3082,22 +3111,6 @@
       "void* callContext)" << endl;
     scope_up(out);
 
-    if (gen_templates_ && !specialized) {
-      // If these are instances of Protocol_, instead of any old TProtocol,
-      // use the specialized process function instead.
-      out <<
-        indent() << "Protocol_* _iprot = dynamic_cast<Protocol_*>(iprot);" <<
-        endl <<
-        indent() << "Protocol_* _oprot = dynamic_cast<Protocol_*>(oprot);" <<
-        endl <<
-        indent() << "if (_iprot && _oprot) {" << endl <<
-        indent() << "  return process_" << tfunction->get_name() <<
-        "(seqid, _iprot, _oprot, callContext);" << endl <<
-        indent() << "}" << endl <<
-        indent() << "T_GENERIC_PROTOCOL(this, iprot, _iprot);" << endl <<
-        indent() << "T_GENERIC_PROTOCOL(this, oprot, _oprot);" << endl << endl;
-    }
-
     string argsname = tservice->get_name() + "_" + tfunction->get_name() +
       "_args";
     string resultname = tservice->get_name() + "_" + tfunction->get_name() +
diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
index f526479..f8093ba 100644
--- a/lib/cpp/Makefile.am
+++ b/lib/cpp/Makefile.am
@@ -105,6 +105,7 @@
 include_thriftdir = $(includedir)/thrift
 include_thrift_HEADERS = \
                          $(top_builddir)/config.h \
+	                 src/TDispatchProcessor.h \
                          src/Thrift.h \
                          src/TReflectionLocal.h \
                          src/TProcessor.h \
@@ -178,6 +179,7 @@
 include_asyncdir = $(include_thriftdir)/async
 include_async_HEADERS = \
                      src/async/TAsyncChannel.h \
+                     src/async/TAsyncDispatchProcessor.h \
                      src/async/TAsyncProcessor.h \
                      src/async/TAsyncBufferProcessor.h \
                      src/async/TAsyncProtocolProcessor.h \
diff --git a/lib/cpp/src/TDispatchProcessor.h b/lib/cpp/src/TDispatchProcessor.h
new file mode 100644
index 0000000..f98751b
--- /dev/null
+++ b/lib/cpp/src/TDispatchProcessor.h
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef _THRIFT_TDISPATCHPROCESSOR_H_
+#define _THRIFT_TDISPATCHPROCESSOR_H_ 1
+
+#include "TProcessor.h"
+
+namespace apache { namespace thrift {
+
+/**
+ * TDispatchProcessor is a helper class to parse the message header then call
+ * another function to dispatch based on the function name.
+ *
+ * Subclasses must implement dispatchCall() to dispatch on the function name.
+ */
+template <class Protocol_>
+class TDispatchProcessorT : public TProcessor {
+ public:
+  virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
+                       boost::shared_ptr<protocol::TProtocol> out,
+                       void* connectionContext) {
+    protocol::TProtocol* inRaw = in.get();
+    protocol::TProtocol* outRaw = out.get();
+
+    // Try to dynamic cast to the template protocol type
+    Protocol_* specificIn = dynamic_cast<Protocol_*>(inRaw);
+    Protocol_* specificOut = dynamic_cast<Protocol_*>(outRaw);
+    if (specificIn && specificOut) {
+      return processFast(specificIn, specificOut, connectionContext);
+    }
+
+    // Log the fact that we have to use the slow path
+    T_GENERIC_PROTOCOL(this, inRaw, specificIn);
+    T_GENERIC_PROTOCOL(this, outRaw, specificOut);
+
+    std::string fname;
+    protocol::TMessageType mtype;
+    int32_t seqid;
+    inRaw->readMessageBegin(fname, mtype, seqid);
+
+    // If this doesn't look like a valid call, log an error and return false so
+    // that the server will close the connection.
+    //
+    // (The old generated processor code used to try to skip a T_STRUCT and
+    // continue.  However, that seems unsafe.)
+    if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
+      GlobalOutput.printf("received invalid message type %d from client",
+                          mtype);
+      return false;
+    }
+
+    return this->dispatchCall(inRaw, outRaw, fname, seqid, connectionContext);
+  }
+
+ protected:
+  bool processFast(Protocol_* in, Protocol_* out, void* connectionContext) {
+    std::string fname;
+    protocol::TMessageType mtype;
+    int32_t seqid;
+    in->readMessageBegin(fname, mtype, seqid);
+
+    if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
+      GlobalOutput.printf("received invalid message type %d from client",
+                          mtype);
+      return false;
+    }
+
+    return this->dispatchCallTemplated(in, out, fname,
+                                       seqid, connectionContext);
+  }
+
+  /**
+   * dispatchCall() methods must be implemented by subclasses
+   */
+  virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
+                            apache::thrift::protocol::TProtocol* out,
+                            const std::string& fname, int32_t seqid,
+                            void* callContext) = 0;
+
+  virtual bool dispatchCallTemplated(Protocol_* in, Protocol_* out,
+                                     const std::string& fname, int32_t seqid,
+                                     void* callContext) = 0;
+};
+
+/**
+ * Non-templatized version of TDispatchProcessor, that doesn't bother trying to
+ * perform a dynamic_cast.
+ */
+class TDispatchProcessor : public TProcessor {
+ public:
+  virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
+                       boost::shared_ptr<protocol::TProtocol> out,
+                       void* connectionContext) {
+    std::string fname;
+    protocol::TMessageType mtype;
+    int32_t seqid;
+    in->readMessageBegin(fname, mtype, seqid);
+
+    if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
+      GlobalOutput.printf("received invalid message type %d from client",
+                          mtype);
+      return false;
+    }
+
+    return dispatchCall(in.get(), out.get(), fname, seqid, connectionContext);
+  }
+
+ protected:
+  virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
+                            apache::thrift::protocol::TProtocol* out,
+                            const std::string& fname, int32_t seqid,
+                            void* callContext) = 0;
+};
+
+// Specialize TDispatchProcessorT for TProtocol and TDummyProtocol just to use
+// the generic TDispatchProcessor.
+template <>
+class TDispatchProcessorT<protocol::TDummyProtocol> :
+  public TDispatchProcessor {};
+template <>
+class TDispatchProcessorT<protocol::TProtocol> :
+  public TDispatchProcessor {};
+
+}} // apache::thrift
+
+#endif // _THRIFT_TDISPATCHPROCESSOR_H_
diff --git a/lib/cpp/src/async/TAsyncDispatchProcessor.h b/lib/cpp/src/async/TAsyncDispatchProcessor.h
new file mode 100644
index 0000000..9427a32
--- /dev/null
+++ b/lib/cpp/src/async/TAsyncDispatchProcessor.h
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_
+#define _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_ 1
+
+#include "TAsyncProcessor.h"
+
+namespace apache { namespace thrift { namespace async {
+
+/**
+ * TAsyncDispatchProcessor is a helper class to parse the message header then
+ * call another function to dispatch based on the function name.
+ *
+ * Subclasses must implement dispatchCall() to dispatch on the function name.
+ */
+template <class Protocol_>
+class TAsyncDispatchProcessorT : public TAsyncProcessor {
+ public:
+  virtual void process(std::tr1::function<void(bool success)> _return,
+                       boost::shared_ptr<protocol::TProtocol> in,
+                       boost::shared_ptr<protocol::TProtocol> out) {
+    protocol::TProtocol* inRaw = in.get();
+    protocol::TProtocol* outRaw = out.get();
+
+    // Try to dynamic cast to the template protocol type
+    Protocol_* specificIn = dynamic_cast<Protocol_*>(inRaw);
+    Protocol_* specificOut = dynamic_cast<Protocol_*>(outRaw);
+    if (specificIn && specificOut) {
+      return processFast(_return, specificIn, specificOut);
+    }
+
+    // Log the fact that we have to use the slow path
+    T_GENERIC_PROTOCOL(this, inRaw, specificIn);
+    T_GENERIC_PROTOCOL(this, outRaw, specificOut);
+
+    std::string fname;
+    protocol::TMessageType mtype;
+    int32_t seqid;
+    inRaw->readMessageBegin(fname, mtype, seqid);
+
+    // If this doesn't look like a valid call, log an error and return false so
+    // that the server will close the connection.
+    //
+    // (The old generated processor code used to try to skip a T_STRUCT and
+    // continue.  However, that seems unsafe.)
+    if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
+      GlobalOutput.printf("received invalid message type %d from client",
+                          mtype);
+      _return(false);
+      return;
+    }
+
+    return this->dispatchCall(_return, inRaw, outRaw, fname, seqid);
+  }
+
+  void processFast(std::tr1::function<void(bool success)> _return,
+                   Protocol_* in, Protocol_* out) {
+    std::string fname;
+    protocol::TMessageType mtype;
+    int32_t seqid;
+    in->readMessageBegin(fname, mtype, seqid);
+
+    if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
+      GlobalOutput.printf("received invalid message type %d from client",
+                          mtype);
+      _return(false);
+      return;
+    }
+
+    return this->dispatchCallTemplated(_return, in, out, fname, seqid);
+  }
+
+  virtual void dispatchCall(std::tr1::function<void(bool ok)> _return,
+                            apache::thrift::protocol::TProtocol* in,
+                            apache::thrift::protocol::TProtocol* out,
+                            const std::string& fname, int32_t seqid) = 0;
+
+  virtual void dispatchCallTemplated(std::tr1::function<void(bool ok)> _return,
+                                     Protocol_* in, Protocol_* out,
+                                     const std::string& fname,
+                                     int32_t seqid) = 0;
+};
+
+/**
+ * Non-templatized version of TAsyncDispatchProcessor,
+ * that doesn't bother trying to perform a dynamic_cast.
+ */
+class TAsyncDispatchProcessor : public TAsyncProcessor {
+ public:
+  virtual void process(std::tr1::function<void(bool success)> _return,
+                       boost::shared_ptr<protocol::TProtocol> in,
+                       boost::shared_ptr<protocol::TProtocol> out) {
+    protocol::TProtocol* inRaw = in.get();
+    protocol::TProtocol* outRaw = out.get();
+
+    std::string fname;
+    protocol::TMessageType mtype;
+    int32_t seqid;
+    inRaw->readMessageBegin(fname, mtype, seqid);
+
+    // If this doesn't look like a valid call, log an error and return false so
+    // that the server will close the connection.
+    //
+    // (The old generated processor code used to try to skip a T_STRUCT and
+    // continue.  However, that seems unsafe.)
+    if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
+      GlobalOutput.printf("received invalid message type %d from client",
+                          mtype);
+      _return(false);
+      return;
+    }
+
+    return dispatchCall(_return, inRaw, outRaw, fname, seqid);
+  }
+
+  virtual void dispatchCall(std::tr1::function<void(bool ok)> _return,
+                            apache::thrift::protocol::TProtocol* in,
+                            apache::thrift::protocol::TProtocol* out,
+                            const std::string& fname, int32_t seqid) = 0;
+};
+
+// Specialize TAsyncDispatchProcessorT for TProtocol and TDummyProtocol just to
+// use the generic TDispatchProcessor.
+template <>
+class TAsyncDispatchProcessorT<protocol::TDummyProtocol> :
+  public TAsyncDispatchProcessor {};
+template <>
+class TAsyncDispatchProcessorT<protocol::TProtocol> :
+  public TAsyncDispatchProcessor {};
+
+}}} // apache::thrift::async
+
+#endif // _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_