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_