You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2017/12/03 01:03:05 UTC

[35/50] [abbrv] thrift git commit: THRIFT-2013: add multiplex server and client test support to cpp language add multiplex client test support to csharp and java languages fix a bug in the server-side header protocol factory fix a bug in the cpp SSL serv

THRIFT-2013: add multiplex server and client test support to cpp language
add multiplex client test support to csharp and java languages
fix a bug in the server-side header protocol factory
fix a bug in the cpp SSL server socket implementation
remove unnecessary sleep in cpp server testOneway

This closes #1414


Project: http://git-wip-us.apache.org/repos/asf/thrift/repo
Commit: http://git-wip-us.apache.org/repos/asf/thrift/commit/58402ff6
Tree: http://git-wip-us.apache.org/repos/asf/thrift/tree/58402ff6
Diff: http://git-wip-us.apache.org/repos/asf/thrift/diff/58402ff6

Branch: refs/heads/0.11.0
Commit: 58402ff6a71f00f9d61a9676bdabd3e5bbe9ea3f
Parents: 87ad2bc
Author: James E. King, III <jk...@apache.org>
Authored: Fri Nov 17 14:41:46 2017 -0500
Committer: James E. King, III <jk...@apache.org>
Committed: Sat Nov 18 21:10:40 2017 -0500

----------------------------------------------------------------------
 README.md                                       |   2 +-
 .../thrift/processor/TMultiplexedProcessor.h    | 111 +++++++++++--------
 lib/cpp/src/thrift/protocol/THeaderProtocol.h   |   2 +-
 lib/cpp/src/thrift/transport/TSSLSocket.cpp     |  51 +++++----
 .../ThriftMVCTest/Controllers/HomeController.cs |   8 +-
 .../test/ThriftMVCTest/SecondServiceImpl.cs     |  14 +--
 lib/erl/test/thrift_test_test.erl               |  12 --
 .../test/org/apache/thrift/test/TestClient.java |  34 +++++-
 .../test/org/apache/thrift/test/TestServer.java |   4 -
 lib/nodejs/test/client.js                       |   2 +-
 lib/nodejs/test/server.js                       |   4 +-
 test/ThriftTest.thrift                          |   3 +-
 test/c_glib/src/thrift_second_service_handler.c |  13 ---
 test/cpp/CMakeLists.txt                         |   5 +-
 test/cpp/Makefile.am                            |   6 +-
 test/cpp/src/TestClient.cpp                     | 108 ++++++++++++------
 test/cpp/src/TestServer.cpp                     |  65 +++++++----
 test/csharp/TestClient.cs                       |  41 +++++--
 test/features/known_failures_Linux.json         |  12 +-
 test/known_failures_Linux.json                  |  90 ++++++++++++---
 test/rs/src/bin/test_client.rs                  |  12 --
 test/rs/src/bin/test_server.rs                  |   4 -
 test/tests.json                                 |  69 +++++++++---
 23 files changed, 431 insertions(+), 241 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 2ef9a5e..5435041 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 Apache Thrift
 =============
 
-Last Modified: 2017--10
+Last Modified: 2017-11-10
 
 License
 =======

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h
----------------------------------------------------------------------
diff --git a/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h b/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h
index 13b09bb..aa3d49f 100644
--- a/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h
+++ b/lib/cpp/src/thrift/processor/TMultiplexedProcessor.h
@@ -27,8 +27,6 @@
 
 namespace apache {
 namespace thrift {
-using stdcxx::shared_ptr;
-
 namespace protocol {
 
 /**
@@ -38,7 +36,7 @@ namespace protocol {
  */
 class StoredMessageProtocol : public TProtocolDecorator {
 public:
-  StoredMessageProtocol(shared_ptr<protocol::TProtocol> _protocol,
+  StoredMessageProtocol(stdcxx::shared_ptr<protocol::TProtocol> _protocol,
                         const std::string& _name,
                         const TMessageType _type,
                         const int32_t _seqid)
@@ -67,19 +65,19 @@ public:
  * processors with it, as shown in the following example:</p>
  *
  * <blockquote><code>
- *     shared_ptr<TMultiplexedProcessor> processor(new TMultiplexedProcessor());
+ *     stdcxx::shared_ptr<TMultiplexedProcessor> processor(new TMultiplexedProcessor());
  *
  *     processor->registerProcessor(
  *         "Calculator",
- *         shared_ptr<TProcessor>( new CalculatorProcessor(
- *             shared_ptr<CalculatorHandler>( new CalculatorHandler()))));
+ *         stdcxx::shared_ptr<TProcessor>( new CalculatorProcessor(
+ *             stdcxx::shared_ptr<CalculatorHandler>( new CalculatorHandler()))));
  *
  *     processor->registerProcessor(
  *         "WeatherReport",
- *         shared_ptr<TProcessor>( new WeatherReportProcessor(
- *             shared_ptr<WeatherReportHandler>( new WeatherReportHandler()))));
+ *         stdcxx::shared_ptr<TProcessor>( new WeatherReportProcessor(
+ *             stdcxx::shared_ptr<WeatherReportHandler>( new WeatherReportHandler()))));
  *
- *     shared_ptr<TServerTransport> transport(new TServerSocket(9090));
+ *     stdcxx::shared_ptr<TServerTransport> transport(new TServerSocket(9090));
  *     TSimpleServer server(processor, transport);
  *
  *     server.serve();
@@ -87,7 +85,7 @@ public:
  */
 class TMultiplexedProcessor : public TProcessor {
 public:
-  typedef std::map<std::string, shared_ptr<TProcessor> > services_t;
+  typedef std::map<std::string, stdcxx::shared_ptr<TProcessor> > services_t;
 
   /**
     * 'Register' a service with this <code>TMultiplexedProcessor</code>.  This
@@ -100,11 +98,41 @@ public:
     *                         as "handlers", e.g. WeatherReportHandler,
     *                         implementing WeatherReportIf interface.
     */
-  void registerProcessor(const std::string& serviceName, shared_ptr<TProcessor> processor) {
+  void registerProcessor(const std::string& serviceName, stdcxx::shared_ptr<TProcessor> processor) {
     services[serviceName] = processor;
   }
 
   /**
+   * Register a service to be called to process queries without service name
+   * \param [in] processor   Implementation of a service.
+   */
+  void registerDefault(const stdcxx::shared_ptr<TProcessor>& processor) {
+    defaultProcessor = processor;
+  }
+
+  /**
+   * Chew up invalid input and return an exception to throw.
+   */
+  TException protocol_error(stdcxx::shared_ptr<protocol::TProtocol> in,
+                            stdcxx::shared_ptr<protocol::TProtocol> out,
+                            const std::string& name, 
+                            int32_t seqid, 
+                            const std::string& msg) const {
+    in->skip(::apache::thrift::protocol::T_STRUCT);
+    in->readMessageEnd();
+    in->getTransport()->readEnd();
+    ::apache::thrift::TApplicationException
+      x(::apache::thrift::TApplicationException::PROTOCOL_ERROR,
+        "TMultiplexedProcessor: " + msg);
+    out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
+    x.write(out.get());
+    out->writeMessageEnd();
+    out->getTransport()->writeEnd();
+    out->getTransport()->flush();
+    return TException(msg);
+}
+   
+  /**
    * This implementation of <code>process</code> performs the following steps:
    *
    * <ol>
@@ -119,8 +147,8 @@ public:
    * the service name was not found in the message, or if the service
    * name was not found in the service map.
    */
-  bool process(shared_ptr<protocol::TProtocol> in,
-               shared_ptr<protocol::TProtocol> out,
+  bool process(stdcxx::shared_ptr<protocol::TProtocol> in,
+               stdcxx::shared_ptr<protocol::TProtocol> out,
                void* connectionContext) {
     std::string name;
     protocol::TMessageType type;
@@ -133,22 +161,10 @@ public:
 
     if (type != protocol::T_CALL && type != protocol::T_ONEWAY) {
       // Unexpected message type.
-      in->skip(::apache::thrift::protocol::T_STRUCT);
-      in->readMessageEnd();
-      in->getTransport()->readEnd();
-      const std::string msg("TMultiplexedProcessor: Unexpected message type");
-      ::apache::thrift::TApplicationException
-          x(::apache::thrift::TApplicationException::PROTOCOL_ERROR, msg);
-      out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
-      x.write(out.get());
-      out->writeMessageEnd();
-      out->getTransport()->writeEnd();
-      out->getTransport()->flush();
-      throw TException(msg);
+      throw protocol_error(in, out, name, seqid, "Unexpected message type");
     }
 
     // Extract the service name
-
     boost::tokenizer<boost::char_separator<char> > tok(name, boost::char_separator<char>(":"));
 
     std::vector<std::string> tokens;
@@ -161,39 +177,46 @@ public:
       services_t::iterator it = services.find(tokens[0]);
 
       if (it != services.end()) {
-        shared_ptr<TProcessor> processor = it->second;
+        stdcxx::shared_ptr<TProcessor> processor = it->second;
         // Let the processor registered for this service name
         // process the message.
         return processor
-            ->process(shared_ptr<protocol::TProtocol>(
+            ->process(stdcxx::shared_ptr<protocol::TProtocol>(
                           new protocol::StoredMessageProtocol(in, tokens[1], type, seqid)),
                       out,
                       connectionContext);
       } else {
         // Unknown service.
-        in->skip(::apache::thrift::protocol::T_STRUCT);
-        in->readMessageEnd();
-        in->getTransport()->readEnd();
-
-        std::string msg("TMultiplexedProcessor: Unknown service: ");
-        msg += tokens[0];
-        ::apache::thrift::TApplicationException
-            x(::apache::thrift::TApplicationException::PROTOCOL_ERROR, msg);
-        out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
-        x.write(out.get());
-        out->writeMessageEnd();
-        out->getTransport()->writeEnd();
-        out->getTransport()->flush();
-        msg += ". Did you forget to call registerProcessor()?";
-        throw TException(msg);
+        throw protocol_error(in, out, name, seqid, 
+            "Unknown service: " + tokens[0] +
+				". Did you forget to call registerProcessor()?");
       }
+    } else if (tokens.size() == 1) {
+	  if (defaultProcessor) {
+        // non-multiplexed client forwards to default processor
+        return defaultProcessor            
+            ->process(stdcxx::shared_ptr<protocol::TProtocol>(
+                          new protocol::StoredMessageProtocol(in, tokens[0], type, seqid)),
+                      out,
+                      connectionContext);
+	  } else {
+		throw protocol_error(in, out, name, seqid,
+			"Non-multiplexed client request dropped. "
+			"Did you forget to call defaultProcessor()?");
+	  }
+    } else {
+		throw protocol_error(in, out, name, seqid,
+		    "Wrong number of tokens.");
     }
-    return false;
   }
 
 private:
   /** Map of service processor objects, indexed by service names. */
   services_t services;
+  
+  //! If a non-multi client requests something, it goes to the
+  //! default processor (if one is defined) for backwards compatibility.
+  stdcxx::shared_ptr<TProcessor> defaultProcessor;
 };
 }
 }

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/cpp/src/thrift/protocol/THeaderProtocol.h
----------------------------------------------------------------------
diff --git a/lib/cpp/src/thrift/protocol/THeaderProtocol.h b/lib/cpp/src/thrift/protocol/THeaderProtocol.h
index 0b3997c..8cd5017 100644
--- a/lib/cpp/src/thrift/protocol/THeaderProtocol.h
+++ b/lib/cpp/src/thrift/protocol/THeaderProtocol.h
@@ -192,7 +192,7 @@ class THeaderProtocolFactory : public TProtocolFactory {
 public:
   virtual stdcxx::shared_ptr<TProtocol> getProtocol(stdcxx::shared_ptr<transport::TTransport> trans) {
     THeaderProtocol* headerProtocol
-        = new THeaderProtocol(trans, stdcxx::shared_ptr<transport::TTransport>(), T_BINARY_PROTOCOL);
+        = new THeaderProtocol(trans, trans, T_BINARY_PROTOCOL);
     return stdcxx::shared_ptr<TProtocol>(headerProtocol);
   }
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/cpp/src/thrift/transport/TSSLSocket.cpp
----------------------------------------------------------------------
diff --git a/lib/cpp/src/thrift/transport/TSSLSocket.cpp b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
index ddefb34..3f0e28e 100644
--- a/lib/cpp/src/thrift/transport/TSSLSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
@@ -157,7 +157,7 @@ void cleanupOpenSSL() {
   mutexes.reset();
 }
 
-static void buildErrors(string& message, int error = 0);
+static void buildErrors(string& message, int errno_copy = 0, int sslerrno = 0);
 static bool matchName(const char* host, const char* pattern, int size);
 static char uppercase(char c);
 
@@ -301,7 +301,7 @@ bool TSSLSocket::peek() {
         default:;// do nothing
       }
       string errors;
-      buildErrors(errors, errno_copy);
+      buildErrors(errors, errno_copy, error);
       throw TSSLException("SSL_peek: " + errors);
     } else if (rc == 0) {
       ERR_clear_error();
@@ -325,12 +325,14 @@ void TSSLSocket::close() {
   if (ssl_ != NULL) {
     try {
       int rc;
+      int errno_copy = 0;
+      int error = 0;
 
       do {
         rc = SSL_shutdown(ssl_);
         if (rc <= 0) {
-          int errno_copy = THRIFT_GET_SOCKET_ERROR;
-          int error = SSL_get_error(ssl_, rc);
+          errno_copy = THRIFT_GET_SOCKET_ERROR;
+          error = SSL_get_error(ssl_, rc);
           switch (error) {
             case SSL_ERROR_SYSCALL:
               if ((errno_copy != THRIFT_EINTR)
@@ -348,9 +350,8 @@ void TSSLSocket::close() {
       } while (rc == 2);
 
       if (rc < 0) {
-        int errno_copy = THRIFT_GET_SOCKET_ERROR;
         string errors;
-        buildErrors(errors, errno_copy);
+        buildErrors(errors, errno_copy, error);
         GlobalOutput(("SSL_shutdown: " + errors).c_str());
       }
     } catch (TTransportException& te) {
@@ -380,17 +381,19 @@ uint32_t TSSLSocket::read(uint8_t* buf, uint32_t len) {
     throw TTransportException(TTransportException::UNKNOWN, "retry again");
   int32_t bytes = 0;
   while (readRetryCount_ < maxRecvRetries_) {
-    ERR_clear_error();
     bytes = SSL_read(ssl_, buf, len);
+    int32_t errno_copy = THRIFT_GET_SOCKET_ERROR;
     int32_t error = SSL_get_error(ssl_, bytes);
     readRetryCount_++;
-    if (bytes >= 0 && error == 0) {
+    if (error == SSL_ERROR_NONE) {
       readRetryCount_ = 0;
       break;
     }
-    int32_t errno_copy = THRIFT_GET_SOCKET_ERROR;
     unsigned int waitEventReturn;
     switch (error) {
+      case SSL_ERROR_ZERO_RETURN:
+        throw TTransportException(TTransportException::END_OF_FILE, "client disconnected");
+
       case SSL_ERROR_SYSCALL:
         if ((errno_copy != THRIFT_EINTR)
             && (errno_copy != THRIFT_EAGAIN)) {
@@ -422,9 +425,9 @@ uint32_t TSSLSocket::read(uint8_t* buf, uint32_t len) {
           throw TTransportException(TTransportException::INTERNAL_ERROR, "too much recv retries");
         }
         else if (waitEventReturn == TSSL_DATA) {
-            // in case of SSL and huge thrift packets, there may be a number of 
-            // socket operations, before any data becomes available by SSL_read(). 
-            // Therefore the number of retries should not be increased and 
+            // in case of SSL and huge thrift packets, there may be a number of
+            // socket operations, before any data becomes available by SSL_read().
+            // Therefore the number of retries should not be increased and
             // the operation should be repeated.
             readRetryCount_--;
             continue;
@@ -433,7 +436,7 @@ uint32_t TSSLSocket::read(uint8_t* buf, uint32_t len) {
       default:;// do nothing
     }
     string errors;
-    buildErrors(errors, errno_copy);
+    buildErrors(errors, errno_copy, error);
     throw TSSLException("SSL_read: " + errors);
   }
   return bytes;
@@ -470,7 +473,7 @@ void TSSLSocket::write(const uint8_t* buf, uint32_t len) {
         default:;// do nothing
       }
       string errors;
-      buildErrors(errors, errno_copy);
+      buildErrors(errors, errno_copy, error);
       throw TSSLException("SSL_write: " + errors);
     }
     written += bytes;
@@ -514,7 +517,7 @@ uint32_t TSSLSocket::write_partial(const uint8_t* buf, uint32_t len) {
         default:;// do nothing
       }
       string errors;
-      buildErrors(errors, errno_copy);
+      buildErrors(errors, errno_copy, error);
       throw TSSLException("SSL_write: " + errors);
     }
     written += bytes;
@@ -574,12 +577,14 @@ void TSSLSocket::initializeHandshake() {
   }
 
   int rc;
+  int errno_copy = 0;
+  int error = 0;
   if (server()) {
     do {
       rc = SSL_accept(ssl_);
       if (rc <= 0) {
-        int errno_copy = THRIFT_GET_SOCKET_ERROR;
-        int error = SSL_get_error(ssl_, rc);
+        errno_copy = THRIFT_GET_SOCKET_ERROR;
+        error = SSL_get_error(ssl_, rc);
         switch (error) {
           case SSL_ERROR_SYSCALL:
             if ((errno_copy != THRIFT_EINTR)
@@ -610,8 +615,8 @@ void TSSLSocket::initializeHandshake() {
     do {
       rc = SSL_connect(ssl_);
       if (rc <= 0) {
-        int errno_copy = THRIFT_GET_SOCKET_ERROR;
-        int error = SSL_get_error(ssl_, rc);
+        errno_copy = THRIFT_GET_SOCKET_ERROR;
+        error = SSL_get_error(ssl_, rc);
         switch (error) {
           case SSL_ERROR_SYSCALL:
             if ((errno_copy != THRIFT_EINTR)
@@ -635,10 +640,9 @@ void TSSLSocket::initializeHandshake() {
     } while (rc == 2);
   }
   if (rc <= 0) {
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
     string fname(server() ? "SSL_accept" : "SSL_connect");
     string errors;
-    buildErrors(errors, errno_copy);
+    buildErrors(errors, errno_copy, error);
     throw TSSLException(fname + ": " + errors);
   }
   authorize();
@@ -975,7 +979,7 @@ int TSSLSocketFactory::passwordCallback(char* password, int size, int, void* dat
 }
 
 // extract error messages from error queue
-void buildErrors(string& errors, int errno_copy) {
+void buildErrors(string& errors, int errno_copy, int sslerrno) {
   unsigned long errorCode;
   char message[256];
 
@@ -999,6 +1003,9 @@ void buildErrors(string& errors, int errno_copy) {
   if (errors.empty()) {
     errors = "error code: " + to_string(errno_copy);
   }
+  if (sslerrno) {
+    errors += " (SSL_error_code = " + to_string(sslerrno) + ")";
+  }
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
----------------------------------------------------------------------
diff --git a/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs b/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
index ab9eada..c9a1ec4 100644
--- a/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
+++ b/lib/csharp/test/ThriftMVCTest/Controllers/HomeController.cs
@@ -41,9 +41,8 @@ namespace ThriftMVCTest.Controllers
             SecondService.IAsync asyncService =
                 new SecondService.Client(new TBinaryProtocol(new THttpClient(new Uri(baseUri, "Async.thrift"))));
 
-            await asyncService.blahBlahAsync();
             var result = await asyncService.secondtestStringAsync("TestString");
-            if (result != "TestString")
+            if (result != "testString(\"TestString\")")
             {
                 throw new Exception("The wrong result was returned");
             }
@@ -59,9 +58,8 @@ namespace ThriftMVCTest.Controllers
             SecondService.ISync service =
                 new SecondService.Client(new TBinaryProtocol(new THttpClient(new Uri(baseUri, "Sync.thrift"))));
 
-            service.blahBlah();
             var result = service.secondtestString("TestString");
-            if (result != "TestString")
+            if (result != "testString(\"TestString\")")
             {
                 throw new Exception("The wrong result was returned");
             }
@@ -69,4 +67,4 @@ namespace ThriftMVCTest.Controllers
             return RedirectToAction("Index");
         }
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
----------------------------------------------------------------------
diff --git a/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs b/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
index dce0148..fad301a 100644
--- a/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
+++ b/lib/csharp/test/ThriftMVCTest/SecondServiceImpl.cs
@@ -24,24 +24,14 @@ namespace ThriftMVCTest
 {
     public class SecondServiceImpl : SecondService.IAsync, SecondService.ISync
     {
-        public Task blahBlahAsync()
-        {
-            return Task.FromResult(0);
-        }
-
         public Task<string> secondtestStringAsync(string thing)
         {
             return Task.FromResult(thing);
         }
 
-        public void blahBlah()
-        {
-
-        }
-
         public string secondtestString(string thing)
         {
-            return thing;
+            return "testString(\"" + thing + "\")";
         }
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/erl/test/thrift_test_test.erl
----------------------------------------------------------------------
diff --git a/lib/erl/test/thrift_test_test.erl b/lib/erl/test/thrift_test_test.erl
index ae20f31..77df61d 100644
--- a/lib/erl/test/thrift_test_test.erl
+++ b/lib/erl/test/thrift_test_test.erl
@@ -628,18 +628,6 @@ service_info_test_() ->
       {struct, []},
       thrift_test_thrift:function_info(testOneway, exceptions)
     )},
-    {"blahBlah params", ?_assertEqual(
-      {struct, []},
-      second_service_thrift:function_info(blahBlah, params_type)
-    )},
-    {"blahBlah reply", ?_assertEqual(
-      {struct, []},
-      second_service_thrift:function_info(blahBlah, reply_type)
-    )},
-    {"blahBlah exceptions", ?_assertEqual(
-      {struct, []},
-      second_service_thrift:function_info(blahBlah, exceptions)
-    )},
     {"secondtestString params", ?_assertEqual(
       {struct, [{1, string}]},
       second_service_thrift:function_info(secondtestString, params_type)

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/java/test/org/apache/thrift/test/TestClient.java
----------------------------------------------------------------------
diff --git a/lib/java/test/org/apache/thrift/test/TestClient.java b/lib/java/test/org/apache/thrift/test/TestClient.java
index b2ce1e6..feaa972 100644
--- a/lib/java/test/org/apache/thrift/test/TestClient.java
+++ b/lib/java/test/org/apache/thrift/test/TestClient.java
@@ -33,6 +33,7 @@ import org.apache.thrift.TSerializer;
 import org.apache.thrift.protocol.TBinaryProtocol;
 import org.apache.thrift.protocol.TCompactProtocol;
 import org.apache.thrift.protocol.TJSONProtocol;
+import org.apache.thrift.protocol.TMultiplexedProtocol;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.protocol.TSimpleJSONProtocol;
 import org.apache.thrift.transport.TFastFramedTransport;
@@ -46,6 +47,7 @@ import org.apache.thrift.transport.TTransportException;
 // Generated code
 import thrift.test.Insanity;
 import thrift.test.Numberz;
+import thrift.test.SecondService;
 import thrift.test.ThriftTest;
 import thrift.test.Xception;
 import thrift.test.Xception2;
@@ -64,6 +66,7 @@ public class TestClient {
   private static int ERR_STRUCTS = 2;
   private static int ERR_CONTAINERS = 4;
   private static int ERR_EXCEPTIONS = 8;
+  private static int ERR_PROTOCOLS = 16;
   private static int ERR_UNKNOWN = 64;
 
   public static void main(String [] args) {
@@ -102,7 +105,7 @@ public class TestClient {
           System.out.println("  --host=arg (=" + host + ")\tHost to connect");
           System.out.println("  --port=arg (=" + port + ")\tPort number to connect");
           System.out.println("  --transport=arg (=" + transport_type + ")\n\t\t\t\tTransport: buffered, framed, fastframed, http");
-          System.out.println("  --protocol=arg (=" + protocol_type + ")\tProtocol: binary, json, compact");
+          System.out.println("  --protocol=arg (=" + protocol_type + ")\tProtocol: binary, compact, json, multi, multic, multij");
           System.out.println("  --ssl\t\t\tEncrypted Transport using SSL");
           System.out.println("  --testloops[--n]=arg (=" + numTests + ")\tNumber of Tests");
           System.exit(0);
@@ -117,6 +120,9 @@ public class TestClient {
       if (protocol_type.equals("binary")) {
       } else if (protocol_type.equals("compact")) {
       } else if (protocol_type.equals("json")) {
+      } else if (protocol_type.equals("multi")) {
+      } else if (protocol_type.equals("multic")) {
+      } else if (protocol_type.equals("multij")) {
       } else {
         throw new Exception("Unknown protocol type! " + protocol_type);
       }
@@ -163,16 +169,21 @@ public class TestClient {
     }
 
     TProtocol tProtocol = null;
-    if (protocol_type.equals("json")) {
+    TProtocol tProtocol2 = null;
+    if (protocol_type.equals("json") || protocol_type.equals("multij")) {
       tProtocol = new TJSONProtocol(transport);
-    } else if (protocol_type.equals("compact")) {
+    } else if (protocol_type.equals("compact") || protocol_type.equals("multic")) {
       tProtocol = new TCompactProtocol(transport);
     } else {
       tProtocol = new TBinaryProtocol(transport);
     }
 
-    ThriftTest.Client testClient =
-      new ThriftTest.Client(tProtocol);
+    if (protocol_type.startsWith("multi")) {
+      tProtocol2 = new TMultiplexedProtocol(tProtocol, "SecondService");
+      tProtocol = new TMultiplexedProtocol(tProtocol, "ThriftTest");
+    }
+
+    ThriftTest.Client testClient = new ThriftTest.Client(tProtocol);
     Insanity insane = new Insanity();
 
     long timeMin = 0;
@@ -223,6 +234,19 @@ public class TestClient {
         }
 
         /**
+         * Multiplexed test
+         */
+        if (protocol_type.startsWith("multi")) {
+          SecondService.Client secondClient = new SecondService.Client(tProtocol2);
+          System.out.print("secondtestString(\"Test2\")");
+          s = secondClient.secondtestString("Test2");
+          System.out.print(" = \"" + s + "\"\n");
+          if (!s.equals("testString(\"Test2\")")) {
+            returnCode |= ERR_PROTOCOLS;
+            System.out.println("*** FAILURE ***\n");
+          }
+        }
+        /**
          * BYTE TEST
          */
         System.out.print("testByte(1)");

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/java/test/org/apache/thrift/test/TestServer.java
----------------------------------------------------------------------
diff --git a/lib/java/test/org/apache/thrift/test/TestServer.java b/lib/java/test/org/apache/thrift/test/TestServer.java
index 71b86c3..1f3e555 100644
--- a/lib/java/test/org/apache/thrift/test/TestServer.java
+++ b/lib/java/test/org/apache/thrift/test/TestServer.java
@@ -73,10 +73,6 @@ public class TestServer {
   static class SecondHandler implements thrift.test.SecondService.Iface {
 
     @Override
-    public void blahBlah() throws org.apache.thrift.TException
-    { throw new org.apache.thrift.TException("blahBlah"); }
-
-    @Override
     public java.lang.String secondtestString(java.lang.String thing) throws org.apache.thrift.TException
     { return "testString(\"" + thing + "\")"; }
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/nodejs/test/client.js
----------------------------------------------------------------------
diff --git a/lib/nodejs/test/client.js b/lib/nodejs/test/client.js
index 9609518..006fad2 100644
--- a/lib/nodejs/test/client.js
+++ b/lib/nodejs/test/client.js
@@ -108,7 +108,7 @@ if (type === 'tcp') {
   connection.on('connect', function() {
     secondclient.secondtestString("Test", function(err, response) {
       assert(!err);
-      assert.equal("Test", response);
+      assert.equal("testString(\"Test\")", response);
     });
 
     runTests();

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/lib/nodejs/test/server.js
----------------------------------------------------------------------
diff --git a/lib/nodejs/test/server.js b/lib/nodejs/test/server.js
index bad3b17..8f2e06b 100644
--- a/lib/nodejs/test/server.js
+++ b/lib/nodejs/test/server.js
@@ -72,8 +72,8 @@ if (type === 'http' || type ==='websocket') {
 if (type === 'multiplex') {
   var SecondServiceHandler = {
     secondtestString: function(thing, result) {
-      console.log('testString(\'' + thing + '\')');
-      result(null, thing);
+      console.log('testString("' + thing + '")');
+      result(null, 'testString("' + thing + '")');
     }
   };
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/ThriftTest.thrift
----------------------------------------------------------------------
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index c56f571..24dcbb9 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -321,13 +321,12 @@ service ThriftTest
 
 service SecondService
 {
-  void blahBlah()
   /**
    * Prints 'testString("%s")' with thing as '%s'
    * @param string thing - the string to print
    * @return string - returns the string 'thing'
    */
-  string       secondtestString(1: string thing),
+  string secondtestString(1: string thing)
 }
 
 struct VersioningTestV1 {

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/c_glib/src/thrift_second_service_handler.c
----------------------------------------------------------------------
diff --git a/test/c_glib/src/thrift_second_service_handler.c b/test/c_glib/src/thrift_second_service_handler.c
index c464372..66ac7bc 100644
--- a/test/c_glib/src/thrift_second_service_handler.c
+++ b/test/c_glib/src/thrift_second_service_handler.c
@@ -50,17 +50,6 @@ second_service_handler_secondtest_string (TTestSecondServiceIf  *iface,
   return TRUE;
 }
 
-gboolean
-second_service_handler_blah_blah (TTestSecondServiceIf *iface, GError **error)
-{
-  THRIFT_UNUSED_VAR (iface);
-  THRIFT_UNUSED_VAR (error);
-
-  printf ("blahBlah()\n");
-
-  return TRUE;
-}
-
 static void
 second_service_handler_init (SecondServiceHandler *self)
 {
@@ -76,7 +65,5 @@ second_service_handler_class_init (SecondServiceHandlerClass *klass)
 
   base_class->secondtest_string =
       second_service_handler_secondtest_string;
-  base_class->blah_blah =
-      second_service_handler_blah_blah;
 
 }

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt
index 1facfa4..cdd63db 100755
--- a/test/cpp/CMakeLists.txt
+++ b/test/cpp/CMakeLists.txt
@@ -34,6 +34,7 @@ include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
 include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
 
 set(crosstestgencpp_SOURCES
+    gen-cpp/SecondService.cpp
     gen-cpp/ThriftTest.cpp
     gen-cpp/ThriftTest_types.cpp
     gen-cpp/ThriftTest_constants.cpp
@@ -44,7 +45,7 @@ LINK_AGAINST_THRIFT_LIBRARY(crosstestgencpp thrift)
 
 set(crossstressgencpp_SOURCES
     gen-cpp/Service.cpp
-    #gen-cpp/StressTest_types.cpp #basically empty, so omitting
+    gen-cpp/StressTest_types.cpp
     gen-cpp/StressTest_constants.cpp
 )
 add_library(crossstressgencpp STATIC ${crossstressgencpp_SOURCES})
@@ -79,7 +80,7 @@ add_test(NAME StressTestNonBlocking COMMAND StressTestNonBlocking)
 # Common thrift code generation rules
 #
 
-add_custom_command(OUTPUT gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp
+add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp
     COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
 )
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/cpp/Makefile.am
----------------------------------------------------------------------
diff --git a/test/cpp/Makefile.am b/test/cpp/Makefile.am
index 359e7e6..e8be80a 100755
--- a/test/cpp/Makefile.am
+++ b/test/cpp/Makefile.am
@@ -21,12 +21,16 @@ AUTOMAKE_OPTIONS = subdir-objects serial-tests
 BUILT_SOURCES = gen-cpp/ThriftTest.cpp \
                 gen-cpp/ThriftTest_types.cpp \
                 gen-cpp/ThriftTest_constants.cpp \
+                gen-cpp/SecondService.cpp \
                 gen-cpp/StressTest_types.cpp \
                 gen-cpp/StressTest_constants.cpp \
                 gen-cpp/Service.cpp
 
 noinst_LTLIBRARIES = libtestgencpp.la libstresstestgencpp.la
 nodist_libtestgencpp_la_SOURCES = \
+	gen-cpp/SecondService.cpp \
+	gen-cpp/SecondService.h \
+	gen-cpp/SecondService.tcc \
 	gen-cpp/ThriftTest_constants.cpp \
 	gen-cpp/ThriftTest_constants.h \
 	gen-cpp/ThriftTest_types.cpp \
@@ -98,7 +102,7 @@ StressTestNonBlocking_LDADD = \
 #
 # Common thrift code generation rules
 #
-gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
+gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen cpp:templates,cob_style -r $<
 
 gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT)

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/cpp/src/TestClient.cpp
----------------------------------------------------------------------
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index 6b2e731..6e7ff8e 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -26,6 +26,7 @@
 #include <thrift/protocol/TCompactProtocol.h>
 #include <thrift/protocol/THeaderProtocol.h>
 #include <thrift/protocol/TJSONProtocol.h>
+#include <thrift/protocol/TMultiplexedProtocol.h>
 #include <thrift/transport/THttpClient.h>
 #include <thrift/transport/TTransportUtils.h>
 #include <thrift/transport/TSocket.h>
@@ -40,13 +41,15 @@
 #include <inttypes.h>
 #endif
 
-#include <boost/program_options.hpp>
+#include <boost/algorithm/string.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/program_options.hpp>
 #include <thrift/stdcxx.h>
 #if _WIN32
 #include <thrift/windows/TWinsockSingleton.h>
 #endif
 
+#include "SecondService.h"
 #include "ThriftTest.h"
 
 using namespace std;
@@ -156,28 +159,33 @@ int main(int argc, char** argv) {
   int return_code = 0;
 
   boost::program_options::options_description desc("Allowed options");
-  desc.add_options()("help,h",
-                     "produce help message")("host",
-                                             boost::program_options::value<string>(&host)
-                                                 ->default_value(host),
-                                             "Host to connect")("port",
-                                                                boost::program_options::value<int>(
-                                                                    &port)->default_value(port),
-                                                                "Port number to connect")(
-      "domain-socket",
-      boost::program_options::value<string>(&domain_socket)->default_value(domain_socket),
-      "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")(
-      "abstract-namespace",
-      "Look for the domain socket in the Abstract Namespace (no connection with filesystem pathnames)")(
-      "transport",
-      boost::program_options::value<string>(&transport_type)->default_value(transport_type),
-      "Transport: buffered, framed, http, evhttp")(
-      "protocol",
-      boost::program_options::value<string>(&protocol_type)->default_value(protocol_type),
-      "Protocol: binary, header, compact, json")("ssl", "Encrypted Transport using SSL")(
-      "testloops,n",
-      boost::program_options::value<int>(&numTests)->default_value(numTests),
-      "Number of Tests")("noinsane", "Do not run insanity test");
+  desc.add_options()
+      ("help,h", "produce help message")
+      ("host", 
+          boost::program_options::value<string>(&host)->default_value(host), 
+          "Host to connect")
+      ("port", 
+          boost::program_options::value<int>(&port)->default_value(port), 
+          "Port number to connect")
+      ("domain-socket", 
+          boost::program_options::value<string>(&domain_socket)->default_value(domain_socket),
+          "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
+      ("abstract-namespace",
+          "Look for the domain socket in the Abstract Namespace"
+          " (no connection with filesystem pathnames)")
+      ("transport",
+          boost::program_options::value<string>(&transport_type)->default_value(transport_type),
+          "Transport: buffered, framed, http, evhttp")
+      ("protocol",
+          boost::program_options::value<string>(&protocol_type)->default_value(protocol_type),
+          "Protocol: binary, compact, header, json, multi, multic, multih, multij")
+      ("ssl", 
+          "Encrypted Transport using SSL")
+      ("testloops,n",
+          boost::program_options::value<int>(&numTests)->default_value(numTests),
+          "Number of Tests")
+      ("noinsane",
+          "Do not run insanity test");
 
   boost::program_options::variables_map vm;
   boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
@@ -194,6 +202,10 @@ int main(int argc, char** argv) {
       } else if (protocol_type == "compact") {
       } else if (protocol_type == "header") {
       } else if (protocol_type == "json") {
+      } else if (protocol_type == "multi") {
+      } else if (protocol_type == "multic") {
+      } else if (protocol_type == "multih") {
+      } else if (protocol_type == "multij") {
       } else {
         throw invalid_argument("Unknown protocol type " + protocol_type);
       }
@@ -232,6 +244,7 @@ int main(int argc, char** argv) {
   stdcxx::shared_ptr<TSocket> socket;
   stdcxx::shared_ptr<TTransport> transport;
   stdcxx::shared_ptr<TProtocol> protocol;
+  stdcxx::shared_ptr<TProtocol> protocol2;	// SecondService for multiplexed
 
   if (ssl) {
     cout << "Client Certificate File: " << certPath << endl;
@@ -271,18 +284,20 @@ int main(int argc, char** argv) {
     transport = bufferedSocket;
   }
 
-  if (protocol_type.compare("json") == 0) {
-    stdcxx::shared_ptr<TProtocol> jsonProtocol(new TJSONProtocol(transport));
-    protocol = jsonProtocol;
-  } else if (protocol_type.compare("compact") == 0) {
-    stdcxx::shared_ptr<TProtocol> compactProtocol(new TCompactProtocol(transport));
-    protocol = compactProtocol;
-  } else if (protocol_type == "header") {
-    stdcxx::shared_ptr<TProtocol> headerProtocol(new THeaderProtocol(transport));
-    protocol = headerProtocol;
+  if (protocol_type == "json" || protocol_type == "multij") {
+    protocol = stdcxx::make_shared<TJSONProtocol>(transport);
+  } else if (protocol_type == "compact" || protocol_type == "multic") {
+    protocol = stdcxx::make_shared<TCompactProtocol>(transport);
+  } else if (protocol_type == "header" || protocol_type == "multih") {
+    protocol = stdcxx::make_shared<THeaderProtocol>(transport);
   } else {
-    stdcxx::shared_ptr<TBinaryProtocol> binaryProtocol(new TBinaryProtocol(transport));
-    protocol = binaryProtocol;
+    protocol = stdcxx::make_shared<TBinaryProtocol>(transport);
+  }
+
+  if (boost::starts_with(protocol_type, "multi")) {
+	protocol2 = stdcxx::make_shared<TMultiplexedProtocol>(protocol, "SecondService");
+	// we don't need access to the original protocol any more, so...
+	protocol = stdcxx::make_shared<TMultiplexedProtocol>(protocol, "ThriftTest");
   }
 
   // Connection info
@@ -367,6 +382,25 @@ int main(int argc, char** argv) {
       return_code |= ERR_BASETYPES;
     }
 
+    //
+    // Multiplexed protocol - call another service method
+    // in the middle of the ThriftTest
+    //
+    if (boost::starts_with(protocol_type, "multi")) {
+		SecondServiceClient ssc(protocol2);
+		// transport is already open...
+		  
+        try {
+          cout << "secondService.secondTestString(\"foo\") => " << flush;
+	  	  std::string result;
+		  ssc.secondtestString(result, "foo");
+		  cout << "{" << result << "}" << endl;
+	    } catch (std::exception& e) {
+		  cout << "  *** FAILED *** " << e.what() << endl;
+		  return_code |= ERR_EXCEPTIONS;
+		}
+    }
+
     try {
 #ifdef _MSC_VER
 #pragma warning( push )
@@ -1096,12 +1130,14 @@ int main(int argc, char** argv) {
     /**
      * I32 TEST
      */
-    cout << "re-test testI32(-1)";
+    cout << "re-test testI32(-1)" << flush;
     int i32 = testClient.testI32(-1);
     cout << " = " << i32 << endl;
     if (i32 != -1)
       return_code |= ERR_BASETYPES;
 
+    cout << endl << "All tests done." << endl << flush;
+    
     uint64_t stop = now();
     uint64_t tot = stop - start;
 
@@ -1115,10 +1151,10 @@ int main(int argc, char** argv) {
       time_max = tot;
     }
 
+    cout << flush;
     transport->close();
   }
 
-  cout << endl << "All tests done." << endl;
 
   uint64_t time_avg = time_tot / numTests;
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/cpp/src/TestServer.cpp
----------------------------------------------------------------------
diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp
index 37d0eb6..744a86c 100644
--- a/test/cpp/src/TestServer.cpp
+++ b/test/cpp/src/TestServer.cpp
@@ -17,26 +17,29 @@
  * under the License.
  */
 
-#include <thrift/concurrency/ThreadManager.h>
+#include <thrift/async/TAsyncBufferProcessor.h>
+#include <thrift/async/TAsyncProtocolProcessor.h>
+#include <thrift/async/TEvhttpServer.h>
 #include <thrift/concurrency/PlatformThreadFactory.h>
+#include <thrift/concurrency/ThreadManager.h>
+#include <thrift/processor/TMultiplexedProcessor.h>
 #include <thrift/protocol/TBinaryProtocol.h>
 #include <thrift/protocol/TCompactProtocol.h>
 #include <thrift/protocol/THeaderProtocol.h>
 #include <thrift/protocol/TJSONProtocol.h>
+#include <thrift/server/TNonblockingServer.h>
 #include <thrift/server/TSimpleServer.h>
-#include <thrift/server/TThreadedServer.h>
 #include <thrift/server/TThreadPoolServer.h>
-#include <thrift/async/TEvhttpServer.h>
-#include <thrift/async/TAsyncBufferProcessor.h>
-#include <thrift/async/TAsyncProtocolProcessor.h>
-#include <thrift/server/TNonblockingServer.h>
-#include <thrift/transport/TServerSocket.h>
-#include <thrift/transport/TSSLServerSocket.h>
-#include <thrift/transport/TSSLSocket.h>
-#include <thrift/transport/TNonblockingServerSocket.h>
+#include <thrift/server/TThreadedServer.h>
 #include <thrift/transport/THttpServer.h>
 #include <thrift/transport/THttpTransport.h>
+#include <thrift/transport/TNonblockingServerSocket.h>
+#include <thrift/transport/TSSLServerSocket.h>
+#include <thrift/transport/TSSLSocket.h>
+#include <thrift/transport/TServerSocket.h>
 #include <thrift/transport/TTransportUtils.h>
+
+#include "SecondService.h"
 #include "ThriftTest.h"
 
 #ifdef HAVE_STDINT_H
@@ -50,6 +53,7 @@
 #include <stdexcept>
 #include <sstream>
 
+#include <boost/algorithm/string.hpp>
 #include <boost/program_options.hpp>
 #include <boost/filesystem.hpp>
 #include <thrift/stdcxx.h>
@@ -331,13 +335,18 @@ public:
     }
   }
 
-  void testOneway(const int32_t sleepFor) {
-    printf("testOneway(%d): Sleeping...\n", sleepFor);
-    THRIFT_SLEEP_SEC(sleepFor);
-    printf("testOneway(%d): done sleeping!\n", sleepFor);
+  void testOneway(const int32_t aNum) {
+    printf("testOneway(%d): call received\n", aNum);
   }
 };
 
+class SecondHandler : public SecondServiceIf
+{
+  public:
+    void secondtestString(std::string& result, const std::string& thing)
+    { result = "testString(\"" + thing + "\")"; }
+};	
+
 class TestProcessorEventHandler : public TProcessorEventHandler {
   virtual void* getContext(const char* fn_name, void* serverContext) {
     (void)serverContext;
@@ -565,7 +574,7 @@ int main(int argc, char** argv) {
     ("abstract-namespace", "Create the domain socket in the Abstract Namespace (no connection with filesystem pathnames)")
     ("server-type", po::value<string>(&server_type)->default_value(server_type), "type of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\"")
     ("transport", po::value<string>(&transport_type)->default_value(transport_type), "transport: buffered, framed, http")
-    ("protocol", po::value<string>(&protocol_type)->default_value(protocol_type), "protocol: binary, compact, header, json")
+    ("protocol", po::value<string>(&protocol_type)->default_value(protocol_type), "protocol: binary, compact, header, json, multi, multic, multih, multij")
     ("ssl", "Encrypted Transport using SSL")
     ("processor-events", "processor-events")
     ("workers,n", po::value<size_t>(&workers)->default_value(workers), "Number of thread pools workers. Only valid for thread-pool server type")
@@ -597,6 +606,10 @@ int main(int argc, char** argv) {
       } else if (protocol_type == "compact") {
       } else if (protocol_type == "json") {
       } else if (protocol_type == "header") {
+      } else if (protocol_type == "multi") {	// multiplexed binary
+      } else if (protocol_type == "multic") {	// multiplexed compact
+      } else if (protocol_type == "multih") {	// multiplexed header
+      } else if (protocol_type == "multij") {	// multiplexed json
       } else {
         throw invalid_argument("Unknown protocol type " + protocol_type);
       }
@@ -627,15 +640,15 @@ int main(int argc, char** argv) {
 
   // Dispatcher
   stdcxx::shared_ptr<TProtocolFactory> protocolFactory;
-  if (protocol_type == "json") {
+  if (protocol_type == "json" || protocol_type == "multij") {
     stdcxx::shared_ptr<TProtocolFactory> jsonProtocolFactory(new TJSONProtocolFactory());
     protocolFactory = jsonProtocolFactory;
-  } else if (protocol_type == "compact") {
+  } else if (protocol_type == "compact" || protocol_type == "multic") {
     TCompactProtocolFactoryT<TBufferBase> *compactProtocolFactory = new TCompactProtocolFactoryT<TBufferBase>();
     compactProtocolFactory->setContainerSizeLimit(container_limit);
     compactProtocolFactory->setStringSizeLimit(string_limit);
     protocolFactory.reset(compactProtocolFactory);
-  } else if (protocol_type == "header") {
+  } else if (protocol_type == "header" || protocol_type == "multih") {
     stdcxx::shared_ptr<TProtocolFactory> headerProtocolFactory(new THeaderProtocolFactory());
     protocolFactory = headerProtocolFactory;
   } else {
@@ -645,9 +658,9 @@ int main(int argc, char** argv) {
     protocolFactory.reset(binaryProtocolFactory);
   }
 
-  // Processor
+  // Processors
   stdcxx::shared_ptr<TestHandler> testHandler(new TestHandler());
-  stdcxx::shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
+  stdcxx::shared_ptr<TProcessor> testProcessor(new ThriftTestProcessor(testHandler));
 
   if (vm.count("processor-events")) {
     testProcessor->setEventHandler(
@@ -706,6 +719,18 @@ int main(int argc, char** argv) {
   }
   cout << endl;
 
+  // Multiplexed Processor if needed
+  if (boost::starts_with(protocol_type, "multi")) {
+    stdcxx::shared_ptr<SecondHandler> secondHandler(new SecondHandler());
+    stdcxx::shared_ptr<SecondServiceProcessor> secondProcessor(new SecondServiceProcessor(secondHandler));
+
+    stdcxx::shared_ptr<TMultiplexedProcessor> multiplexedProcessor(new TMultiplexedProcessor());
+    multiplexedProcessor->registerDefault(testProcessor); // non-multi clients go to the default processor (multi:binary, multic:compact, ...)
+    multiplexedProcessor->registerProcessor("ThriftTest", testProcessor);
+    multiplexedProcessor->registerProcessor("SecondService", secondProcessor);
+    testProcessor = stdcxx::dynamic_pointer_cast<TProcessor>(multiplexedProcessor);
+  }
+
   // Server
   stdcxx::shared_ptr<apache::thrift::server::TServer> server;
 

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/csharp/TestClient.cs
----------------------------------------------------------------------
diff --git a/test/csharp/TestClient.cs b/test/csharp/TestClient.cs
index fad1057..17e5978 100644
--- a/test/csharp/TestClient.cs
+++ b/test/csharp/TestClient.cs
@@ -33,7 +33,7 @@ namespace Test
 {
     public class TestClient
     {
-        private class TestParams
+        public class TestParams
         {
             public int numIterations = 1;
             public string host = "localhost";
@@ -44,6 +44,7 @@ namespace Test
             public bool framed;
             public string protocol;
             public bool encrypted = false;
+            public bool multiplexed = false;
             protected bool _isFirstTransport = true;
 
 
@@ -105,21 +106,30 @@ namespace Test
         private const int ErrorStructs = 2;
         private const int ErrorContainers = 4;
         private const int ErrorExceptions = 8;
+        private const int ErrorProtocol = 16;
         private const int ErrorUnknown = 64;
 
         private class ClientTest
         {
+            private readonly TestParams param;
             private readonly TTransport transport;
+            private readonly SecondService.Client second;
             private readonly ThriftTest.Client client;
             private readonly int numIterations;
             private bool done;
 
             public int ReturnCode { get; set; }
 
-            public ClientTest(TestParams param)
+            public ClientTest(TestParams paramin)
             {
+                param = paramin;
                 transport = param.CreateTransport();
-                client = new ThriftTest.Client(param.CreateProtocol(transport));
+                TProtocol protocol = param.CreateProtocol(transport);
+                if (param.multiplexed)
+                {
+                    second = new SecondService.Client(new TMultiplexedProtocol(protocol, "SecondService"));
+                }
+                client = new ThriftTest.Client(protocol);
                 numIterations = param.numIterations;
             }
             public void Execute()
@@ -148,7 +158,7 @@ namespace Test
 
                     try
                     {
-                        ReturnCode |= ExecuteClientTest(client);
+                        ReturnCode |= ExecuteClientTest(client, second, param);
                     }
                     catch (Exception ex)
                     {
@@ -215,12 +225,12 @@ namespace Test
                         {
                             numThreads = Convert.ToInt32(args[++i]);
                         }
-                        else if (args[i] == "--compact" || args[i] == "--protocol=compact")
+                        else if (args[i] == "--compact" || args[i] == "--protocol=compact" || args[i] == "--protocol=multic")
                         {
                             param.protocol = "compact";
                             Console.WriteLine("Using compact protocol");
                         }
-                        else if (args[i] == "--json" || args[i] == "--protocol=json")
+                        else if (args[i] == "--json" || args[i] == "--protocol=json" || args[i] == "--protocol=multij")
                         {
                             param.protocol = "json";
                             Console.WriteLine("Using JSON protocol");
@@ -230,6 +240,11 @@ namespace Test
                             param.encrypted = true;
                             Console.WriteLine("Using encrypted transport");
                         }
+
+                        if (args[i].StartsWith("--protocol=multi"))
+                        {
+                            param.multiplexed = true;
+                        }
                     }
                 }
                 catch (Exception ex)
@@ -296,7 +311,7 @@ namespace Test
             return retval;
         }
 
-        public static int ExecuteClientTest(ThriftTest.Client client)
+        public static int ExecuteClientTest(ThriftTest.Client client, SecondService.Client second, TestParams param)
         {
             int returnCode = 0;
 
@@ -313,6 +328,18 @@ namespace Test
                 returnCode |= ErrorBaseTypes;
             }
 
+            if (param.multiplexed)
+            {
+                Console.WriteLine("secondTestString(\"Test2\")");
+                s = second.secondtestString("Test2");
+              Console.WriteLine(" = \"" + s + "\"");
+              if ("testString(\"Test2\")" != s)
+              {
+                  Console.WriteLine("*** FAILED ***");
+                  returnCode |= ErrorProtocol;
+              }
+            }
+
             Console.Write("testBool(true)");
             bool t = client.testBool((bool)true);
             Console.WriteLine(" = " + t);

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/features/known_failures_Linux.json
----------------------------------------------------------------------
diff --git a/test/features/known_failures_Linux.json b/test/features/known_failures_Linux.json
index e3575f9..f96356d 100644
--- a/test/features/known_failures_Linux.json
+++ b/test/features/known_failures_Linux.json
@@ -1,6 +1,10 @@
 [
   "c_glib-limit_container_length_binary_buffered-ip",
   "c_glib-limit_string_length_binary_buffered-ip",
+  "cpp-theader_framed_binary_multih-header_buffered-ip",
+  "cpp-theader_framed_compact_multih-header_buffered-ip",
+  "cpp-theader_unframed_binary_multih-header_buffered-ip",
+  "cpp-theader_unframed_compact_multih-header_buffered-ip",
   "csharp-limit_container_length_binary_buffered-ip",
   "csharp-limit_container_length_compact_buffered-ip",
   "csharp-limit_string_length_binary_buffered-ip",
@@ -33,8 +37,10 @@
   "rb-limit_string_length_accel-binary_buffered-ip",
   "rb-limit_string_length_binary_buffered-ip",
   "rb-limit_string_length_compact_buffered-ip",
+  "rs-limit_container_length_binary_buffered-ip",
+  "rs-limit_container_length_compact_buffered-ip",
+  "rs-limit_container_length_multic-compact_buffered-ip",
   "rs-limit_string_length_binary_buffered-ip",
   "rs-limit_string_length_compact_buffered-ip",
-  "rs-limit_container_length_binary_buffered-ip",
-  "rs-limit_container_length_compact_buffered-ip"
-]
+  "rs-limit_string_length_multic-compact_buffered-ip"
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/known_failures_Linux.json
----------------------------------------------------------------------
diff --git a/test/known_failures_Linux.json b/test/known_failures_Linux.json
index eda5df0..ea194a1 100644
--- a/test/known_failures_Linux.json
+++ b/test/known_failures_Linux.json
@@ -1,38 +1,90 @@
 [
-  "cpp-cpp_binary_buffered-ip-ssl",
-  "cpp-cpp_binary_framed-ip-ssl",
+  "c_glib-csharp_multi-binary_buffered-ip",
+  "c_glib-csharp_multi-binary_framed-ip",
+  "c_glib-csharp_multi_buffered-ip",
+  "c_glib-csharp_multi_framed-ip",
+  "c_glib-csharp_multic_buffered-ip",
+  "c_glib-csharp_multic-compact_buffered-ip",
+  "c_glib-csharp_multic-compact_framed-ip",
+  "c_glib-csharp_multic_framed-ip",
+  "c_glib-rs_multi_buffered-ip",
+  "c_glib-rs_multi_framed-ip",
+  "c_glib-rs_multic_buffered-ip",
+  "c_glib-rs_multic_framed-ip",
   "cpp-cpp_binary_http-domain",
-  "cpp-cpp_binary_http-ip-ssl",
-  "cpp-cpp_compact_buffered-ip-ssl",
-  "cpp-cpp_compact_framed-ip-ssl",
-  "cpp-cpp_compact_http-ip-ssl",
-  "cpp-cpp_header_buffered-ip-ssl",
-  "cpp-cpp_header_framed-ip-ssl",
-  "cpp-cpp_header_http-ip-ssl",
-  "cpp-cpp_json_buffered-ip-ssl",
-  "cpp-cpp_json_framed-ip-ssl",
-  "cpp-cpp_json_http-ip-ssl",
+  "cpp-cpp_compact_http-domain",
+  "cpp-cpp_compact_http-ip",
+  "cpp-cpp_header_http-domain",
+  "cpp-cpp_json_http-domain",
+  "cpp-cpp_json_http-ip",
+  "cpp-cpp_multi-binary_http-domain",
+  "cpp-cpp_multi-binary_http-ip",
+  "cpp-cpp_multi_http-domain",
+  "cpp-cpp_multi_http-ip",
+  "cpp-cpp_multic-compact_http-domain",
+  "cpp-cpp_multic-compact_http-ip",
+  "cpp-cpp_multic_http-domain",
+  "cpp-cpp_multic_http-ip",
+  "cpp-cpp_multih-header_http-domain",
+  "cpp-cpp_multih-header_http-ip",
+  "cpp-cpp_multih_http-domain",
+  "cpp-cpp_multih_http-ip",
+  "cpp-cpp_multij-json_http-domain",
+  "cpp-cpp_multij-json_http-ip",
+  "cpp-cpp_multij_http-domain",
+  "cpp-cpp_multij_http-ip",
   "cpp-dart_binary_http-ip",
   "cpp-dart_compact_http-ip",
   "cpp-dart_json_http-ip",
+  "cpp-dart_multi-binary_http-ip",
+  "cpp-dart_multic-compact_http-ip",
+  "cpp-dart_multij-json_http-ip",
   "cpp-go_binary_http-ip",
   "cpp-go_binary_http-ip-ssl",
   "cpp-go_compact_http-ip",
   "cpp-go_compact_http-ip-ssl",
   "cpp-go_json_http-ip",
   "cpp-go_json_http-ip-ssl",
+  "cpp-go_multi-binary_http-ip",
+  "cpp-go_multi-binary_http-ip-ssl",
+  "cpp-go_multic-compact_http-ip",
+  "cpp-go_multic-compact_http-ip-ssl",
+  "cpp-go_multij-json_http-ip",
+  "cpp-go_multij-json_http-ip-ssl",
   "cpp-java_binary_http-ip",
   "cpp-java_binary_http-ip-ssl",
   "cpp-java_compact_http-ip",
   "cpp-java_compact_http-ip-ssl",
   "cpp-java_json_http-ip",
   "cpp-java_json_http-ip-ssl",
+  "cpp-java_multi-binary_http-ip",
+  "cpp-java_multi-binary_http-ip-ssl",
+  "cpp-java_multi_http-ip",
+  "cpp-java_multi_http-ip-ssl",
+  "cpp-java_multic-compact_http-ip",
+  "cpp-java_multic-compact_http-ip-ssl",
+  "cpp-java_multic_http-ip",
+  "cpp-java_multic_http-ip-ssl",
+  "cpp-java_multij-json_http-ip",
+  "cpp-java_multij-json_http-ip-ssl",
+  "cpp-java_multij_http-ip",
+  "cpp-java_multij_http-ip-ssl",
   "cpp-nodejs_binary_http-ip",
   "cpp-nodejs_binary_http-ip-ssl",
   "cpp-nodejs_compact_http-ip",
   "cpp-nodejs_compact_http-ip-ssl",
   "cpp-nodejs_json_http-ip",
   "cpp-nodejs_json_http-ip-ssl",
+  "cpp-nodejs_multi-binary_http-ip",
+  "cpp-nodejs_multi-binary_http-ip-ssl",
+  "cpp-nodejs_multic-compact_http-ip",
+  "cpp-nodejs_multic-compact_http-ip-ssl",
+  "cpp-nodejs_multij-json_http-ip",
+  "cpp-nodejs_multij-json_http-ip-ssl",
+  "cpp-rs_multi_buffered-ip",
+  "cpp-rs_multi_framed-ip",
+  "cpp-rs_multic_buffered-ip",
+  "cpp-rs_multic_framed-ip",
   "csharp-d_binary_buffered-ip-ssl",
   "csharp-d_binary_framed-ip-ssl",
   "csharp-d_compact_buffered-ip-ssl",
@@ -246,9 +298,19 @@
   "nodejs-netcore_json_framed-ip",
   "nodejs-netcore_json_framed-ip-ssl",
   "rs-csharp_binary_buffered-ip",
-  "rs-csharp_compact_buffered-ip",
   "rs-csharp_binary_framed-ip",
+  "rs-csharp_compact_buffered-ip",
   "rs-csharp_compact_framed-ip",
+  "rs-csharp_multi-binary_buffered-ip",
+  "rs-csharp_multi-binary_framed-ip",
+  "rs-csharp_multi_buffered-ip",
+  "rs-csharp_multi_framed-ip",
+  "rs-csharp_multic-compact_buffered-ip",
+  "rs-csharp_multic-compact_framed-ip",
+  "rs-csharp_multic_buffered-ip",
+  "rs-csharp_multic_framed-ip",
   "rs-dart_binary_framed-ip",
-  "rs-dart_compact_framed-ip"
+  "rs-dart_compact_framed-ip",
+  "rs-dart_multi-binary_framed-ip",
+  "rs-dart_multic-compact_framed-ip"
 ]

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/rs/src/bin/test_client.rs
----------------------------------------------------------------------
diff --git a/test/rs/src/bin/test_client.rs b/test/rs/src/bin/test_client.rs
index d720313..7c11ad5 100644
--- a/test/rs/src/bin/test_client.rs
+++ b/test/rs/src/bin/test_client.rs
@@ -287,18 +287,6 @@ fn make_thrift_calls(
 
     // do the multiplexed calls while making the main ThriftTest calls
     if let Some(ref mut client) = second_service_client.as_mut() {
-        info!("SecondService blahBlah");
-        {
-            let r = client.blah_blah();
-            match r {
-                Err(thrift::Error::Application(ref e)) => {
-                    info!("received an {:?}", e);
-                    Ok(())
-                }
-                _ => Err(thrift::Error::User("did not get exception".into())),
-            }?;
-        }
-
         info!("SecondService secondtestString");
         {
             verify_expected_result(

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/rs/src/bin/test_server.rs
----------------------------------------------------------------------
diff --git a/test/rs/src/bin/test_server.rs b/test/rs/src/bin/test_server.rs
index a32e938..81a2ad8 100644
--- a/test/rs/src/bin/test_server.rs
+++ b/test/rs/src/bin/test_server.rs
@@ -390,10 +390,6 @@ impl ThriftTestSyncHandler for ThriftTestSyncHandlerImpl {
 
 struct SecondServiceSyncHandlerImpl;
 impl SecondServiceSyncHandler for SecondServiceSyncHandlerImpl {
-    fn handle_blah_blah(&self) -> thrift::Result<()> {
-        Err(thrift::new_application_error(thrift::ApplicationErrorKind::Unknown, "blahBlah"),)
-    }
-
     fn handle_secondtest_string(&self, thing: String) -> thrift::Result<String> {
         info!("testString({})", &thing);
         let ret = format!("testString(\"{}\")", &thing);

http://git-wip-us.apache.org/repos/asf/thrift/blob/58402ff6/test/tests.json
----------------------------------------------------------------------
diff --git a/test/tests.json b/test/tests.json
index c1c3155..bde9014 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -11,9 +11,7 @@
       ],
       "protocols": [
         "binary:multi",
-        "compact:multic",
-        "multi",
-        "multic"
+        "compact:multic"
       ]
     },
     "client": {
@@ -22,8 +20,6 @@
         "--lt-debug"
       ],
       "protocols": [
-        "multi",
-        "multic",
         "multi:binary",
         "multic:compact"
       ],
@@ -40,7 +36,9 @@
     ],
     "protocols": [
       "binary",
-      "compact"
+      "compact",
+      "multi",
+      "multic"
     ],
     "workdir": "c_glib"
   },
@@ -124,10 +122,7 @@
       "protocols": [
         "binary:multi",
         "compact:multic",
-        "json:multij",
-        "multi",
-        "multic",
-        "multij"
+        "json:multij"
       ]
     },
     "client": {
@@ -135,6 +130,11 @@
       "extra_args": ["run-testclient"],
       "transports": [
         "http"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact",
+        "multij:json"
       ]
     },
     "transports": [
@@ -149,7 +149,10 @@
     "protocols": [
       "binary",
       "compact",
-      "json"
+      "json",
+      "multi",
+      "multic",
+      "multij"
     ],
     "workdir": "../lib/java"
   },
@@ -298,12 +301,24 @@
     "server": {
       "command": [
         "TestServer"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic",
+        "header:multih",
+        "json:multij"
       ]
     },
     "client": {
       "timeout": 8,
       "command": [
         "TestClient"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact",
+        "multih:header",
+        "multij:json"
       ]
     },
     "transports": [
@@ -320,7 +335,11 @@
       "compact",
       "binary",
       "json",
-      "header"
+      "header",
+      "multi",
+      "multic",
+      "multih",
+      "multij"
     ],
     "workdir": "cpp"
   },
@@ -385,6 +404,12 @@
         "mono",
         "TestClientServer.exe",
         "client"
+      ],
+      "protocols": [
+        "multi",
+        "multic",
+        "multi:binary",
+        "multic:compact"
       ]
     },
     "workdir": "csharp"
@@ -408,9 +433,9 @@
       "command": [
         "dotnet",
         "run",
-	"--no-build",
-	"--no-restore",
-	"--",
+  "--no-build",
+  "--no-restore",
+  "--",
         "server"
       ]
     },
@@ -419,9 +444,9 @@
       "command": [
         "dotnet",
         "run",
-	"--no-build",
-	"--no-restore",
-	"--",
+  "--no-build",
+  "--no-restore",
+  "--",
         "client"
       ]
     },
@@ -622,12 +647,20 @@
     "server": {
       "command": [
         "test_server"
+      ],
+      "protocols": [
+        "binary:multi",
+        "compact:multic"
       ]
     },
     "client": {
       "timeout": 6,
       "command": [
         "test_client"
+      ],
+      "protocols": [
+        "multi:binary",
+        "multic:compact"
       ]
     },
     "sockets": [