Merge pull request #7762 from KindDragon/master

Fix CMake for windows (VS2015)
diff --git a/.gitmodules b/.gitmodules
index d41b8d5..92d5ac3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -17,3 +17,6 @@
 [submodule "third_party/nanopb"]
 	path = third_party/nanopb
 	url = https://github.com/nanopb/nanopb.git
+[submodule "third_party/thrift"]
+	path = third_party/thrift
+	url = https://github.com/apache/thrift.git
diff --git a/Makefile b/Makefile
index 7cef08c..2db87e8 100644
--- a/Makefile
+++ b/Makefile
@@ -800,13 +800,6 @@
 NO_DEPS = true
 endif
 
-INSTALL_OK = false
-ifeq ($(HAS_VALID_PROTOC),true)
-ifeq ($(HAS_SYSTEM_PROTOBUF_VERIFY),true)
-INSTALL_OK = true
-endif
-endif
-
 .SECONDARY = %.pb.h %.pb.cc
 
 ifeq ($(DEP_MISSING),)
@@ -1049,6 +1042,7 @@
 grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin
 grpc_python_plugin: $(BINDIR)/$(CONFIG)/grpc_python_plugin
 grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
+grpc_tool_test: $(BINDIR)/$(CONFIG)/grpc_tool_test
 grpclb_api_test: $(BINDIR)/$(CONFIG)/grpclb_api_test
 grpclb_test: $(BINDIR)/$(CONFIG)/grpclb_test
 hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
@@ -1407,6 +1401,7 @@
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
   $(BINDIR)/$(CONFIG)/grpc_cli \
+  $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
   $(BINDIR)/$(CONFIG)/grpclb_test \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
@@ -1493,6 +1488,7 @@
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
   $(BINDIR)/$(CONFIG)/grpc_cli \
+  $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
   $(BINDIR)/$(CONFIG)/grpclb_test \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
@@ -1784,6 +1780,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing golden_file_test"
 	$(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_tool_test"
+	$(Q) $(BINDIR)/$(CONFIG)/grpc_tool_test || ( echo test grpc_tool_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpclb_api_test"
 	$(Q) $(BINDIR)/$(CONFIG)/grpclb_api_test || ( echo test grpclb_api_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpclb_test"
@@ -2163,7 +2161,7 @@
 	$(Q) mkdir -p `dirname $@`
 	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
-install: install_c install_cxx install-plugins install-certs verify-install
+install: install_c install_cxx install-plugins install-certs
 
 install_c: install-headers_c install-static_c install-shared_c
 
@@ -2346,28 +2344,6 @@
 	$(Q) $(INSTALL) -d $(prefix)/share/grpc
 	$(Q) $(INSTALL) etc/roots.pem $(prefix)/share/grpc/roots.pem
 
-verify-install:
-ifeq ($(INSTALL_OK),true)
-	@echo "Your system looks ready to go."
-	@echo
-else
-	@echo "Warning: it looks like protoc 3.0.0+ isn't installed on your system,"
-	@echo "which means that you won't be able to compile .proto files for use"
-	@echo "with gRPC."
-	@echo
-	@echo "If you are just using pre-compiled protocol buffers, or you otherwise"
-	@echo "have no need to compile .proto files, you can ignore this."
-	@echo
-	@echo "If you do need protobuf for some reason, you can download and install"
-	@echo "it from:"
-	@echo
-	@echo "   https://github.com/google/protobuf/releases"
-	@echo
-	@echo "Once you've done so, you can re-run this check by doing:"
-	@echo
-	@echo "   make verify-install"
-endif
-
 clean:
 	$(E) "[CLEAN]   Cleaning build directories."
 	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) cache.mk
@@ -4060,6 +4036,8 @@
     include/grpc/impl/codegen/time.h \
     include/grpc++/impl/codegen/proto_utils.h \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/thrift_serializer.h \
+    include/grpc++/impl/codegen/thrift_utils.h \
 
 LIBGRPC++_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_TEST_UTIL_SRC))))
 
@@ -4294,6 +4272,8 @@
 
 LIBGRPC_CLI_LIBS_SRC = \
     test/cpp/util/cli_call.cc \
+    test/cpp/util/cli_credentials.cc \
+    test/cpp/util/grpc_tool.cc \
     test/cpp/util/proto_file_parser.cc \
     test/cpp/util/proto_reflection_descriptor_database.cc \
 
@@ -11331,16 +11311,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_cli
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_cli
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_cli.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_cli.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 
 deps_grpc_cli: $(GRPC_CLI_OBJS:.o=.dep)
 
@@ -11537,6 +11517,60 @@
 endif
 
 
+GRPC_TOOL_TEST_SRC = \
+    $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
+    test/cpp/util/grpc_tool_test.cc \
+    test/cpp/util/string_ref_helper.cc \
+
+GRPC_TOOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_TOOL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpc_tool_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/grpc_tool_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_tool_test: $(PROTOBUF_DEP) $(GRPC_TOOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_TOOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_tool_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/echo.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/echo_messages.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_tool_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_grpc_tool_test: $(GRPC_TOOL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_TOOL_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_tool_test.o: $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+
+
 GRPCLB_API_TEST_SRC = \
     $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc \
     test/cpp/grpclb/grpclb_api_test.cc \
@@ -15300,7 +15334,9 @@
 test/cpp/util/benchmark_config.cc: $(OPENSSL_DEP)
 test/cpp/util/byte_buffer_proto_helper.cc: $(OPENSSL_DEP)
 test/cpp/util/cli_call.cc: $(OPENSSL_DEP)
+test/cpp/util/cli_credentials.cc: $(OPENSSL_DEP)
 test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP)
+test/cpp/util/grpc_tool.cc: $(OPENSSL_DEP)
 test/cpp/util/proto_file_parser.cc: $(OPENSSL_DEP)
 test/cpp/util/proto_reflection_descriptor_database.cc: $(OPENSSL_DEP)
 test/cpp/util/string_ref_helper.cc: $(OPENSSL_DEP)
diff --git a/build.yaml b/build.yaml
index 6ca2e9e..2f57859 100644
--- a/build.yaml
+++ b/build.yaml
@@ -789,6 +789,13 @@
   - src/cpp/ext/reflection.pb.cc
   uses:
   - grpc++_codegen_proto
+- name: thrift_util
+  language: c++
+  public_headers:
+  - include/grpc++/impl/codegen/thrift_serializer.h
+  - include/grpc++/impl/codegen/thrift_utils.h
+  uses:
+  - grpc++_codegen_base
 libs:
 - name: gpr
   build: all
@@ -1031,6 +1038,7 @@
   - grpc++_codegen_base_src
   - grpc++_codegen_proto
   - grpc++_config_proto
+  - thrift_util
 - name: grpc++_unsecure
   build: all
   language: c++
@@ -1052,16 +1060,21 @@
   language: c++
   headers:
   - test/cpp/util/cli_call.h
+  - test/cpp/util/cli_credentials.h
+  - test/cpp/util/config_grpc_cli.h
+  - test/cpp/util/grpc_tool.h
   - test/cpp/util/proto_file_parser.h
   - test/cpp/util/proto_reflection_descriptor_database.h
   src:
   - test/cpp/util/cli_call.cc
+  - test/cpp/util/cli_credentials.cc
+  - test/cpp/util/grpc_tool.cc
   - test/cpp/util/proto_file_parser.cc
   - test/cpp/util/proto_reflection_descriptor_database.cc
   deps:
   - grpc++_reflection
   - grpc++
-  - grpc_plugin_support
+  - grpc++_test_config
 - name: grpc_plugin_support
   build: protoc
   language: c++
@@ -2711,12 +2724,9 @@
   - test/cpp/util/grpc_cli.cc
   deps:
   - grpc_cli_libs
-  - grpc++_test_util
-  - grpc_test_util
   - grpc++_reflection
   - grpc++
   - grpc
-  - gpr_test_util
   - gpr
   - grpc++_test_config
 - name: grpc_cpp_plugin
@@ -2778,6 +2788,28 @@
   secure: false
   vs_config_type: Application
   vs_project_guid: '{069E9D05-B78B-4751-9252-D21EBAE7DE8E}'
+- name: grpc_tool_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - test/cpp/util/string_ref_helper.h
+  src:
+  - src/proto/grpc/testing/echo.proto
+  - src/proto/grpc/testing/echo_messages.proto
+  - test/cpp/util/grpc_tool_test.cc
+  - test/cpp/util/string_ref_helper.cc
+  deps:
+  - grpc_cli_libs
+  - grpc++_reflection
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  filegroups:
+  - grpc++_codegen_proto
+  - grpc++_config_proto
 - name: grpclb_api_test
   gtest: true
   build: test
diff --git a/examples/cpp/cpptutorial.md b/examples/cpp/cpptutorial.md
index de7e4b2..ae84aba 100644
--- a/examples/cpp/cpptutorial.md
+++ b/examples/cpp/cpptutorial.md
@@ -127,7 +127,7 @@
 service definition. We do this using the protocol buffer compiler `protoc` with
 a special gRPC C++ plugin.
 
-For simplicity, we've provided a [makefile](route_guide/Makefile) that runs
+For simplicity, we've provided a [Makefile](route_guide/Makefile) that runs
 `protoc` for you with the appropriate plugin, input, and output (if you want to
 run this yourself, make sure you've installed protoc and followed the gRPC code
 [installation instructions](../../INSTALL.md) first):
diff --git a/examples/csharp/helloworld-from-cli/Greeter/Helloworld.cs b/examples/csharp/helloworld-from-cli/Greeter/Helloworld.cs
new file mode 100644
index 0000000..6477b4f
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/Greeter/Helloworld.cs
@@ -0,0 +1,259 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: helloworld.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Helloworld {
+
+  /// <summary>Holder for reflection information generated from helloworld.proto</summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public static partial class HelloworldReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for helloworld.proto</summary>
+    public static pbr::FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr::FileDescriptor descriptor;
+
+    static HelloworldReflection() {
+      byte[] descriptorData = global::System.Convert.FromBase64String(
+          string.Concat(
+            "ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVz",
+            "dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo",
+            "CTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1Jl",
+            "cXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEI2Chtpby5ncnBjLmV4",
+            "YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXYgZw",
+            "cm90bzM="));
+      descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr::FileDescriptor[] { },
+          new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+            new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloRequest), global::Helloworld.HelloRequest.Parser, new[]{ "Name" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloReply), global::Helloworld.HelloReply.Parser, new[]{ "Message" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  /// <summary>
+  ///  The request message containing the user's name.
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HelloRequest : pb::IMessage<HelloRequest> {
+    private static readonly pb::MessageParser<HelloRequest> _parser = new pb::MessageParser<HelloRequest>(() => new HelloRequest());
+    public static pb::MessageParser<HelloRequest> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public HelloRequest() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public HelloRequest(HelloRequest other) : this() {
+      name_ = other.name_;
+    }
+
+    public HelloRequest Clone() {
+      return new HelloRequest(this);
+    }
+
+    /// <summary>Field number for the "name" field.</summary>
+    public const int NameFieldNumber = 1;
+    private string name_ = "";
+    public string Name {
+      get { return name_; }
+      set {
+        name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as HelloRequest);
+    }
+
+    public bool Equals(HelloRequest other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Name != other.Name) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Name.Length != 0) hash ^= Name.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Name.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Name);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Name.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+      }
+      return size;
+    }
+
+    public void MergeFrom(HelloRequest other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Name.Length != 0) {
+        Name = other.Name;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Name = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  ///  The response message containing the greetings
+  /// </summary>
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HelloReply : pb::IMessage<HelloReply> {
+    private static readonly pb::MessageParser<HelloReply> _parser = new pb::MessageParser<HelloReply>(() => new HelloReply());
+    public static pb::MessageParser<HelloReply> Parser { get { return _parser; } }
+
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[1]; }
+    }
+
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    public HelloReply() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    public HelloReply(HelloReply other) : this() {
+      message_ = other.message_;
+    }
+
+    public HelloReply Clone() {
+      return new HelloReply(this);
+    }
+
+    /// <summary>Field number for the "message" field.</summary>
+    public const int MessageFieldNumber = 1;
+    private string message_ = "";
+    public string Message {
+      get { return message_; }
+      set {
+        message_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    public override bool Equals(object other) {
+      return Equals(other as HelloReply);
+    }
+
+    public bool Equals(HelloReply other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Message != other.Message) return false;
+      return true;
+    }
+
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Message.Length != 0) hash ^= Message.GetHashCode();
+      return hash;
+    }
+
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (Message.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Message);
+      }
+    }
+
+    public int CalculateSize() {
+      int size = 0;
+      if (Message.Length != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
+      }
+      return size;
+    }
+
+    public void MergeFrom(HelloReply other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Message.Length != 0) {
+        Message = other.Message;
+      }
+    }
+
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 10: {
+            Message = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/examples/csharp/helloworld-from-cli/Greeter/HelloworldGrpc.cs b/examples/csharp/helloworld-from-cli/Greeter/HelloworldGrpc.cs
new file mode 100644
index 0000000..041f5a7
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/Greeter/HelloworldGrpc.cs
@@ -0,0 +1,143 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: helloworld.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+#region Designer generated code
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+
+namespace Helloworld {
+  /// <summary>
+  ///  The greeting service definition.
+  /// </summary>
+  public static class Greeter
+  {
+    static readonly string __ServiceName = "helloworld.Greeter";
+
+    static readonly Marshaller<global::Helloworld.HelloRequest> __Marshaller_HelloRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom);
+    static readonly Marshaller<global::Helloworld.HelloReply> __Marshaller_HelloReply = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom);
+
+    static readonly Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHello = new Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>(
+        MethodType.Unary,
+        __ServiceName,
+        "SayHello",
+        __Marshaller_HelloRequest,
+        __Marshaller_HelloReply);
+
+    /// <summary>Service descriptor</summary>
+    public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+    {
+      get { return global::Helloworld.HelloworldReflection.Descriptor.Services[0]; }
+    }
+
+    /// <summary>Base class for server-side implementations of Greeter</summary>
+    public abstract class GreeterBase
+    {
+      /// <summary>
+      ///  Sends a greeting
+      /// </summary>
+      public virtual global::System.Threading.Tasks.Task<global::Helloworld.HelloReply> SayHello(global::Helloworld.HelloRequest request, ServerCallContext context)
+      {
+        throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+      }
+
+    }
+
+    /// <summary>Client for Greeter</summary>
+    public class GreeterClient : ClientBase<GreeterClient>
+    {
+      /// <summary>Creates a new client for Greeter</summary>
+      /// <param name="channel">The channel to use to make remote calls.</param>
+      public GreeterClient(Channel channel) : base(channel)
+      {
+      }
+      /// <summary>Creates a new client for Greeter that uses a custom <c>CallInvoker</c>.</summary>
+      /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
+      public GreeterClient(CallInvoker callInvoker) : base(callInvoker)
+      {
+      }
+      /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+      protected GreeterClient() : base()
+      {
+      }
+      /// <summary>Protected constructor to allow creation of configured clients.</summary>
+      /// <param name="configuration">The client configuration.</param>
+      protected GreeterClient(ClientBaseConfiguration configuration) : base(configuration)
+      {
+      }
+
+      /// <summary>
+      ///  Sends a greeting
+      /// </summary>
+      public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      {
+        return SayHello(request, new CallOptions(headers, deadline, cancellationToken));
+      }
+      /// <summary>
+      ///  Sends a greeting
+      /// </summary>
+      public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, CallOptions options)
+      {
+        return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request);
+      }
+      /// <summary>
+      ///  Sends a greeting
+      /// </summary>
+      public virtual AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+      {
+        return SayHelloAsync(request, new CallOptions(headers, deadline, cancellationToken));
+      }
+      /// <summary>
+      ///  Sends a greeting
+      /// </summary>
+      public virtual AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, CallOptions options)
+      {
+        return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request);
+      }
+      protected override GreeterClient NewInstance(ClientBaseConfiguration configuration)
+      {
+        return new GreeterClient(configuration);
+      }
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
+    public static ServerServiceDefinition BindService(GreeterBase serviceImpl)
+    {
+      return ServerServiceDefinition.CreateBuilder()
+          .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build();
+    }
+
+  }
+}
+#endregion
diff --git a/examples/csharp/helloworld-from-cli/Greeter/project.json b/examples/csharp/helloworld-from-cli/Greeter/project.json
new file mode 100644
index 0000000..8774941
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/Greeter/project.json
@@ -0,0 +1,22 @@
+{
+  "title": "Greeter",
+  "version": "1.0.0-*",
+  "buildOptions": {
+    "debugType": "portable",
+  },
+  "dependencies": {
+    "Google.Protobuf": "3.0.0-beta3",
+    "Grpc": "1.0.0-pre1",
+  },
+  "frameworks": {
+    "net45": {
+      "frameworkAssemblies": {
+        "System.Runtime": "",
+        "System.IO": ""
+      },
+      "dependencies": {
+	"Microsoft.NETCore.Platforms": "1.0.1" 
+      }
+    }
+  }
+}
diff --git a/examples/csharp/helloworld-from-cli/GreeterClient/Program.cs b/examples/csharp/helloworld-from-cli/GreeterClient/Program.cs
new file mode 100644
index 0000000..444d473
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/GreeterClient/Program.cs
@@ -0,0 +1,53 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using Grpc.Core;
+using Helloworld;
+
+namespace GreeterClient
+{
+    class Program
+    {
+        public static void Main(string[] args)
+        {
+            Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
+
+            var client = new Greeter.GreeterClient(channel);
+            String user = "you";
+
+            var reply = client.SayHello(new HelloRequest { Name = user });
+            Console.WriteLine("Greeting: " + reply.Message);
+
+            channel.ShutdownAsync().Wait();
+            Console.WriteLine("Press any key to exit...");
+            Console.ReadKey();
+        }
+    }
+}
diff --git a/examples/csharp/helloworld-from-cli/GreeterClient/project.json b/examples/csharp/helloworld-from-cli/GreeterClient/project.json
new file mode 100644
index 0000000..c2bf694
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/GreeterClient/project.json
@@ -0,0 +1,26 @@
+{
+  "title": "GreeterClient",
+  "version": "1.0.0-*",
+  "buildOptions": {
+    "debugType": "portable",
+    "emitEntryPoint": "true"
+  },
+  "dependencies": {
+    "Google.Protobuf": "3.0.0-beta3",
+    "Grpc": "1.0.0-pre1",
+    "Greeter": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": {
+      "frameworkAssemblies": {
+        "System.Runtime": "",
+        "System.IO": ""
+      },
+      "dependencies": {
+	"Microsoft.NETCore.Platforms": "1.0.1" 
+      }
+    }
+  }
+}
diff --git a/examples/csharp/helloworld-from-cli/GreeterServer/Program.cs b/examples/csharp/helloworld-from-cli/GreeterServer/Program.cs
new file mode 100644
index 0000000..fdab379
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/GreeterServer/Program.cs
@@ -0,0 +1,66 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+using System;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Helloworld;
+
+namespace GreeterServer
+{
+    class GreeterImpl : Greeter.GreeterBase
+    {
+        // Server side handler of the SayHello RPC
+        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
+        {
+            return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
+        }
+    }
+
+    class Program
+    {
+        const int Port = 50051;
+
+        public static void Main(string[] args)
+        {
+            Server server = new Server
+            {
+                Services = { Greeter.BindService(new GreeterImpl()) },
+                Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
+            };
+            server.Start();
+
+            Console.WriteLine("Greeter server listening on port " + Port);
+            Console.WriteLine("Press any key to stop the server...");
+            Console.ReadKey();
+
+            server.ShutdownAsync().Wait();
+        }
+    }
+}
diff --git a/examples/csharp/helloworld-from-cli/GreeterServer/project.json b/examples/csharp/helloworld-from-cli/GreeterServer/project.json
new file mode 100644
index 0000000..29a1067
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/GreeterServer/project.json
@@ -0,0 +1,26 @@
+{
+  "title": "GreeterServer",
+  "version": "1.0.0-*",
+  "buildOptions": {
+    "debugType": "portable",
+    "emitEntryPoint": "true"
+  },
+  "dependencies": {
+    "Google.Protobuf": "3.0.0-beta3",
+    "Grpc": "1.0.0-pre1",
+    "Greeter": {
+      "target": "project"
+    }
+  },
+  "frameworks": {
+    "net45": {
+      "frameworkAssemblies": {
+        "System.Runtime": "",
+        "System.IO": ""
+      },
+      "dependencies": {
+	"Microsoft.NETCore.Platforms": "1.0.1" 
+      }
+    }
+  }
+}
diff --git a/examples/csharp/helloworld-from-cli/README.md b/examples/csharp/helloworld-from-cli/README.md
new file mode 100644
index 0000000..4db0776
--- /dev/null
+++ b/examples/csharp/helloworld-from-cli/README.md
@@ -0,0 +1,59 @@
+gRPC in 3 minutes (C#)
+========================
+
+BACKGROUND
+-------------
+This is a different version of the helloworld example, using the dotnet sdk
+tools to build and run.
+
+For this sample, we've already generated the server and client stubs from [helloworld.proto][].
+
+Example projects in this directory depend on the [Grpc](https://www.nuget.org/packages/Grpc/)
+and [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf/) NuGet packages
+which have been already added to the project for you.
+
+The examples in this directory target .NET 4.5 framework, as .NET Core support is
+currently experimental.
+
+PREREQUISITES
+-------------
+
+- The DotNetCore SDK cli.
+
+- The .NET 4.5 framework.
+
+Both are available to download at https://www.microsoft.com/net/download
+
+BUILD
+-------
+
+From the `examples/csharp/helloworld-from-cli` directory:
+
+- `dotnet restore`
+
+- `dotnet build **/project.json` (this will automatically download NuGet dependencies)
+
+Try it!
+-------
+
+- Run the server
+
+  ```
+  > cd GreeterServer
+  > dotnet run
+  ```
+
+- Run the client
+
+  ```
+  > cd GreeterClient
+  > dotnet run
+  ```
+
+Tutorial
+--------
+
+You can find a more detailed tutorial about Grpc in [gRPC Basics: C#][]
+
+[helloworld.proto]:../../protos/helloworld.proto
+[gRPC Basics: C#]:http://www.grpc.io/docs/tutorials/basic/csharp.html
diff --git a/examples/csharp/helloworld/README.md b/examples/csharp/helloworld/README.md
index d13c9ac..71840ad 100644
--- a/examples/csharp/helloworld/README.md
+++ b/examples/csharp/helloworld/README.md
@@ -13,7 +13,7 @@
 -------------
 
 - Windows: .NET Framework 4.5+, Visual Studio 2013 or 2015
-- Linux: Mono 4+, MonoDevelop 5.9+ (with NuGet add-in installed)
+- Linux: Mono 4+, MonoDevelop 5.9+
 - Mac OS X: Xamarin Studio 5.9+
 
 BUILD
@@ -21,7 +21,20 @@
 
 - Open solution `Greeter.sln` with Visual Studio, Monodevelop (on Linux) or Xamarin Studio (on Mac OS X)
 
-- Build the solution (this will automatically download NuGet dependencies)
+# Using Visual Studio
+
+* Build the solution (this will automatically download NuGet dependencies)
+
+# Using Monodevelop or Xamarin Studio
+
+The nuget add-in available for Xamarin Studio and Monodevelop IDEs is too old to 
+download all of the nuget dependencies of gRPC. One alternative to is to use the dotnet command line tools instead (see [helloworld-from-cli]).
+
+Using these IDEs, a workaround is as follows:
+* Obtain a nuget executable for your platform and update it with
+ `nuget update -self`. 
+* Navigate to this directory and run `nuget restore`.
+* Now that packages have been restored into their proper package folder, build the solution from your IDE.
 
 Try it!
 -------
@@ -49,5 +62,6 @@
 
 You can find a more detailed tutorial in [gRPC Basics: C#][]
 
+[helloworld-from-cli]:../helloworld-from-cli/README.md
 [helloworld.proto]:../../protos/helloworld.proto
 [gRPC Basics: C#]:http://www.grpc.io/docs/tutorials/basic/csharp.html
diff --git a/examples/node/package.json b/examples/node/package.json
index 2cae031..6317838 100644
--- a/examples/node/package.json
+++ b/examples/node/package.json
@@ -3,8 +3,8 @@
   "version": "0.1.0",
   "dependencies": {
     "async": "^1.5.2",
-    "google-protobuf": "^3.0.0-alpha.5",
-    "grpc": "^0.14.0",
+    "google-protobuf": "^3.0.0",
+    "grpc": "^1.0.0",
     "lodash": "^4.6.1",
     "minimist": "^1.2.0"
   }
diff --git a/examples/ruby/greeter_client.rb b/examples/ruby/greeter_client.rb
index cb4aa19..1cdf79e 100755
--- a/examples/ruby/greeter_client.rb
+++ b/examples/ruby/greeter_client.rb
@@ -38,7 +38,7 @@
 $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
 
 require 'grpc'
-require 'helloworld_services'
+require 'helloworld_services_pb'
 
 def main
   stub = Helloworld::Greeter::Stub.new('localhost:50051', :this_channel_is_insecure)
diff --git a/examples/ruby/greeter_server.rb b/examples/ruby/greeter_server.rb
index 622513d..6d82043 100755
--- a/examples/ruby/greeter_server.rb
+++ b/examples/ruby/greeter_server.rb
@@ -38,7 +38,7 @@
 $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
 
 require 'grpc'
-require 'helloworld_services'
+require 'helloworld_services_pb'
 
 # GreeterServer is simple server that implements the Helloworld Greeter server.
 class GreeterServer < Helloworld::Greeter::Service
diff --git a/examples/ruby/grpc-demo.gemspec b/examples/ruby/grpc-demo.gemspec
index b1dfdae..e1b77a5 100644
--- a/examples/ruby/grpc-demo.gemspec
+++ b/examples/ruby/grpc-demo.gemspec
@@ -3,7 +3,7 @@
 
 Gem::Specification.new do |s|
   s.name          = 'grpc-demo'
-  s.version       = '0.11.0'
+  s.version       = '1.0.0'
   s.authors       = ['gRPC Authors']
   s.email         = 'temiola@google.com'
   s.homepage      = 'https://github.com/grpc/grpc'
@@ -17,7 +17,7 @@
   s.require_paths = ['lib']
   s.platform      = Gem::Platform::RUBY
 
-  s.add_dependency 'grpc', '~> 0.11'
+  s.add_dependency 'grpc', '~> 1.0.0'
 
   s.add_development_dependency 'bundler', '~> 1.7'
 end
diff --git a/examples/ruby/lib/helloworld.rb b/examples/ruby/lib/helloworld_pb.rb
similarity index 100%
rename from examples/ruby/lib/helloworld.rb
rename to examples/ruby/lib/helloworld_pb.rb
diff --git a/examples/ruby/lib/helloworld_services.rb b/examples/ruby/lib/helloworld_services_pb.rb
similarity index 98%
rename from examples/ruby/lib/helloworld_services.rb
rename to examples/ruby/lib/helloworld_services_pb.rb
index fbec667..4fee0aa 100644
--- a/examples/ruby/lib/helloworld_services.rb
+++ b/examples/ruby/lib/helloworld_services_pb.rb
@@ -32,7 +32,7 @@
 #
 
 require 'grpc'
-require 'helloworld'
+require 'helloworld_pb'
 
 module Helloworld
   module Greeter
diff --git a/examples/ruby/lib/route_guide.rb b/examples/ruby/lib/route_guide_pb.rb
similarity index 100%
rename from examples/ruby/lib/route_guide.rb
rename to examples/ruby/lib/route_guide_pb.rb
diff --git a/examples/ruby/lib/route_guide_services.rb b/examples/ruby/lib/route_guide_services_pb.rb
similarity index 98%
rename from examples/ruby/lib/route_guide_services.rb
rename to examples/ruby/lib/route_guide_services_pb.rb
index d8f123d..d43fcc6 100644
--- a/examples/ruby/lib/route_guide_services.rb
+++ b/examples/ruby/lib/route_guide_services_pb.rb
@@ -32,7 +32,7 @@
 #
 
 require 'grpc'
-require 'route_guide'
+require 'route_guide_pb'
 
 module Routeguide
   module RouteGuide
diff --git a/examples/ruby/route_guide/route_guide_client.rb b/examples/ruby/route_guide/route_guide_client.rb
index e7f802c..330725e 100755
--- a/examples/ruby/route_guide/route_guide_client.rb
+++ b/examples/ruby/route_guide/route_guide_client.rb
@@ -39,7 +39,7 @@
 
 require 'grpc'
 require 'multi_json'
-require 'route_guide_services'
+require 'route_guide_services_pb'
 
 include Routeguide
 
diff --git a/examples/ruby/route_guide/route_guide_server.rb b/examples/ruby/route_guide/route_guide_server.rb
index bebe49b..a5a73a8 100755
--- a/examples/ruby/route_guide/route_guide_server.rb
+++ b/examples/ruby/route_guide/route_guide_server.rb
@@ -40,7 +40,7 @@
 
 require 'grpc'
 require 'multi_json'
-require 'route_guide_services'
+require 'route_guide_services_pb'
 
 include Routeguide
 COORD_FACTOR = 1e7
diff --git a/grpc.gemspec b/grpc.gemspec
index 29d8afe..a7516a3 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -27,7 +27,7 @@
   s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
-  s.add_dependency 'google-protobuf', '~> 3.0.0.alpha.5.0.3'
+  s.add_dependency 'google-protobuf', '~> 3.0'
   s.add_dependency 'googleauth',      '~> 0.5.1'
 
   s.add_development_dependency 'bundler',            '~> 1.9'
diff --git a/include/grpc++/impl/codegen/thrift_serializer.h b/include/grpc++/impl/codegen/thrift_serializer.h
new file mode 100644
index 0000000..7308a15
--- /dev/null
+++ b/include/grpc++/impl/codegen/thrift_serializer.h
@@ -0,0 +1,219 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_THRIFT_SERIALIZER_H
+#define GRPCXX_IMPL_CODEGEN_THRIFT_SERIALIZER_H
+
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/byte_buffer_reader.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/protocol/TCompactProtocol.h>
+#include <thrift/protocol/TProtocolException.h>
+#include <thrift/transport/TBufferTransports.h>
+#include <thrift/transport/TTransportUtils.h>
+#include <boost/make_shared.hpp>
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+namespace apache {
+namespace thrift {
+namespace util {
+
+using apache::thrift::protocol::TBinaryProtocolT;
+using apache::thrift::protocol::TCompactProtocolT;
+using apache::thrift::protocol::TMessageType;
+using apache::thrift::protocol::TNetworkBigEndian;
+using apache::thrift::transport::TMemoryBuffer;
+using apache::thrift::transport::TBufferBase;
+using apache::thrift::transport::TTransport;
+
+template <typename Dummy, typename Protocol>
+class ThriftSerializer {
+ public:
+  ThriftSerializer()
+      : prepared_(false),
+        last_deserialized_(false),
+        serialize_version_(false) {}
+
+  virtual ~ThriftSerializer() {}
+
+  // Serialize the passed type into the internal buffer
+  // and returns a pointer to internal buffer and its size
+  template <typename T>
+  void Serialize(const T& fields, const uint8_t** serialized_buffer,
+                 size_t* serialized_len) {
+    // prepare or reset buffer
+    if (!prepared_ || last_deserialized_) {
+      prepare();
+    } else {
+      buffer_->resetBuffer();
+    }
+    last_deserialized_ = false;
+
+    // if required serialize protocol version
+    if (serialize_version_) {
+      protocol_->writeMessageBegin("", TMessageType(0), 0);
+    }
+
+    // serialize fields into buffer
+    fields.write(protocol_.get());
+
+    // write the end of message
+    if (serialize_version_) {
+      protocol_->writeMessageEnd();
+    }
+
+    uint8_t* byte_buffer;
+    uint32_t byte_buffer_size;
+    buffer_->getBuffer(&byte_buffer, &byte_buffer_size);
+    *serialized_buffer = byte_buffer;
+    *serialized_len = byte_buffer_size;
+  }
+
+  // Serialize the passed type into the byte buffer
+  template <typename T>
+  void Serialize(const T& fields, grpc_byte_buffer** bp) {
+    const uint8_t* byte_buffer;
+    size_t byte_buffer_size;
+
+    Serialize(fields, &byte_buffer, &byte_buffer_size);
+
+    gpr_slice slice = gpr_slice_from_copied_buffer(
+        reinterpret_cast<const char*>(byte_buffer), byte_buffer_size);
+
+    *bp = grpc_raw_byte_buffer_create(&slice, 1);
+
+    gpr_slice_unref(slice);
+  }
+
+  // Deserialize the passed char array into  the passed type, returns the number
+  // of bytes that have been consumed from the passed string.
+  template <typename T>
+  uint32_t Deserialize(uint8_t* serialized_buffer, size_t length, T* fields) {
+    // prepare buffer if necessary
+    if (!prepared_) {
+      prepare();
+    }
+    last_deserialized_ = true;
+
+    // reset buffer transport
+    buffer_->resetBuffer(serialized_buffer, length);
+
+    // read the protocol version if necessary
+    if (serialize_version_) {
+      std::string name = "";
+      TMessageType mt = static_cast<TMessageType>(0);
+      int32_t seq_id = 0;
+      protocol_->readMessageBegin(name, mt, seq_id);
+    }
+
+    // deserialize buffer into fields
+    uint32_t len = fields->read(protocol_.get());
+
+    // read the end of message
+    if (serialize_version_) {
+      protocol_->readMessageEnd();
+    }
+
+    return len;
+  }
+
+  // Deserialize the passed byte buffer to passed type, returns the number
+  // of bytes consumed from byte buffer
+  template <typename T>
+  uint32_t Deserialize(grpc_byte_buffer* buffer, T* msg) {
+    grpc_byte_buffer_reader reader;
+    grpc_byte_buffer_reader_init(&reader, buffer);
+
+    gpr_slice slice = grpc_byte_buffer_reader_readall(&reader);
+
+    uint32_t len =
+        Deserialize(GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice), msg);
+
+    gpr_slice_unref(slice);
+
+    grpc_byte_buffer_reader_destroy(&reader);
+
+    return len;
+  }
+
+  // set serialization version flag
+  void SetSerializeVersion(bool value) { serialize_version_ = value; }
+
+  // Set the container size limit to deserialize
+  // This function should be called after buffer_ is initialized
+  void SetContainerSizeLimit(int32_t container_limit) {
+    if (!prepared_) {
+      prepare();
+    }
+    protocol_->setContainerSizeLimit(container_limit);
+  }
+
+  // Set the string size limit to deserialize
+  // This function should be called after buffer_ is initialized
+  void SetStringSizeLimit(int32_t string_limit) {
+    if (!prepared_) {
+      prepare();
+    }
+    protocol_->setStringSizeLimit(string_limit);
+  }
+
+ private:
+  bool prepared_;
+  bool last_deserialized_;
+  boost::shared_ptr<TMemoryBuffer> buffer_;
+  std::shared_ptr<Protocol> protocol_;
+  bool serialize_version_;
+
+  void prepare() {
+    buffer_ = boost::make_shared<TMemoryBuffer>();
+    // create a protocol for the memory buffer transport
+    protocol_ = std::make_shared<Protocol>(buffer_);
+    prepared_ = true;
+  }
+
+};  // ThriftSerializer
+
+typedef ThriftSerializer<void, TBinaryProtocolT<TBufferBase, TNetworkBigEndian>>
+    ThriftSerializerBinary;
+typedef ThriftSerializer<void, TCompactProtocolT<TBufferBase>>
+    ThriftSerializerCompact;
+
+}  // namespace util
+}  // namespace thrift
+}  // namespace apache
+
+#endif
\ No newline at end of file
diff --git a/include/grpc++/impl/codegen/thrift_utils.h b/include/grpc++/impl/codegen/thrift_utils.h
new file mode 100644
index 0000000..7d19b24
--- /dev/null
+++ b/include/grpc++/impl/codegen/thrift_utils.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_THRIFT_UTILS_H
+#define GRPCXX_IMPL_CODEGEN_THRIFT_UTILS_H
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
+#include <grpc++/impl/codegen/serialization_traits.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/status_code_enum.h>
+#include <grpc++/impl/codegen/thrift_serializer.h>
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/byte_buffer_reader.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+#include <cstdint>
+#include <cstdlib>
+
+namespace grpc {
+
+using apache::thrift::util::ThriftSerializerCompact;
+
+template <class T>
+class SerializationTraits<T, typename std::enable_if<std::is_base_of<
+                                 apache::thrift::TBase, T>::value>::type> {
+ public:
+  static Status Serialize(const T& msg, grpc_byte_buffer** bp,
+                          bool* own_buffer) {
+    *own_buffer = true;
+
+    ThriftSerializerCompact serializer;
+    serializer.Serialize(msg, bp);
+
+    return Status(StatusCode::OK, "ok");
+  }
+
+  static Status Deserialize(grpc_byte_buffer* buffer, T* msg,
+                            int max_message_size) {
+    if (!buffer) {
+      return Status(StatusCode::INTERNAL, "No payload");
+    }
+
+    ThriftSerializerCompact deserializer;
+    deserializer.Deserialize(buffer, msg);
+
+    grpc_byte_buffer_destroy(buffer);
+
+    return Status(StatusCode::OK, "ok");
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_THRIFT_UTILS_H
diff --git a/include/grpc++/support/byte_buffer.h b/include/grpc++/support/byte_buffer.h
index 20bd407..01249a0 100644
--- a/include/grpc++/support/byte_buffer.h
+++ b/include/grpc++/support/byte_buffer.h
@@ -72,6 +72,9 @@
   /// Buffer size in bytes.
   size_t Length() const;
 
+  /// Swap the state of *this and *other.
+  void Swap(ByteBuffer* other);
+
  private:
   friend class SerializationTraits<ByteBuffer, void>;
 
diff --git a/package.json b/package.json
index 0e229c9..9afba31 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
   "devDependencies": {
     "async": "^1.5.0",
     "google-auth-library": "^0.9.2",
-    "google-protobuf": "^3.0.0-alpha.5",
+    "google-protobuf": "^3.0.0",
     "istanbul": "^0.3.21",
     "jsdoc": "^3.3.2",
     "jshint": "^2.5.0",
diff --git a/package.xml b/package.xml
index 38b74f5..890cf32 100644
--- a/package.xml
+++ b/package.xml
@@ -10,7 +10,7 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2016-07-28</date>
+ <date>2016-08-09</date>
  <time>16:06:07</time>
  <version>
   <release>1.1.0</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>BSD</license>
  <notes>
-- PHP7 Support continued, reduce code duplication #7543
+- Fixed Ubuntu compile error #7571, #7642
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -1139,5 +1139,20 @@
 - PHP7 Support continued, reduce code duplication #7543
    </notes>
   </release>
+  <release>
+   <version>
+    <release>1.0.0RC4</release>
+    <api>1.0.0RC4</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2016-08-09</date>
+   <license>BSD</license>
+   <notes>
+- Fixed Ubuntu compile error #7571, #7642
+   </notes>
+  </release>
  </changelog>
 </package>
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 25d8aca..029c150 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -46,189 +46,519 @@
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/transport/metadata_batch.h"
+#include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/transport_impl.h"
 #include "third_party/objective_c/Cronet/cronet_c_for_grpc.h"
 
 #define GRPC_HEADER_SIZE_IN_BYTES 5
 
-// Global flag that gets set with GRPC_TRACE env variable
-int grpc_cronet_trace = 1;
+#define CRONET_LOG(...)                          \
+  do {                                           \
+    if (grpc_cronet_trace) gpr_log(__VA_ARGS__); \
+  } while (0)
 
-// Cronet transport object
+/* TODO (makdharma): Hook up into the wider tracing mechanism */
+int grpc_cronet_trace = 0;
+
+enum e_op_result {
+  ACTION_TAKEN_WITH_CALLBACK,
+  ACTION_TAKEN_NO_CALLBACK,
+  NO_ACTION_POSSIBLE
+};
+
+enum e_op_id {
+  OP_SEND_INITIAL_METADATA = 0,
+  OP_SEND_MESSAGE,
+  OP_SEND_TRAILING_METADATA,
+  OP_RECV_MESSAGE,
+  OP_RECV_INITIAL_METADATA,
+  OP_RECV_TRAILING_METADATA,
+  OP_CANCEL_ERROR,
+  OP_ON_COMPLETE,
+  OP_FAILED,
+  OP_SUCCEEDED,
+  OP_CANCELED,
+  OP_RECV_MESSAGE_AND_ON_COMPLETE,
+  OP_READ_REQ_MADE,
+  OP_NUM_OPS
+};
+
+/* Cronet callbacks. See cronet_c_for_grpc.h for documentation for each. */
+
+static void on_request_headers_sent(cronet_bidirectional_stream *);
+static void on_response_headers_received(
+    cronet_bidirectional_stream *,
+    const cronet_bidirectional_stream_header_array *, const char *);
+static void on_write_completed(cronet_bidirectional_stream *, const char *);
+static void on_read_completed(cronet_bidirectional_stream *, char *, int);
+static void on_response_trailers_received(
+    cronet_bidirectional_stream *,
+    const cronet_bidirectional_stream_header_array *);
+static void on_succeeded(cronet_bidirectional_stream *);
+static void on_failed(cronet_bidirectional_stream *, int);
+static void on_canceled(cronet_bidirectional_stream *);
+static cronet_bidirectional_stream_callback cronet_callbacks = {
+    on_request_headers_sent,
+    on_response_headers_received,
+    on_read_completed,
+    on_write_completed,
+    on_response_trailers_received,
+    on_succeeded,
+    on_failed,
+    on_canceled};
+
+/* Cronet transport object */
 struct grpc_cronet_transport {
   grpc_transport base; /* must be first element in this structure */
   cronet_engine *engine;
   char *host;
 };
-
 typedef struct grpc_cronet_transport grpc_cronet_transport;
 
-enum send_state {
-  CRONET_SEND_IDLE = 0,
-  CRONET_REQ_STARTED,
-  CRONET_SEND_HEADER,
-  CRONET_WRITE,
-  CRONET_WRITE_COMPLETED,
+/* TODO (makdharma): reorder structure for memory efficiency per
+   http://www.catb.org/esr/structure-packing/#_structure_reordering: */
+struct read_state {
+  /* vars to store data coming from server */
+  char *read_buffer;
+  bool length_field_received;
+  int received_bytes;
+  int remaining_bytes;
+  int length_field;
+  char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES];
+  char *payload_field;
+  bool read_stream_closed;
+
+  /* vars for holding data destined for the application */
+  struct grpc_slice_buffer_stream sbs;
+  gpr_slice_buffer read_slice_buffer;
+
+  /* vars for trailing metadata */
+  grpc_chttp2_incoming_metadata_buffer trailing_metadata;
+  bool trailing_metadata_valid;
+
+  /* vars for initial metadata */
+  grpc_chttp2_incoming_metadata_buffer initial_metadata;
 };
 
-enum recv_state {
-  CRONET_RECV_IDLE = 0,
-  CRONET_RECV_READ_LENGTH,
-  CRONET_RECV_READ_DATA,
-  CRONET_RECV_CLOSED,
+struct write_state {
+  char *write_buffer;
 };
 
-static const char *recv_state_name[] = {
-    "CRONET_RECV_IDLE", "CRONET_RECV_READ_LENGTH", "CRONET_RECV_READ_DATA,",
-    "CRONET_RECV_CLOSED"};
-
-// Enum that identifies calling function.
-enum e_caller {
-  PERFORM_STREAM_OP,
-  ON_READ_COMPLETE,
-  ON_RESPONSE_HEADERS_RECEIVED,
-  ON_RESPONSE_TRAILERS_RECEIVED
+/* track state of one stream op */
+struct op_state {
+  bool state_op_done[OP_NUM_OPS];
+  bool state_callback_received[OP_NUM_OPS];
+  /* data structure for storing data coming from server */
+  struct read_state rs;
+  /* data structure for storing data going to the server */
+  struct write_state ws;
 };
 
-enum callback_id {
-  CB_SEND_INITIAL_METADATA = 0,
-  CB_SEND_MESSAGE,
-  CB_SEND_TRAILING_METADATA,
-  CB_RECV_MESSAGE,
-  CB_RECV_INITIAL_METADATA,
-  CB_RECV_TRAILING_METADATA,
-  CB_NUM_CALLBACKS
+struct op_and_state {
+  grpc_transport_stream_op op;
+  struct op_state state;
+  bool done;
+  struct stream_obj *s;      /* Pointer back to the stream object */
+  struct op_and_state *next; /* next op_and_state in the linked list */
+};
+
+struct op_storage {
+  int num_pending_ops;
+  struct op_and_state *head;
 };
 
 struct stream_obj {
-  // we store received bytes here as they trickle in.
-  gpr_slice_buffer write_slice_buffer;
+  struct op_and_state *oas;
+  grpc_transport_stream_op *curr_op;
+  grpc_cronet_transport curr_ct;
+  grpc_stream *curr_gs;
   cronet_bidirectional_stream *cbs;
-  gpr_slice slice;
-  gpr_slice_buffer read_slice_buffer;
-  struct grpc_slice_buffer_stream sbs;
-  char *read_buffer;
-  int remaining_read_bytes;
-  int total_read_bytes;
-
-  char *write_buffer;
-  size_t write_buffer_size;
-
-  // Hold the URL
-  char *url;
-
-  bool response_headers_received;
-  bool read_requested;
-  bool response_trailers_received;
-  bool read_closed;
-
-  // Recv message stuff
-  grpc_byte_buffer **recv_message;
-  // Initial metadata stuff
-  grpc_metadata_batch *recv_initial_metadata;
-  // Trailing metadata stuff
-  grpc_metadata_batch *recv_trailing_metadata;
-  grpc_chttp2_incoming_metadata_buffer imb;
-
-  // This mutex protects receive state machine execution
-  gpr_mu recv_mu;
-  // we can queue up up to 2 callbacks for each OP
-  grpc_closure *callback_list[CB_NUM_CALLBACKS][2];
-
-  // storage for header
-  cronet_bidirectional_stream_header *headers;
-  uint32_t num_headers;
   cronet_bidirectional_stream_header_array header_array;
-  // state tracking
-  enum recv_state cronet_recv_state;
-  enum send_state cronet_send_state;
-};
 
+  /* Stream level state. Some state will be tracked both at stream and stream_op
+   * level */
+  struct op_state state;
+
+  /* OP storage */
+  struct op_storage storage;
+
+  /* Mutex to protect storage */
+  gpr_mu mu;
+};
 typedef struct stream_obj stream_obj;
 
-static void next_send_step(stream_obj *s);
-static void next_recv_step(stream_obj *s, enum e_caller caller);
+static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
+                                          struct op_and_state *oas);
 
-static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                                   grpc_stream *gs, grpc_pollset *pollset) {}
+/*
+  Utility function to translate enum into string for printing
+*/
+static const char *op_result_string(enum e_op_result i) {
+  switch (i) {
+    case ACTION_TAKEN_WITH_CALLBACK:
+      return "ACTION_TAKEN_WITH_CALLBACK";
+    case ACTION_TAKEN_NO_CALLBACK:
+      return "ACTION_TAKEN_NO_CALLBACK";
+    case NO_ACTION_POSSIBLE:
+      return "NO_ACTION_POSSIBLE";
+  }
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
 
-static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
-                                       grpc_transport *gt, grpc_stream *gs,
-                                       grpc_pollset_set *pollset_set) {}
+static const char *op_id_string(enum e_op_id i) {
+  switch (i) {
+    case OP_SEND_INITIAL_METADATA:
+      return "OP_SEND_INITIAL_METADATA";
+    case OP_SEND_MESSAGE:
+      return "OP_SEND_MESSAGE";
+    case OP_SEND_TRAILING_METADATA:
+      return "OP_SEND_TRAILING_METADATA";
+    case OP_RECV_MESSAGE:
+      return "OP_RECV_MESSAGE";
+    case OP_RECV_INITIAL_METADATA:
+      return "OP_RECV_INITIAL_METADATA";
+    case OP_RECV_TRAILING_METADATA:
+      return "OP_RECV_TRAILING_METADATA";
+    case OP_CANCEL_ERROR:
+      return "OP_CANCEL_ERROR";
+    case OP_ON_COMPLETE:
+      return "OP_ON_COMPLETE";
+    case OP_FAILED:
+      return "OP_FAILED";
+    case OP_SUCCEEDED:
+      return "OP_SUCCEEDED";
+    case OP_CANCELED:
+      return "OP_CANCELED";
+    case OP_RECV_MESSAGE_AND_ON_COMPLETE:
+      return "OP_RECV_MESSAGE_AND_ON_COMPLETE";
+    case OP_READ_REQ_MADE:
+      return "OP_READ_REQ_MADE";
+    case OP_NUM_OPS:
+      return "OP_NUM_OPS";
+  }
+  return "UNKNOWN";
+}
 
-static void enqueue_callbacks(grpc_closure *callback_list[]) {
+/*
+  Add a new stream op to op storage.
+*/
+static void add_to_storage(struct stream_obj *s, grpc_transport_stream_op *op) {
+  struct op_storage *storage = &s->storage;
+  /* add new op at the beginning of the linked list. The memory is freed
+  in remove_from_storage */
+  struct op_and_state *new_op = gpr_malloc(sizeof(struct op_and_state));
+  memcpy(&new_op->op, op, sizeof(grpc_transport_stream_op));
+  memset(&new_op->state, 0, sizeof(new_op->state));
+  new_op->s = s;
+  new_op->done = false;
+  gpr_mu_lock(&s->mu);
+  new_op->next = storage->head;
+  storage->head = new_op;
+  storage->num_pending_ops++;
+  CRONET_LOG(GPR_DEBUG, "adding new op %p. %d in the queue.", new_op,
+             storage->num_pending_ops);
+  gpr_mu_unlock(&s->mu);
+}
+
+/*
+  Traverse the linked list and delete op and free memory
+*/
+static void remove_from_storage(struct stream_obj *s,
+                                struct op_and_state *oas) {
+  struct op_and_state *curr;
+  if (s->storage.head == NULL || oas == NULL) {
+    return;
+  }
+  if (s->storage.head == oas) {
+    s->storage.head = oas->next;
+    gpr_free(oas);
+    s->storage.num_pending_ops--;
+    CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas,
+               s->storage.num_pending_ops);
+  } else {
+    for (curr = s->storage.head; curr != NULL; curr = curr->next) {
+      if (curr->next == oas) {
+        curr->next = oas->next;
+        s->storage.num_pending_ops--;
+        CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas,
+                   s->storage.num_pending_ops);
+        gpr_free(oas);
+        break;
+      } else if (curr->next == NULL) {
+        CRONET_LOG(GPR_ERROR, "Reached end of LL and did not find op to free");
+      }
+    }
+  }
+}
+
+/*
+  Cycle through ops and try to take next action. Break when either
+  an action with callback is taken, or no action is possible.
+  This can be executed from the Cronet network thread via cronet callback
+  or on the application supplied thread via the perform_stream_op function.
+*/
+static void execute_from_storage(stream_obj *s) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  if (callback_list[0]) {
-    grpc_exec_ctx_sched(&exec_ctx, callback_list[0], GRPC_ERROR_NONE, NULL);
-    callback_list[0] = NULL;
+  gpr_mu_lock(&s->mu);
+  for (struct op_and_state *curr = s->storage.head; curr != NULL;) {
+    CRONET_LOG(GPR_DEBUG, "calling op at %p. done = %d", curr, curr->done);
+    GPR_ASSERT(curr->done == 0);
+    enum e_op_result result = execute_stream_op(&exec_ctx, curr);
+    CRONET_LOG(GPR_DEBUG, "execute_stream_op[%p] returns %s", curr,
+               op_result_string(result));
+    /* if this op is done, then remove it and free memory */
+    if (curr->done) {
+      struct op_and_state *next = curr->next;
+      remove_from_storage(s, curr);
+      curr = next;
+    }
+    /* continue processing the same op if ACTION_TAKEN_WITHOUT_CALLBACK */
+    if (result == NO_ACTION_POSSIBLE) {
+      curr = curr->next;
+    } else if (result == ACTION_TAKEN_WITH_CALLBACK) {
+      break;
+    }
   }
-  if (callback_list[1]) {
-    grpc_exec_ctx_sched(&exec_ctx, callback_list[1], GRPC_ERROR_NONE, NULL);
-    callback_list[1] = NULL;
-  }
+  gpr_mu_unlock(&s->mu);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void on_canceled(cronet_bidirectional_stream *stream) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "on_canceled %p", stream);
-  }
-}
-
+/*
+  Cronet callback
+*/
 static void on_failed(cronet_bidirectional_stream *stream, int net_error) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "on_failed %p, error = %d", stream, net_error);
+  CRONET_LOG(GPR_DEBUG, "on_failed(%p, %d)", stream, net_error);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  cronet_bidirectional_stream_destroy(s->cbs);
+  s->state.state_callback_received[OP_FAILED] = true;
+  s->cbs = NULL;
+  if (s->header_array.headers) {
+    gpr_free(s->header_array.headers);
+    s->header_array.headers = NULL;
   }
+  if (s->state.ws.write_buffer) {
+    gpr_free(s->state.ws.write_buffer);
+    s->state.ws.write_buffer = NULL;
+  }
+  execute_from_storage(s);
 }
 
+/*
+  Cronet callback
+*/
+static void on_canceled(cronet_bidirectional_stream *stream) {
+  CRONET_LOG(GPR_DEBUG, "on_canceled(%p)", stream);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  cronet_bidirectional_stream_destroy(s->cbs);
+  s->state.state_callback_received[OP_CANCELED] = true;
+  s->cbs = NULL;
+  if (s->header_array.headers) {
+    gpr_free(s->header_array.headers);
+    s->header_array.headers = NULL;
+  }
+  if (s->state.ws.write_buffer) {
+    gpr_free(s->state.ws.write_buffer);
+    s->state.ws.write_buffer = NULL;
+  }
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
 static void on_succeeded(cronet_bidirectional_stream *stream) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "on_succeeded %p", stream);
+  CRONET_LOG(GPR_DEBUG, "on_succeeded(%p)", stream);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  cronet_bidirectional_stream_destroy(s->cbs);
+  s->state.state_callback_received[OP_SUCCEEDED] = true;
+  s->cbs = NULL;
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_request_headers_sent(cronet_bidirectional_stream *stream) {
+  CRONET_LOG(GPR_DEBUG, "W: on_request_headers_sent(%p)", stream);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  s->state.state_op_done[OP_SEND_INITIAL_METADATA] = true;
+  s->state.state_callback_received[OP_SEND_INITIAL_METADATA] = true;
+  /* Free the memory allocated for headers */
+  if (s->header_array.headers) {
+    gpr_free(s->header_array.headers);
+    s->header_array.headers = NULL;
+  }
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_response_headers_received(
+    cronet_bidirectional_stream *stream,
+    const cronet_bidirectional_stream_header_array *headers,
+    const char *negotiated_protocol) {
+  CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream,
+             headers, negotiated_protocol);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  memset(&s->state.rs.initial_metadata, 0,
+         sizeof(s->state.rs.initial_metadata));
+  grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata);
+  for (size_t i = 0; i < headers->count; i++) {
+    grpc_chttp2_incoming_metadata_buffer_add(
+        &s->state.rs.initial_metadata,
+        grpc_mdelem_from_metadata_strings(
+            grpc_mdstr_from_string(headers->headers[i].key),
+            grpc_mdstr_from_string(headers->headers[i].value)));
+  }
+  s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_write_completed(cronet_bidirectional_stream *stream,
+                               const char *data) {
+  stream_obj *s = (stream_obj *)stream->annotation;
+  CRONET_LOG(GPR_DEBUG, "W: on_write_completed(%p, %s)", stream, data);
+  if (s->state.ws.write_buffer) {
+    gpr_free(s->state.ws.write_buffer);
+    s->state.ws.write_buffer = NULL;
+  }
+  s->state.state_callback_received[OP_SEND_MESSAGE] = true;
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
+                              int count) {
+  stream_obj *s = (stream_obj *)stream->annotation;
+  CRONET_LOG(GPR_DEBUG, "R: on_read_completed(%p, %p, %d)", stream, data,
+             count);
+  s->state.state_callback_received[OP_RECV_MESSAGE] = true;
+  if (count > 0) {
+    s->state.rs.received_bytes += count;
+    s->state.rs.remaining_bytes -= count;
+    if (s->state.rs.remaining_bytes > 0) {
+      CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
+      s->state.state_op_done[OP_READ_REQ_MADE] = true;
+      cronet_bidirectional_stream_read(
+          s->cbs, s->state.rs.read_buffer + s->state.rs.received_bytes,
+          s->state.rs.remaining_bytes);
+    } else {
+      execute_from_storage(s);
+    }
+  } else {
+    s->state.rs.read_stream_closed = true;
+    execute_from_storage(s);
   }
 }
 
+/*
+  Cronet callback
+*/
 static void on_response_trailers_received(
     cronet_bidirectional_stream *stream,
     const cronet_bidirectional_stream_header_array *trailers) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "R: on_response_trailers_received");
-  }
+  CRONET_LOG(GPR_DEBUG, "R: on_response_trailers_received(%p,%p)", stream,
+             trailers);
   stream_obj *s = (stream_obj *)stream->annotation;
-
-  memset(&s->imb, 0, sizeof(s->imb));
-  grpc_chttp2_incoming_metadata_buffer_init(&s->imb);
-  unsigned int i = 0;
-  for (i = 0; i < trailers->count; i++) {
+  memset(&s->state.rs.trailing_metadata, 0,
+         sizeof(s->state.rs.trailing_metadata));
+  s->state.rs.trailing_metadata_valid = false;
+  grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata);
+  for (size_t i = 0; i < trailers->count; i++) {
+    CRONET_LOG(GPR_DEBUG, "trailer key=%s, value=%s", trailers->headers[i].key,
+               trailers->headers[i].value);
     grpc_chttp2_incoming_metadata_buffer_add(
-        &s->imb, grpc_mdelem_from_metadata_strings(
-                     grpc_mdstr_from_string(trailers->headers[i].key),
-                     grpc_mdstr_from_string(trailers->headers[i].value)));
+        &s->state.rs.trailing_metadata,
+        grpc_mdelem_from_metadata_strings(
+            grpc_mdstr_from_string(trailers->headers[i].key),
+            grpc_mdstr_from_string(trailers->headers[i].value)));
+    s->state.rs.trailing_metadata_valid = true;
   }
-  s->response_trailers_received = true;
-  next_recv_step(s, ON_RESPONSE_TRAILERS_RECEIVED);
+  s->state.state_callback_received[OP_RECV_TRAILING_METADATA] = true;
+  execute_from_storage(s);
 }
 
-static void on_write_completed(cronet_bidirectional_stream *stream,
-                               const char *data) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "W: on_write_completed");
-  }
-  stream_obj *s = (stream_obj *)stream->annotation;
-  enqueue_callbacks(s->callback_list[CB_SEND_MESSAGE]);
-  s->cronet_send_state = CRONET_WRITE_COMPLETED;
-  next_send_step(s);
+/*
+ Utility function that takes the data from s->write_slice_buffer and assembles
+ into a contiguous byte stream with 5 byte gRPC header prepended.
+*/
+static void create_grpc_frame(gpr_slice_buffer *write_slice_buffer,
+                              char **pp_write_buffer,
+                              size_t *p_write_buffer_size) {
+  gpr_slice slice = gpr_slice_buffer_take_first(write_slice_buffer);
+  size_t length = GPR_SLICE_LENGTH(slice);
+  *p_write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
+  /* This is freed in the on_write_completed callback */
+  char *write_buffer = gpr_malloc(length + GRPC_HEADER_SIZE_IN_BYTES);
+  *pp_write_buffer = write_buffer;
+  uint8_t *p = (uint8_t *)write_buffer;
+  /* Append 5 byte header */
+  *p++ = 0;
+  *p++ = (uint8_t)(length >> 24);
+  *p++ = (uint8_t)(length >> 16);
+  *p++ = (uint8_t)(length >> 8);
+  *p++ = (uint8_t)(length);
+  /* append actual data */
+  memcpy(p, GPR_SLICE_START_PTR(slice), length);
 }
 
-static void process_recv_message(stream_obj *s, const uint8_t *recv_data) {
-  gpr_slice read_data_slice = gpr_slice_malloc((uint32_t)s->total_read_bytes);
-  uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice);
-  if (s->total_read_bytes > 0) {
-    // Only copy if there is non-zero number of bytes
-    memcpy(dst_p, recv_data, (size_t)s->total_read_bytes);
-    gpr_slice_buffer_add(&s->read_slice_buffer, read_data_slice);
+/*
+ Convert metadata in a format that Cronet can consume
+*/
+static void convert_metadata_to_cronet_headers(
+    grpc_linked_mdelem *head, const char *host, char **pp_url,
+    cronet_bidirectional_stream_header **pp_headers, size_t *p_num_headers) {
+  grpc_linked_mdelem *curr = head;
+  /* Walk the linked list and get number of header fields */
+  size_t num_headers_available = 0;
+  while (curr != NULL) {
+    curr = curr->next;
+    num_headers_available++;
   }
-  grpc_slice_buffer_stream_init(&s->sbs, &s->read_slice_buffer, 0);
-  *s->recv_message = (grpc_byte_buffer *)&s->sbs;
+  /* Allocate enough memory. It is freed in the on_request_headers_sent callback
+   */
+  cronet_bidirectional_stream_header *headers =
+      (cronet_bidirectional_stream_header *)gpr_malloc(
+          sizeof(cronet_bidirectional_stream_header) * num_headers_available);
+  *pp_headers = headers;
+
+  /* Walk the linked list again, this time copying the header fields.
+    s->num_headers can be less than num_headers_available, as some headers
+    are not used for cronet.
+    TODO (makdharma): Eliminate need to traverse the LL second time for perf.
+   */
+  curr = head;
+  size_t num_headers = 0;
+  while (num_headers < num_headers_available) {
+    grpc_mdelem *mdelem = curr->md;
+    curr = curr->next;
+    const char *key = grpc_mdstr_as_c_string(mdelem->key);
+    const char *value = grpc_mdstr_as_c_string(mdelem->value);
+    if (mdelem->key == GRPC_MDSTR_METHOD || mdelem->key == GRPC_MDSTR_SCHEME ||
+        mdelem->key == GRPC_MDSTR_AUTHORITY) {
+      /* Cronet populates these fields on its own */
+      continue;
+    }
+    if (mdelem->key == GRPC_MDSTR_PATH) {
+      /* Create URL by appending :path value to the hostname */
+      gpr_asprintf(pp_url, "https://%s%s", host, value);
+      continue;
+    }
+    CRONET_LOG(GPR_DEBUG, "header %s = %s", key, value);
+    headers[num_headers].key = key;
+    headers[num_headers].value = value;
+    num_headers++;
+    if (curr == NULL) {
+      break;
+    }
+  }
+  *p_num_headers = (size_t)num_headers;
 }
 
 static int parse_grpc_header(const uint8_t *data) {
@@ -241,422 +571,439 @@
   return length;
 }
 
-static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
-                              int count) {
-  stream_obj *s = (stream_obj *)stream->annotation;
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "R: on_read_completed count=%d, total=%d, remaining=%d",
-            count, s->total_read_bytes, s->remaining_read_bytes);
-  }
-  if (count > 0) {
-    GPR_ASSERT(s->recv_message);
-    s->remaining_read_bytes -= count;
-    next_recv_step(s, ON_READ_COMPLETE);
-  } else {
-    s->read_closed = true;
-    next_recv_step(s, ON_READ_COMPLETE);
-  }
-}
-
-static void on_response_headers_received(
-    cronet_bidirectional_stream *stream,
-    const cronet_bidirectional_stream_header_array *headers,
-    const char *negotiated_protocol) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "R: on_response_headers_received");
-  }
-  stream_obj *s = (stream_obj *)stream->annotation;
-  enqueue_callbacks(s->callback_list[CB_RECV_INITIAL_METADATA]);
-  s->response_headers_received = true;
-  next_recv_step(s, ON_RESPONSE_HEADERS_RECEIVED);
-}
-
-static void on_request_headers_sent(cronet_bidirectional_stream *stream) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "W: on_request_headers_sent");
-  }
-  stream_obj *s = (stream_obj *)stream->annotation;
-  enqueue_callbacks(s->callback_list[CB_SEND_INITIAL_METADATA]);
-  s->cronet_send_state = CRONET_SEND_HEADER;
-  next_send_step(s);
-}
-
-// Callback function pointers (invoked by cronet in response to events)
-static cronet_bidirectional_stream_callback callbacks = {
-    on_request_headers_sent,
-    on_response_headers_received,
-    on_read_completed,
-    on_write_completed,
-    on_response_trailers_received,
-    on_succeeded,
-    on_failed,
-    on_canceled};
-
-static void invoke_closing_callback(stream_obj *s) {
-  grpc_chttp2_incoming_metadata_buffer_publish(&s->imb,
-                                               s->recv_trailing_metadata);
-  if (s->callback_list[CB_RECV_TRAILING_METADATA]) {
-    enqueue_callbacks(s->callback_list[CB_RECV_TRAILING_METADATA]);
-  }
-}
-
-static void set_recv_state(stream_obj *s, enum recv_state state) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "next_state = %s", recv_state_name[state]);
-  }
-  s->cronet_recv_state = state;
-}
-
-// This is invoked from perform_stream_op, and all on_xxxx callbacks.
-static void next_recv_step(stream_obj *s, enum e_caller caller) {
-  gpr_mu_lock(&s->recv_mu);
-  switch (s->cronet_recv_state) {
-    case CRONET_RECV_IDLE:
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_IDLE");
+/*
+  Op Execution: Decide if one of the actions contained in the stream op can be
+  executed. This is the heart of the state machine.
+*/
+static bool op_can_be_run(grpc_transport_stream_op *curr_op,
+                          struct op_state *stream_state,
+                          struct op_state *op_state, enum e_op_id op_id) {
+  bool result = true;
+  /* When call is canceled, every op can be run, except under following
+  conditions
+  */
+  bool is_canceled_of_failed = stream_state->state_op_done[OP_CANCEL_ERROR] ||
+                               stream_state->state_callback_received[OP_FAILED];
+  if (is_canceled_of_failed) {
+    if (op_id == OP_SEND_INITIAL_METADATA) result = false;
+    if (op_id == OP_SEND_MESSAGE) result = false;
+    if (op_id == OP_SEND_TRAILING_METADATA) result = false;
+    if (op_id == OP_CANCEL_ERROR) result = false;
+    /* already executed */
+    if (op_id == OP_RECV_INITIAL_METADATA &&
+        stream_state->state_op_done[OP_RECV_INITIAL_METADATA])
+      result = false;
+    if (op_id == OP_RECV_MESSAGE &&
+        stream_state->state_op_done[OP_RECV_MESSAGE])
+      result = false;
+    if (op_id == OP_RECV_TRAILING_METADATA &&
+        stream_state->state_op_done[OP_RECV_TRAILING_METADATA])
+      result = false;
+  } else if (op_id == OP_SEND_INITIAL_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_SEND_INITIAL_METADATA]) result = false;
+  } else if (op_id == OP_RECV_INITIAL_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_RECV_INITIAL_METADATA]) result = false;
+    /* we haven't sent headers yet. */
+    else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
+      result = false;
+    /* we haven't received headers yet. */
+    else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA])
+      result = false;
+  } else if (op_id == OP_SEND_MESSAGE) {
+    /* already executed (note we're checking op specific state, not stream
+     state) */
+    if (op_state->state_op_done[OP_SEND_MESSAGE]) result = false;
+    /* we haven't sent headers yet. */
+    else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
+      result = false;
+  } else if (op_id == OP_RECV_MESSAGE) {
+    /* already executed */
+    if (op_state->state_op_done[OP_RECV_MESSAGE]) result = false;
+    /* we haven't received headers yet. */
+    else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA])
+      result = false;
+  } else if (op_id == OP_RECV_TRAILING_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_RECV_TRAILING_METADATA]) result = false;
+    /* we have asked for but haven't received message yet. */
+    else if (stream_state->state_op_done[OP_READ_REQ_MADE] &&
+             !stream_state->state_op_done[OP_RECV_MESSAGE])
+      result = false;
+    /* we haven't received trailers  yet. */
+    else if (!stream_state->state_callback_received[OP_RECV_TRAILING_METADATA])
+      result = false;
+    /* we haven't received on_succeeded  yet. */
+    else if (!stream_state->state_callback_received[OP_SUCCEEDED])
+      result = false;
+  } else if (op_id == OP_SEND_TRAILING_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_SEND_TRAILING_METADATA]) result = false;
+    /* we haven't sent initial metadata yet */
+    else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
+      result = false;
+    /* we haven't sent message yet */
+    else if (curr_op->send_message &&
+             !stream_state->state_op_done[OP_SEND_MESSAGE])
+      result = false;
+    /* we haven't got on_write_completed for the send yet */
+    else if (stream_state->state_op_done[OP_SEND_MESSAGE] &&
+             !stream_state->state_callback_received[OP_SEND_MESSAGE])
+      result = false;
+  } else if (op_id == OP_CANCEL_ERROR) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_CANCEL_ERROR]) result = false;
+  } else if (op_id == OP_ON_COMPLETE) {
+    /* already executed (note we're checking op specific state, not stream
+    state) */
+    if (op_state->state_op_done[OP_ON_COMPLETE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    }
+    /* Check if every op that was asked for is done. */
+    else if (curr_op->send_initial_metadata &&
+             !stream_state->state_callback_received[OP_SEND_INITIAL_METADATA]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->send_message &&
+               !op_state->state_op_done[OP_SEND_MESSAGE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->send_message &&
+               !stream_state->state_callback_received[OP_SEND_MESSAGE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->send_trailing_metadata &&
+               !stream_state->state_op_done[OP_SEND_TRAILING_METADATA]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->recv_initial_metadata &&
+               !stream_state->state_op_done[OP_RECV_INITIAL_METADATA]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->recv_message &&
+               !stream_state->state_op_done[OP_RECV_MESSAGE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->recv_trailing_metadata) {
+      /* We aren't done with trailing metadata yet */
+      if (!stream_state->state_op_done[OP_RECV_TRAILING_METADATA]) {
+        CRONET_LOG(GPR_DEBUG, "Because");
+        result = false;
       }
-      if (caller == PERFORM_STREAM_OP ||
-          caller == ON_RESPONSE_HEADERS_RECEIVED) {
-        if (s->read_closed && s->response_trailers_received) {
-          invoke_closing_callback(s);
-          set_recv_state(s, CRONET_RECV_CLOSED);
-        } else if (s->response_headers_received == true &&
-                   s->read_requested == true) {
-          set_recv_state(s, CRONET_RECV_READ_LENGTH);
-          s->total_read_bytes = s->remaining_read_bytes =
-              GRPC_HEADER_SIZE_IN_BYTES;
-          GPR_ASSERT(s->read_buffer);
-          if (grpc_cronet_trace) {
-            gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
-          }
-          cronet_bidirectional_stream_read(s->cbs, s->read_buffer,
-                                           s->remaining_read_bytes);
+      /* We've asked for actual message in an earlier op, and it hasn't been
+        delivered yet. */
+      else if (stream_state->state_op_done[OP_READ_REQ_MADE]) {
+        /* If this op is not the one asking for read, (which means some earlier
+          op has asked), and the read hasn't been delivered. */
+        if (!curr_op->recv_message &&
+            !stream_state->state_callback_received[OP_SUCCEEDED]) {
+          CRONET_LOG(GPR_DEBUG, "Because");
+          result = false;
         }
       }
-      break;
-    case CRONET_RECV_READ_LENGTH:
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_LENGTH");
-      }
-      if (caller == ON_READ_COMPLETE) {
-        if (s->read_closed) {
-          invoke_closing_callback(s);
-          enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
-          set_recv_state(s, CRONET_RECV_CLOSED);
-        } else {
-          GPR_ASSERT(s->remaining_read_bytes == 0);
-          set_recv_state(s, CRONET_RECV_READ_DATA);
-          s->total_read_bytes = s->remaining_read_bytes =
-              parse_grpc_header((const uint8_t *)s->read_buffer);
-          s->read_buffer =
-              gpr_realloc(s->read_buffer, (uint32_t)s->remaining_read_bytes);
-          GPR_ASSERT(s->read_buffer);
-          if (grpc_cronet_trace) {
-            gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
-          }
-          if (s->remaining_read_bytes > 0) {
-            cronet_bidirectional_stream_read(s->cbs, (char *)s->read_buffer,
-                                             s->remaining_read_bytes);
-          } else {
-            // Calling the closing callback directly since this is a 0 byte read
-            // for an empty message.
-            process_recv_message(s, NULL);
-            enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
-            invoke_closing_callback(s);
-            set_recv_state(s, CRONET_RECV_CLOSED);
-          }
-        }
-      }
-      break;
-    case CRONET_RECV_READ_DATA:
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_DATA");
-      }
-      if (caller == ON_READ_COMPLETE) {
-        if (s->remaining_read_bytes > 0) {
-          int offset = s->total_read_bytes - s->remaining_read_bytes;
-          GPR_ASSERT(s->read_buffer);
-          if (grpc_cronet_trace) {
-            gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
-          }
-          cronet_bidirectional_stream_read(
-              s->cbs, (char *)s->read_buffer + offset, s->remaining_read_bytes);
-        } else {
-          gpr_slice_buffer_init(&s->read_slice_buffer);
-          uint8_t *p = (uint8_t *)s->read_buffer;
-          process_recv_message(s, p);
-          set_recv_state(s, CRONET_RECV_IDLE);
-          enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
-        }
-      }
-      break;
-    case CRONET_RECV_CLOSED:
-      break;
-    default:
-      GPR_ASSERT(0);  // Should not reach here
-      break;
+    }
+    /* We should see at least one on_write_completed for the trailers that we
+      sent */
+    else if (curr_op->send_trailing_metadata &&
+             !stream_state->state_callback_received[OP_SEND_MESSAGE])
+      result = false;
   }
-  gpr_mu_unlock(&s->recv_mu);
+  CRONET_LOG(GPR_DEBUG, "op_can_be_run %s : %s", op_id_string(op_id),
+             result ? "YES" : "NO");
+  return result;
 }
 
-// This function takes the data from s->write_slice_buffer and assembles into
-// a contiguous byte stream with 5 byte gRPC header prepended.
-static void create_grpc_frame(stream_obj *s) {
-  gpr_slice slice = gpr_slice_buffer_take_first(&s->write_slice_buffer);
-  uint8_t *raw_data = GPR_SLICE_START_PTR(slice);
-  size_t length = GPR_SLICE_LENGTH(slice);
-  s->write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
-  s->write_buffer = gpr_realloc(s->write_buffer, s->write_buffer_size);
-  uint8_t *p = (uint8_t *)s->write_buffer;
-  // Append 5 byte header
-  *p++ = 0;
-  *p++ = (uint8_t)(length >> 24);
-  *p++ = (uint8_t)(length >> 16);
-  *p++ = (uint8_t)(length >> 8);
-  *p++ = (uint8_t)(length);
-  // append actual data
-  memcpy(p, raw_data, length);
-}
-
-static void do_write(stream_obj *s) {
-  gpr_slice_buffer *sb = &s->write_slice_buffer;
-  GPR_ASSERT(sb->count <= 1);
-  if (sb->count > 0) {
-    create_grpc_frame(s);
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write");
-    }
-    cronet_bidirectional_stream_write(s->cbs, s->write_buffer,
-                                      (int)s->write_buffer_size, false);
-  }
-}
-
-//
-static void next_send_step(stream_obj *s) {
-  switch (s->cronet_send_state) {
-    case CRONET_SEND_IDLE:
-      GPR_ASSERT(
-          s->cbs);  // cronet_bidirectional_stream is not initialized yet.
-      s->cronet_send_state = CRONET_REQ_STARTED;
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_start to %s", s->url);
-      }
-      cronet_bidirectional_stream_start(s->cbs, s->url, 0, "POST",
-                                        &s->header_array, false);
-      // we no longer need the memory that was allocated earlier.
-      gpr_free(s->header_array.headers);
-      break;
-    case CRONET_SEND_HEADER:
-      do_write(s);
-      s->cronet_send_state = CRONET_WRITE;
-      break;
-    case CRONET_WRITE_COMPLETED:
-      do_write(s);
-      break;
-    default:
-      GPR_ASSERT(0);
-      break;
-  }
-}
-
-static void convert_metadata_to_cronet_headers(grpc_linked_mdelem *head,
-                                               const char *host,
-                                               stream_obj *s) {
-  grpc_linked_mdelem *curr = head;
-  // Walk the linked list and get number of header fields
-  uint32_t num_headers_available = 0;
-  while (curr != NULL) {
-    curr = curr->next;
-    num_headers_available++;
-  }
-  // Allocate enough memory
-  s->headers = (cronet_bidirectional_stream_header *)gpr_malloc(
-      sizeof(cronet_bidirectional_stream_header) * num_headers_available);
-
-  // Walk the linked list again, this time copying the header fields.
-  // s->num_headers
-  // can be less than num_headers_available, as some headers are not used for
-  // cronet
-  curr = head;
-  s->num_headers = 0;
-  while (s->num_headers < num_headers_available) {
-    grpc_mdelem *mdelem = curr->md;
-    curr = curr->next;
-    const char *key = grpc_mdstr_as_c_string(mdelem->key);
-    const char *value = grpc_mdstr_as_c_string(mdelem->value);
-    if (strcmp(key, ":scheme") == 0 || strcmp(key, ":method") == 0 ||
-        strcmp(key, ":authority") == 0) {
-      // Cronet populates these fields on its own.
-      continue;
-    }
-    if (strcmp(key, ":path") == 0) {
-      // Create URL by appending :path value to the hostname
-      gpr_asprintf(&s->url, "https://%s%s", host, value);
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "extracted URL = %s", s->url);
-      }
-      continue;
-    }
-    s->headers[s->num_headers].key = key;
-    s->headers[s->num_headers].value = value;
-    s->num_headers++;
-    if (curr == NULL) {
-      break;
-    }
-  }
-}
-
-static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                              grpc_stream *gs, grpc_transport_stream_op *op) {
-  grpc_cronet_transport *ct = (grpc_cronet_transport *)gt;
-  GPR_ASSERT(ct->engine);
-  stream_obj *s = (stream_obj *)gs;
-  if (op->recv_trailing_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG,
-              "perform_stream_op - recv_trailing_metadata: on_complete=%p",
-              op->on_complete);
-    }
-    s->recv_trailing_metadata = op->recv_trailing_metadata;
-    GPR_ASSERT(!s->callback_list[CB_RECV_TRAILING_METADATA][0]);
-    s->callback_list[CB_RECV_TRAILING_METADATA][0] = op->on_complete;
-  }
-  if (op->recv_message) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "perform_stream_op - recv_message: on_complete=%p",
-              op->on_complete);
-    }
-    s->recv_message = (grpc_byte_buffer **)op->recv_message;
-    GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][0]);
-    GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][1]);
-    s->callback_list[CB_RECV_MESSAGE][0] = op->recv_message_ready;
-    s->callback_list[CB_RECV_MESSAGE][1] = op->on_complete;
-    s->read_requested = true;
-    next_recv_step(s, PERFORM_STREAM_OP);
-  }
-  if (op->recv_initial_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "perform_stream_op - recv_initial_metadata:=%p",
-              op->on_complete);
-    }
-    s->recv_initial_metadata = op->recv_initial_metadata;
-    GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][0]);
-    GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][1]);
-    s->callback_list[CB_RECV_INITIAL_METADATA][0] =
-        op->recv_initial_metadata_ready;
-    s->callback_list[CB_RECV_INITIAL_METADATA][1] = op->on_complete;
-  }
-  if (op->send_initial_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG,
-              "perform_stream_op - send_initial_metadata: on_complete=%p",
-              op->on_complete);
-    }
-    s->num_headers = 0;
-    convert_metadata_to_cronet_headers(op->send_initial_metadata->list.head,
-                                       ct->host, s);
-    s->header_array.count = s->num_headers;
-    s->header_array.capacity = s->num_headers;
-    s->header_array.headers = s->headers;
-    GPR_ASSERT(!s->callback_list[CB_SEND_INITIAL_METADATA][0]);
-    s->callback_list[CB_SEND_INITIAL_METADATA][0] = op->on_complete;
-  }
-  if (op->send_message) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "perform_stream_op - send_message: on_complete=%p",
-              op->on_complete);
-    }
-    grpc_byte_stream_next(exec_ctx, op->send_message, &s->slice,
-                          op->send_message->length, NULL);
-    // Check that compression flag is not ON. We don't support compression yet.
-    // TODO (makdharma): add compression support
-    GPR_ASSERT(op->send_message->flags == 0);
-    gpr_slice_buffer_add(&s->write_slice_buffer, s->slice);
-    if (s->cbs == NULL) {
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_create");
-      }
-      s->cbs = cronet_bidirectional_stream_create(ct->engine, s, &callbacks);
-      GPR_ASSERT(s->cbs);
-      s->read_closed = false;
-      s->response_trailers_received = false;
-      s->response_headers_received = false;
-      s->cronet_send_state = CRONET_SEND_IDLE;
-      s->cronet_recv_state = CRONET_RECV_IDLE;
-    }
-    GPR_ASSERT(!s->callback_list[CB_SEND_MESSAGE][0]);
-    s->callback_list[CB_SEND_MESSAGE][0] = op->on_complete;
-    next_send_step(s);
-  }
-  if (op->send_trailing_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG,
-              "perform_stream_op - send_trailing_metadata: on_complete=%p",
-              op->on_complete);
-    }
-    GPR_ASSERT(!s->callback_list[CB_SEND_TRAILING_METADATA][0]);
-    s->callback_list[CB_SEND_TRAILING_METADATA][0] = op->on_complete;
-    if (s->cbs) {
-      // Send an "empty" write to the far end to signal that we're done.
-      // This will induce the server to send down trailers.
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write");
-      }
-      cronet_bidirectional_stream_write(s->cbs, "abc", 0, true);
+/*
+  TODO (makdharma): Break down this function in smaller chunks for readability.
+*/
+static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
+                                          struct op_and_state *oas) {
+  grpc_transport_stream_op *stream_op = &oas->op;
+  struct stream_obj *s = oas->s;
+  struct op_state *stream_state = &s->state;
+  enum e_op_result result = NO_ACTION_POSSIBLE;
+  if (stream_op->send_initial_metadata &&
+      op_can_be_run(stream_op, stream_state, &oas->state,
+                    OP_SEND_INITIAL_METADATA)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p OP_SEND_INITIAL_METADATA", oas);
+    /* This OP is the beginning. Reset various states */
+    memset(&s->header_array, 0, sizeof(s->header_array));
+    memset(&stream_state->rs, 0, sizeof(stream_state->rs));
+    memset(&stream_state->ws, 0, sizeof(stream_state->ws));
+    memset(stream_state->state_op_done, 0, sizeof(stream_state->state_op_done));
+    memset(stream_state->state_callback_received, 0,
+           sizeof(stream_state->state_callback_received));
+    /* Start new cronet stream. It is destroyed in on_succeeded, on_canceled,
+     * on_failed */
+    GPR_ASSERT(s->cbs == NULL);
+    s->cbs = cronet_bidirectional_stream_create(s->curr_ct.engine, s->curr_gs,
+                                                &cronet_callbacks);
+    CRONET_LOG(GPR_DEBUG, "%p = cronet_bidirectional_stream_create()", s->cbs);
+    char *url;
+    s->header_array.headers = NULL;
+    convert_metadata_to_cronet_headers(
+        stream_op->send_initial_metadata->list.head, s->curr_ct.host, &url,
+        &s->header_array.headers, &s->header_array.count);
+    s->header_array.capacity = s->header_array.count;
+    CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_start(%p, %s)", s->cbs,
+               url);
+    cronet_bidirectional_stream_start(s->cbs, url, 0, "POST", &s->header_array,
+                                      false);
+    stream_state->state_op_done[OP_SEND_INITIAL_METADATA] = true;
+    result = ACTION_TAKEN_WITH_CALLBACK;
+  } else if (stream_op->recv_initial_metadata &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_RECV_INITIAL_METADATA)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_INITIAL_METADATA", oas);
+    if (!stream_state->state_op_done[OP_CANCEL_ERROR]) {
+      grpc_chttp2_incoming_metadata_buffer_publish(
+          &oas->s->state.rs.initial_metadata, stream_op->recv_initial_metadata);
+      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
+                          GRPC_ERROR_NONE, NULL);
     } else {
-      // We never created a stream. This was probably an empty request.
-      invoke_closing_callback(s);
+      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
+                          GRPC_ERROR_CANCELLED, NULL);
     }
+    stream_state->state_op_done[OP_RECV_INITIAL_METADATA] = true;
+    result = ACTION_TAKEN_NO_CALLBACK;
+  } else if (stream_op->send_message &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_SEND_MESSAGE)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_SEND_MESSAGE", oas);
+    gpr_slice_buffer write_slice_buffer;
+    gpr_slice slice;
+    gpr_slice_buffer_init(&write_slice_buffer);
+    grpc_byte_stream_next(NULL, stream_op->send_message, &slice,
+                          stream_op->send_message->length, NULL);
+    /* Check that compression flag is OFF. We don't support compression yet. */
+    if (stream_op->send_message->flags != 0) {
+      gpr_log(GPR_ERROR, "Compression is not supported");
+      GPR_ASSERT(stream_op->send_message->flags == 0);
+    }
+    gpr_slice_buffer_add(&write_slice_buffer, slice);
+    if (write_slice_buffer.count != 1) {
+      /* Empty request not handled yet */
+      gpr_log(GPR_ERROR, "Empty request is not supported");
+      GPR_ASSERT(write_slice_buffer.count == 1);
+    }
+    if (write_slice_buffer.count > 0) {
+      size_t write_buffer_size;
+      create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer,
+                        &write_buffer_size);
+      CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, %p)",
+                 s->cbs, stream_state->ws.write_buffer);
+      stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
+      cronet_bidirectional_stream_write(s->cbs, stream_state->ws.write_buffer,
+                                        (int)write_buffer_size, false);
+      result = ACTION_TAKEN_WITH_CALLBACK;
+    }
+    stream_state->state_op_done[OP_SEND_MESSAGE] = true;
+    oas->state.state_op_done[OP_SEND_MESSAGE] = true;
+  } else if (stream_op->recv_message &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_RECV_MESSAGE)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_MESSAGE", oas);
+    if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
+      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
+                          GRPC_ERROR_CANCELLED, NULL);
+      stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+    } else if (stream_state->rs.read_stream_closed == true) {
+      /* No more data will be received */
+      CRONET_LOG(GPR_DEBUG, "read stream closed");
+      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
+                          GRPC_ERROR_NONE, NULL);
+      stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+      oas->state.state_op_done[OP_RECV_MESSAGE] = true;
+    } else if (stream_state->rs.length_field_received == false) {
+      if (stream_state->rs.received_bytes == GRPC_HEADER_SIZE_IN_BYTES &&
+          stream_state->rs.remaining_bytes == 0) {
+        /* Start a read operation for data */
+        stream_state->rs.length_field_received = true;
+        stream_state->rs.length_field = stream_state->rs.remaining_bytes =
+            parse_grpc_header((const uint8_t *)stream_state->rs.read_buffer);
+        CRONET_LOG(GPR_DEBUG, "length field = %d",
+                   stream_state->rs.length_field);
+        if (stream_state->rs.length_field > 0) {
+          stream_state->rs.read_buffer =
+              gpr_malloc((size_t)stream_state->rs.length_field);
+          GPR_ASSERT(stream_state->rs.read_buffer);
+          stream_state->rs.remaining_bytes = stream_state->rs.length_field;
+          stream_state->rs.received_bytes = 0;
+          CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
+          stream_state->state_op_done[OP_READ_REQ_MADE] =
+              true; /* Indicates that at least one read request has been made */
+          cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
+                                           stream_state->rs.remaining_bytes);
+          result = ACTION_TAKEN_WITH_CALLBACK;
+        } else {
+          stream_state->rs.remaining_bytes = 0;
+          CRONET_LOG(GPR_DEBUG, "read operation complete. Empty response.");
+          gpr_slice_buffer_init(&stream_state->rs.read_slice_buffer);
+          grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
+                                        &stream_state->rs.read_slice_buffer, 0);
+          *((grpc_byte_buffer **)stream_op->recv_message) =
+              (grpc_byte_buffer *)&stream_state->rs.sbs;
+          grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
+                              GRPC_ERROR_NONE, NULL);
+          stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+          oas->state.state_op_done[OP_RECV_MESSAGE] = true;
+          result = ACTION_TAKEN_NO_CALLBACK;
+        }
+      } else if (stream_state->rs.remaining_bytes == 0) {
+        /* Start a read operation for first 5 bytes (GRPC header) */
+        stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
+        stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
+        stream_state->rs.received_bytes = 0;
+        CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
+        stream_state->state_op_done[OP_READ_REQ_MADE] =
+            true; /* Indicates that at least one read request has been made */
+        cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
+                                         stream_state->rs.remaining_bytes);
+      }
+      result = ACTION_TAKEN_WITH_CALLBACK;
+    } else if (stream_state->rs.remaining_bytes == 0) {
+      CRONET_LOG(GPR_DEBUG, "read operation complete");
+      gpr_slice read_data_slice =
+          gpr_slice_malloc((uint32_t)stream_state->rs.length_field);
+      uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice);
+      memcpy(dst_p, stream_state->rs.read_buffer,
+             (size_t)stream_state->rs.length_field);
+      gpr_slice_buffer_init(&stream_state->rs.read_slice_buffer);
+      gpr_slice_buffer_add(&stream_state->rs.read_slice_buffer,
+                           read_data_slice);
+      grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
+                                    &stream_state->rs.read_slice_buffer, 0);
+      *((grpc_byte_buffer **)stream_op->recv_message) =
+          (grpc_byte_buffer *)&stream_state->rs.sbs;
+      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
+                          GRPC_ERROR_NONE, NULL);
+      stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+      oas->state.state_op_done[OP_RECV_MESSAGE] = true;
+      /* Clear read state of the stream, so next read op (if it were to come)
+       * will work */
+      stream_state->rs.received_bytes = stream_state->rs.remaining_bytes =
+          stream_state->rs.length_field_received = 0;
+      result = ACTION_TAKEN_NO_CALLBACK;
+    }
+  } else if (stream_op->recv_trailing_metadata &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_RECV_TRAILING_METADATA)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_TRAILING_METADATA", oas);
+    if (oas->s->state.rs.trailing_metadata_valid) {
+      grpc_chttp2_incoming_metadata_buffer_publish(
+          &oas->s->state.rs.trailing_metadata,
+          stream_op->recv_trailing_metadata);
+      stream_state->rs.trailing_metadata_valid = false;
+    }
+    stream_state->state_op_done[OP_RECV_TRAILING_METADATA] = true;
+    result = ACTION_TAKEN_NO_CALLBACK;
+  } else if (stream_op->send_trailing_metadata &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_SEND_TRAILING_METADATA)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_SEND_TRAILING_METADATA", oas);
+    CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, 0)", s->cbs);
+    stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
+    cronet_bidirectional_stream_write(s->cbs, "", 0, true);
+    stream_state->state_op_done[OP_SEND_TRAILING_METADATA] = true;
+    result = ACTION_TAKEN_WITH_CALLBACK;
+  } else if (stream_op->cancel_error &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_CANCEL_ERROR)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_CANCEL_ERROR", oas);
+    CRONET_LOG(GPR_DEBUG, "W: cronet_bidirectional_stream_cancel(%p)", s->cbs);
+    if (s->cbs) {
+      cronet_bidirectional_stream_cancel(s->cbs);
+    }
+    stream_state->state_op_done[OP_CANCEL_ERROR] = true;
+    result = ACTION_TAKEN_WITH_CALLBACK;
+  } else if (stream_op->on_complete &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_ON_COMPLETE)) {
+    /* All actions in this stream_op are complete. Call the on_complete callback
+     */
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_ON_COMPLETE", oas);
+    grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete, GRPC_ERROR_NONE,
+                        NULL);
+    oas->state.state_op_done[OP_ON_COMPLETE] = true;
+    oas->done = true;
+    /* reset any send message state, only if this ON_COMPLETE is about a send.
+     */
+    if (stream_op->send_message) {
+      stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
+      stream_state->state_op_done[OP_SEND_MESSAGE] = false;
+    }
+    result = ACTION_TAKEN_NO_CALLBACK;
+    /* If this is the on_complete callback being called for a received message -
+      make a note */
+    if (stream_op->recv_message)
+      stream_state->state_op_done[OP_RECV_MESSAGE_AND_ON_COMPLETE] = true;
+  } else {
+    result = NO_ACTION_POSSIBLE;
   }
+  return result;
 }
 
+/*
+  Functions used by upper layers to access transport functionality.
+*/
+
 static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                        grpc_stream *gs, grpc_stream_refcount *refcount,
                        const void *server_data) {
   stream_obj *s = (stream_obj *)gs;
-  memset(s->callback_list, 0, sizeof(s->callback_list));
+  memset(&s->storage, 0, sizeof(s->storage));
+  s->storage.head = NULL;
+  memset(&s->state, 0, sizeof(s->state));
+  s->curr_op = NULL;
   s->cbs = NULL;
-  gpr_mu_init(&s->recv_mu);
-  s->read_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES);
-  s->write_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES);
-  gpr_slice_buffer_init(&s->write_slice_buffer);
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "cronet_transport - init_stream");
-  }
+  memset(&s->header_array, 0, sizeof(s->header_array));
+  memset(&s->state.rs, 0, sizeof(s->state.rs));
+  memset(&s->state.ws, 0, sizeof(s->state.ws));
+  memset(s->state.state_op_done, 0, sizeof(s->state.state_op_done));
+  memset(s->state.state_callback_received, 0,
+         sizeof(s->state.state_callback_received));
+  gpr_mu_init(&s->mu);
   return 0;
 }
 
-static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                           grpc_stream *gs, void *and_free_memory) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "Destroy stream");
-  }
+static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                                   grpc_stream *gs, grpc_pollset *pollset) {}
+
+static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
+                                       grpc_transport *gt, grpc_stream *gs,
+                                       grpc_pollset_set *pollset_set) {}
+
+static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                              grpc_stream *gs, grpc_transport_stream_op *op) {
+  CRONET_LOG(GPR_DEBUG, "perform_stream_op");
   stream_obj *s = (stream_obj *)gs;
-  s->cbs = NULL;
-  gpr_free(s->read_buffer);
-  gpr_free(s->write_buffer);
-  gpr_free(s->url);
-  gpr_mu_destroy(&s->recv_mu);
-  if (and_free_memory) {
-    gpr_free(and_free_memory);
-  }
+  s->curr_gs = gs;
+  memcpy(&s->curr_ct, gt, sizeof(grpc_cronet_transport));
+  add_to_storage(s, op);
+  execute_from_storage(s);
 }
 
-static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
-  grpc_cronet_transport *ct = (grpc_cronet_transport *)gt;
-  gpr_free(ct->host);
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "Destroy transport");
-  }
+static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                           grpc_stream *gs, void *and_free_memory) {}
+
+static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {}
+
+static char *get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
+  return NULL;
 }
 
+static void perform_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                       grpc_transport_op *op) {}
+
 const grpc_transport_vtable grpc_cronet_vtable = {sizeof(stream_obj),
                                                   "cronet_http",
                                                   init_stream,
                                                   set_pollset_do_nothing,
                                                   set_pollset_set_do_nothing,
                                                   perform_stream_op,
-                                                  NULL,
+                                                  perform_op,
                                                   destroy_stream,
                                                   destroy_transport,
-                                                  NULL};
+                                                  get_peer};
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
index c2cd20e..4c4772a 100644
--- a/src/cpp/util/byte_buffer.cc
+++ b/src/cpp/util/byte_buffer.cc
@@ -37,12 +37,19 @@
 namespace grpc {
 
 ByteBuffer::ByteBuffer(const Slice* slices, size_t nslices) {
-  // TODO(yangg) maybe expose some core API to simplify this
-  std::vector<gpr_slice> c_slices(nslices);
-  for (size_t i = 0; i < nslices; i++) {
-    c_slices[i] = slices[i].slice_;
-  }
-  buffer_ = grpc_raw_byte_buffer_create(c_slices.data(), nslices);
+  // The following assertions check that the representation of a grpc::Slice is
+  // identical to that of a gpr_slice:  it has a gpr_slice field, and nothing
+  // else.
+  static_assert(std::is_same<decltype(slices[0].slice_), gpr_slice>::value,
+                "Slice must have same representation as gpr_slice");
+  static_assert(sizeof(Slice) == sizeof(gpr_slice),
+                "Slice must have same representation as gpr_slice");
+  // The const_cast is legal if grpc_raw_byte_buffer_create() does no more
+  // than its advertised side effect of increasing the reference count of the
+  // slices it processes, and such an increase does not affect the semantics
+  // seen by the caller of this constructor.
+  buffer_ = grpc_raw_byte_buffer_create(
+      reinterpret_cast<gpr_slice*>(const_cast<Slice*>(slices)), nslices);
 }
 
 ByteBuffer::~ByteBuffer() {
@@ -95,4 +102,10 @@
   return *this;
 }
 
+void ByteBuffer::Swap(ByteBuffer* other) {
+  grpc_byte_buffer* tmp = other->buffer_;
+  other->buffer_ = this->buffer_;
+  this->buffer_ = tmp;
+}
+
 }  // namespace grpc
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 1fa14fc..7a69553 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -39,30 +39,25 @@
     <AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.15.0\lib\net45\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index 4baed37..a1f5668 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -15,7 +15,7 @@
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
 	<dependencies>
-	  <dependency id="Google.Apis.Auth" version="1.11.1" />
+	  <dependency id="Google.Apis.Auth" version="1.15.0" />
 	  <dependency id="Grpc.Core" version="$version$" />
     </dependencies>
   </metadata>
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
index c20d9ce..738d3e6 100644
--- a/src/csharp/Grpc.Auth/packages.config
+++ b/src/csharp/Grpc.Auth/packages.config
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.15.0" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.15.0" targetFramework="net45" />
   <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/project.json b/src/csharp/Grpc.Auth/project.json
index 6215ca3..30f0944 100644
--- a/src/csharp/Grpc.Auth/project.json
+++ b/src/csharp/Grpc.Auth/project.json
@@ -23,13 +23,13 @@
   },
   "dependencies": {
     "Grpc.Core": "1.1.0-dev",
-    "Google.Apis.Auth": "1.11.1"
+    "Google.Apis.Auth": "1.15.0"
   },
   "frameworks": {
     "net45": { },
     "netstandard1.5": {
       "imports": [
-        "net45"
+        "portable-net45"
       ],
       "dependencies": {
         "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index df887d8..f1eb13d 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -58,9 +58,9 @@
         [Test]
         public void TestsJsonUpToDate()
         {
-            Dictionary<string, List<string>> discoveredTests = DiscoverAllTestClasses();
-			Dictionary<string, List<string>> testsFromFile 
-			    = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(ReadTestsJson());
+            var discoveredTests = DiscoverAllTestClasses();
+            var testsFromFile 
+                = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(ReadTestsJson());
 
             Assert.AreEqual(discoveredTests, testsFromFile);
         }
diff --git a/src/csharp/Grpc.Examples.MathClient/project.json b/src/csharp/Grpc.Examples.MathClient/project.json
index 764a335..ad31947 100644
--- a/src/csharp/Grpc.Examples.MathClient/project.json
+++ b/src/csharp/Grpc.Examples.MathClient/project.json
@@ -42,6 +42,11 @@
       }
     }
   },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
 
   "dependencies": {
     "Grpc.Examples": {
diff --git a/src/csharp/Grpc.Examples.MathServer/project.json b/src/csharp/Grpc.Examples.MathServer/project.json
index 764a335..ad31947 100644
--- a/src/csharp/Grpc.Examples.MathServer/project.json
+++ b/src/csharp/Grpc.Examples.MathServer/project.json
@@ -42,6 +42,11 @@
       }
     }
   },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
 
   "dependencies": {
     "Grpc.Examples": {
diff --git a/src/csharp/Grpc.Examples/project.json b/src/csharp/Grpc.Examples/project.json
index 5329f39..98bd5d8 100644
--- a/src/csharp/Grpc.Examples/project.json
+++ b/src/csharp/Grpc.Examples/project.json
@@ -20,11 +20,12 @@
         "System.IO": ""
       }
     },
-    "netstandard1.5": {
+    "netcoreapp1.0": {
       "imports": [
         "portable-net45"
       ],
       "dependencies": {
+        "Microsoft.NETCore.App": "1.0.0",
         "NETStandard.Library": "1.6.0"
       }
     }
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index 91fb3ce..6816b5c 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -39,30 +39,25 @@
     <AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.15.0\lib\net45\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/packages.config b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
index c20d9ce..738d3e6 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.15.0" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.15.0" targetFramework="net45" />
   <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
index dda26a6..593bf09 100644
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
@@ -58,7 +58,6 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
-    <None Include="app.config" />
     <None Include="Grpc.IntegrationTesting.QpsWorker.project.json" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config b/src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config
deleted file mode 100644
index e204447..0000000
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/app.config
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Google.Apis.Core" publicKeyToken="4b01fa6e34db77ab" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.11.1.0" newVersion="1.11.1.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
index 9afcb30..2879507 100644
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
@@ -44,6 +44,11 @@
       }
     }
   },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
 
   "dependencies": {
     "Grpc.IntegrationTesting": {
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index f73d99d..987387c 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -39,30 +39,25 @@
     <AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core, Version=1.11.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.15.0\lib\net45\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/packages.config b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
index c20d9ce..738d3e6 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.15.0" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.15.0" targetFramework="net45" />
   <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
index 9afcb30..2879507 100644
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
@@ -44,6 +44,11 @@
       }
     }
   },
+  "runtimes": {
+    "win7-x64": { },
+    "debian.8-x64": { },
+    "osx.10.11-x64": { }
+  },
 
   "dependencies": {
     "Grpc.IntegrationTesting": {
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 7512d2a..e030b21 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -38,9 +38,6 @@
     <AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="CommandLine">
-      <HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
-    </Reference>
     <Reference Include="Moq">
       <HintPath>..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll</HintPath>
     </Reference>
@@ -51,15 +48,6 @@
     <Reference Include="BouncyCastle.Crypto">
       <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
     </Reference>
-    <Reference Include="Google.Apis.Auth">
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices">
-      <HintPath>..\packages\Google.Apis.Auth.1.11.1\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core">
-      <HintPath>..\packages\Google.Apis.Core.1.11.1\lib\net45\Google.Apis.Core.dll</HintPath>
-    </Reference>
     <Reference Include="Google.Protobuf">
       <HintPath>..\packages\Google.Protobuf.3.0.0-beta3\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
     </Reference>
@@ -75,6 +63,18 @@
     <Reference Include="nunitlite">
       <HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
     </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.15.0\lib\net45\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
+    <Reference Include="CommandLineParser.Unofficial">
+      <HintPath>..\packages\CommandLineParser.Unofficial.2.0.275\lib\net45\CommandLineParser.Unofficial.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index ec407d3..79fd18b 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -56,24 +56,24 @@
     {
         private class ClientOptions
         {
-            [Option("server_host", DefaultValue = "127.0.0.1")]
+            [Option("server_host", Default = "127.0.0.1")]
             public string ServerHost { get; set; }
 
-            [Option("server_host_override", DefaultValue = TestCredentials.DefaultHostOverride)]
+            [Option("server_host_override", Default = TestCredentials.DefaultHostOverride)]
             public string ServerHostOverride { get; set; }
 
             [Option("server_port", Required = true)]
             public int ServerPort { get; set; }
 
-            [Option("test_case", DefaultValue = "large_unary")]
+            [Option("test_case", Default = "large_unary")]
             public string TestCase { get; set; }
 
             // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
-            [Option("use_tls", DefaultValue = false)]
+            [Option("use_tls", Default = false)]
             public bool? UseTls { get; set; }
 
             // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca)
-            [Option("use_test_ca", DefaultValue = false)]
+            [Option("use_test_ca", Default = false)]
             public bool? UseTestCa { get; set; }
 
             [Option("default_service_account", Required = false)]
@@ -84,19 +84,6 @@
 
             [Option("service_account_key_file", Required = false)]
             public string ServiceAccountKeyFile { get; set; }
-
-            [HelpOption]
-            public string GetUsage()
-            {
-                var help = new HelpText
-                {
-                    Heading = "gRPC C# interop testing client",
-                    AddDashesToOption = true
-                };
-                help.AddPreOptionsLine("Usage:");
-                help.AddOptions(this);
-                return help;
-            }
         }
 
         ClientOptions options;
@@ -108,14 +95,13 @@
 
         public static void Run(string[] args)
         {
-            var options = new ClientOptions();
-            if (!Parser.Default.ParseArguments(args, options))
-            {
-                Environment.Exit(1);
-            }
-
-            var interopClient = new InteropClient(options);
-            interopClient.Run().Wait();
+            var parserResult = Parser.Default.ParseArguments<ClientOptions>(args)
+                .WithNotParsed(errors => Environment.Exit(1))
+                .WithParsed(options =>
+                {
+                    var interopClient = new InteropClient(options);
+                    interopClient.Run().Wait();
+                });
         }
 
         private async Task Run()
@@ -145,26 +131,16 @@
 
             if (options.TestCase == "jwt_token_creds")
             {
-#if !NETCOREAPP1_0
                 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
                 Assert.IsTrue(googleCredential.IsCreateScopedRequired);
                 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
-#else
-                // TODO(jtattermusch): implement this
-                throw new NotImplementedException("Not supported on CoreCLR yet");
-#endif
             }
 
             if (options.TestCase == "compute_engine_creds")
             {
-#if !NETCOREAPP1_0
                 var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
                 Assert.IsFalse(googleCredential.IsCreateScopedRequired);
                 credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
-#else
-                // TODO(jtattermusch): implement this
-                throw new NotImplementedException("Not supported on CoreCLR yet");
-#endif
             }
             return credentials;
         }
@@ -395,7 +371,6 @@
 
         public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
         {
-#if !NETCOREAPP1_0
             Console.WriteLine("running oauth2_auth_token");
             ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
             string oauth2Token = await credential.GetAccessTokenForRequestAsync();
@@ -413,15 +388,10 @@
             Assert.True(oauthScope.Contains(response.OauthScope));
             Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
             Console.WriteLine("Passed!");
-#else
-            // TODO(jtattermusch): implement this
-            throw new NotImplementedException("Not supported on CoreCLR yet");
-#endif
         }
 
         public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
         {
-#if !NETCOREAPP1_0
             Console.WriteLine("running per_rpc_creds");
             ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
 
@@ -435,10 +405,6 @@
 
             Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
             Console.WriteLine("Passed!");
-#else
-            // TODO(jtattermusch): implement this
-            throw new NotImplementedException("Not supported on CoreCLR yet");
-#endif
         }
 
         public static async Task RunCancelAfterBeginAsync(TestService.TestServiceClient client)
@@ -731,17 +697,12 @@
         // extracts the client_email field from service account file used for auth test cases
         private static string GetEmailFromServiceAccountFile()
         {
-#if !NETCOREAPP1_0
             string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
             Assert.IsNotNull(keyFile);
             var jobject = JObject.Parse(File.ReadAllText(keyFile));
             string email = jobject.GetValue("client_email").Value<string>();
             Assert.IsTrue(email.Length > 0);  // spec requires nonempty client email.
             return email;
-#else
-            // TODO(jtattermusch): implement this
-            throw new NotImplementedException("Not supported on CoreCLR yet");
-#endif
         }
 
         private static Metadata CreateTestMetadata()
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index cd47e31..4118f99 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -51,25 +51,12 @@
     {
         private class ServerOptions
         {
-            [Option("port", DefaultValue = 8070)]
+            [Option("port", Default = 8070)]
             public int Port { get; set; }
 
             // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
-            [Option("use_tls", DefaultValue = false)]
+            [Option("use_tls", Default = false)]
             public bool? UseTls { get; set; }
-
-            [HelpOption]
-            public string GetUsage()
-            {
-                var help = new HelpText
-                {
-                    Heading = "gRPC C# interop testing server",
-                    AddDashesToOption = true
-                };
-                help.AddPreOptionsLine("Usage:");
-                help.AddOptions(this);
-                return help;
-            }
         }
 
         ServerOptions options;
@@ -81,14 +68,13 @@
 
         public static void Run(string[] args)
         {
-            var options = new ServerOptions();
-            if (!Parser.Default.ParseArguments(args, options))
-            {
-                Environment.Exit(1);
-            }
-
-            var interopServer = new InteropServer(options);
-            interopServer.Run();
+            var parserResult = Parser.Default.ParseArguments<ServerOptions>(args)
+                .WithNotParsed(errors => Environment.Exit(1))
+                .WithParsed(options =>
+                {
+                    var interopServer = new InteropServer(options);
+                    interopServer.Run();
+                });
         }
 
         private void Run()
diff --git a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
index a7c9fa8..865556c 100644
--- a/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
+++ b/src/csharp/Grpc.IntegrationTesting/QpsWorker.cs
@@ -52,21 +52,8 @@
     {
         private class ServerOptions
         {
-            [Option("driver_port", DefaultValue = 0)]
+            [Option("driver_port", Default = 0)]
             public int DriverPort { get; set; }
-
-            [HelpOption]
-            public string GetUsage()
-            {
-                var help = new HelpText
-                {
-                    Heading = "gRPC C# performance testing worker",
-                    AddDashesToOption = true
-                };
-                help.AddPreOptionsLine("Usage:");
-                help.AddOptions(this);
-                return help;
-            }
         }
 
         ServerOptions options;
@@ -78,14 +65,13 @@
 
         public static void Run(string[] args)
         {
-            var options = new ServerOptions();
-            if (!Parser.Default.ParseArguments(args, options))
-            {
-                Environment.Exit(1);
-            }
-
-            var workerServer = new QpsWorker(options);
-            workerServer.RunAsync().Wait();
+            var parserResult = Parser.Default.ParseArguments<ServerOptions>(args)
+                .WithNotParsed((x) => Environment.Exit(1))
+                .WithParsed(options =>
+                {
+                    var workerServer = new QpsWorker(options);
+                    workerServer.RunAsync().Wait();
+                });
         }
 
         private async Task RunAsync()
diff --git a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
index 74ee040..750613b 100644
--- a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
@@ -54,36 +54,23 @@
 
         private class ClientOptions
         {
-            [Option("server_addresses", DefaultValue = "localhost:8080")]
+            [Option("server_addresses", Default = "localhost:8080")]
             public string ServerAddresses { get; set; }
 
-            [Option("test_cases", DefaultValue = "large_unary:100")]
+            [Option("test_cases", Default = "large_unary:100")]
             public string TestCases { get; set; }
 
-            [Option("test_duration_secs", DefaultValue = -1)]
+            [Option("test_duration_secs", Default = -1)]
             public int TestDurationSecs { get; set; }
 
-            [Option("num_channels_per_server", DefaultValue = 1)]
+            [Option("num_channels_per_server", Default = 1)]
             public int NumChannelsPerServer { get; set; }
 
-            [Option("num_stubs_per_channel", DefaultValue = 1)]
+            [Option("num_stubs_per_channel", Default = 1)]
             public int NumStubsPerChannel { get; set; }
 
-            [Option("metrics_port", DefaultValue = 8081)]
+            [Option("metrics_port", Default = 8081)]
             public int MetricsPort { get; set; }
-
-            [HelpOption]
-            public string GetUsage()
-            {
-                var help = new HelpText
-                {
-                    Heading = "gRPC C# stress test client",
-                    AddDashesToOption = true
-                };
-                help.AddPreOptionsLine("Usage:");
-                help.AddOptions(this);
-                return help;
-            }
         }
 
         ClientOptions options;
@@ -105,23 +92,21 @@
 
         public static void Run(string[] args)
         {
-            var options = new ClientOptions();
-            if (!Parser.Default.ParseArguments(args, options))
-            {
-                Environment.Exit(1);
-            }
+            var parserResult = Parser.Default.ParseArguments<ClientOptions>(args)
+                .WithNotParsed((x) => Environment.Exit(1))
+                .WithParsed(options => {
+                    GrpcPreconditions.CheckArgument(options.NumChannelsPerServer > 0);
+                    GrpcPreconditions.CheckArgument(options.NumStubsPerChannel > 0);
 
-            GrpcPreconditions.CheckArgument(options.NumChannelsPerServer > 0);
-            GrpcPreconditions.CheckArgument(options.NumStubsPerChannel > 0);
+                    var serverAddresses = options.ServerAddresses.Split(',');
+                    GrpcPreconditions.CheckArgument(serverAddresses.Length > 0, "You need to provide at least one server address");
 
-            var serverAddresses = options.ServerAddresses.Split(',');
-            GrpcPreconditions.CheckArgument(serverAddresses.Length > 0, "You need to provide at least one server address");
+                    var testCases = ParseWeightedTestCases(options.TestCases);
+                    GrpcPreconditions.CheckArgument(testCases.Count > 0, "You need to provide at least one test case");
 
-            var testCases = ParseWeightedTestCases(options.TestCases);
-            GrpcPreconditions.CheckArgument(testCases.Count > 0, "You need to provide at least one test case");
-
-            var interopClient = new StressTestClient(options, serverAddresses.ToList(), testCases);
-            interopClient.Run().Wait();
+                    var interopClient = new StressTestClient(options, serverAddresses.ToList(), testCases);
+                    interopClient.Run().Wait();
+                });
         }
 
         async Task Run()
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index e6e64e6..8bf9dd4 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
-  <package id="CommandLineParser" version="1.9.71" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.11.1" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.11.1" targetFramework="net45" />
+  <package id="CommandLineParser.Unofficial" version="2.0.275" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.15.0" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.15.0" targetFramework="net45" />
   <package id="Google.Protobuf" version="3.0.0-beta3" targetFramework="net45" />
   <package id="System.Interactive.Async" version="3.0.0" targetFramework="net45" />
   <package id="Moq" version="4.2.1510.2205" targetFramework="net45" />
diff --git a/src/csharp/Grpc.IntegrationTesting/project.json b/src/csharp/Grpc.IntegrationTesting/project.json
index bb61a67..9d70651 100644
--- a/src/csharp/Grpc.IntegrationTesting/project.json
+++ b/src/csharp/Grpc.IntegrationTesting/project.json
@@ -58,7 +58,7 @@
       "target": "project"
     },
     "Google.Protobuf": "3.0.0-beta3",
-    "CommandLineParser": "1.9.71",
+    "CommandLineParser.Unofficial": "2.0.275",
     "NUnit": "3.2.0",
     "NUnitLite": "3.2.0-*"
   },
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index f05c024..b92189c 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -31,10 +31,7 @@
 
 @rem Current package versions
 set VERSION=1.1.0-dev
-set PROTOBUF_VERSION=3.0.0-beta3
-
-@rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
-set VERSION_WITH_BETA=%VERSION%-beta
+set PROTOBUF_VERSION=3.0.0
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
@@ -58,7 +55,6 @@
 
 @rem Fetch all dependencies
 %NUGET% restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error
-%NUGET% restore Grpc.sln || goto :error
 
 setlocal
 
@@ -73,7 +69,7 @@
 
 %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
 %NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
-%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
+%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
 %NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
 %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
 
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
index 40e2760..e673359 100644
--- a/src/node/health_check/package.json
+++ b/src/node/health_check/package.json
@@ -15,9 +15,9 @@
     }
   ],
   "dependencies": {
-    "grpc": "^0.15.0",
+    "grpc": "^1.1.0-dev",
     "lodash": "^3.9.3",
-    "google-protobuf": "^3.0.0-alpha.5"
+    "google-protobuf": "^3.0.0"
   },
   "files": [
     "LICENSE",
diff --git a/src/node/tools/bin/protoc.js b/src/node/tools/bin/protoc.js
index 53fc5dc..7f83568 100755
--- a/src/node/tools/bin/protoc.js
+++ b/src/node/tools/bin/protoc.js
@@ -47,7 +47,11 @@
 
 var protoc = path.resolve(__dirname, 'protoc' + exe_ext);
 
-var child_process = execFile(protoc, process.argv.slice(2), function(error, stdout, stderr) {
+var plugin = path.resolve(__dirname, 'grpc_node_plugin' + exe_ext);
+
+var args = ['--plugin=protoc-gen-grpc=' + plugin].concat(process.argv.slice(2));
+
+var child_process = execFile(protoc, args, function(error, stdout, stderr) {
   if (error) {
     throw error;
   }
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
deleted file mode 100644
index 58abb49..0000000
--- a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/*
- * This test file is derived from fixture h2_ssl.c in core end2end test
- * (test/core/end2end/fixture/h2_ssl.c). The structure of the fixture is
- * preserved as much as possible
- *
- * This fixture creates a server full stack using chttp2 and a client
- * full stack using Cronet. End-to-end tests are run against this
- * configuration
- *
- */
-
-
-#import <XCTest/XCTest.h>
-#include "test/core/end2end/end2end_tests.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/support/env.h"
-#include "src/core/lib/support/string.h"
-#include "src/core/lib/support/tmpfile.h"
-#include "test/core/end2end/data/ssl_test_data.h"
-#include "test/core/util/port.h"
-#include "test/core/util/test_config.h"
-
-#include <grpc/grpc_cronet.h>
-#import <Cronet/Cronet.h>
-
-typedef struct fullstack_secure_fixture_data {
-  char *localaddr;
-} fullstack_secure_fixture_data;
-
-static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
-                                                                        grpc_channel_args *client_args, grpc_channel_args *server_args) {
-  grpc_end2end_test_fixture f;
-  int port = grpc_pick_unused_port_or_die();
-  fullstack_secure_fixture_data *ffd =
-  gpr_malloc(sizeof(fullstack_secure_fixture_data));
-  memset(&f, 0, sizeof(f));
-  
-  gpr_join_host_port(&ffd->localaddr, "localhost", port);
-  
-  f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
-  
-  return f;
-}
-
-static void process_auth_failure(void *state, grpc_auth_context *ctx,
-                                 const grpc_metadata *md, size_t md_count,
-                                 grpc_process_auth_metadata_done_cb cb,
-                                 void *user_data) {
-  GPR_ASSERT(state == NULL);
-  cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL);
-}
-
-static void cronet_init_client_secure_fullstack(
-                                                grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
-                                                cronet_engine *cronetEngine) {
-  fullstack_secure_fixture_data *ffd = f->fixture_data;
-  f->client =
-  grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr, client_args, NULL);
-  GPR_ASSERT(f->client != NULL);
-}
-
-static void chttp2_init_server_secure_fullstack(
-                                                grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
-                                                grpc_server_credentials *server_creds) {
-  fullstack_secure_fixture_data *ffd = f->fixture_data;
-  if (f->server) {
-    grpc_server_destroy(f->server);
-  }
-  f->server = grpc_server_create(server_args, NULL);
-  grpc_server_register_completion_queue(f->server, f->cq, NULL);
-  GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
-                                               server_creds));
-  grpc_server_credentials_release(server_creds);
-  grpc_server_start(f->server);
-}
-
-static void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
-  fullstack_secure_fixture_data *ffd = f->fixture_data;
-  gpr_free(ffd->localaddr);
-  gpr_free(ffd);
-}
-
-static void cronet_init_client_simple_ssl_secure_fullstack(
-                                                           grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
-  grpc_arg ssl_name_override = {GRPC_ARG_STRING,
-    GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
-    {"foo.test.google.fr"}};
-  
-  grpc_channel_args *new_client_args =
-  grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
-  [Cronet setHttp2Enabled:YES];
-  [Cronet start];
-  cronet_engine *cronetEngine = [Cronet getGlobalEngine];
-  
-  cronet_init_client_secure_fullstack(f, new_client_args, cronetEngine);
-  grpc_channel_args_destroy(new_client_args);
-}
-
-static int fail_server_auth_check(grpc_channel_args *server_args) {
-  size_t i;
-  if (server_args == NULL) return 0;
-  for (i = 0; i < server_args->num_args; i++) {
-    if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) ==
-        0) {
-      return 1;
-    }
-  }
-  return 0;
-}
-
-static void chttp2_init_server_simple_ssl_secure_fullstack(
-                                                           grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
-  grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
-    test_server1_cert};
-  grpc_server_credentials *ssl_creds =
-  grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL);
-  if (fail_server_auth_check(server_args)) {
-    grpc_auth_metadata_processor processor = {process_auth_failure, NULL, NULL};
-    grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor);
-  }
-  chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
-}
-
-/* All test configurations */
-
-static grpc_end2end_test_config configs[] = {
-  {"chttp2/simple_ssl_fullstack",
-    FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
-    FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS,
-    chttp2_create_fixture_secure_fullstack,
-    cronet_init_client_simple_ssl_secure_fullstack,
-    chttp2_init_server_simple_ssl_secure_fullstack,
-    chttp2_tear_down_secure_fullstack},
-};
-
-
-
-static char *roots_filename;
-
-@interface CoreCronetEnd2EndTests : XCTestCase
-
-@end
-
-@implementation CoreCronetEnd2EndTests
-
-
-// The setUp() function is run before the test cases run and only run once
-+ (void)setUp {
-  [super setUp];
-
-  FILE *roots_file;
-  size_t roots_size = strlen(test_root_cert);
-  
-  char *argv[] = {"CoreCronetEnd2EndTests"};
-  grpc_test_init(1, argv);
-  grpc_end2end_tests_pre_init();
-  
-  /* Set the SSL roots env var. */
-  roots_file = gpr_tmpfile("chttp2_simple_ssl_fullstack_test", &roots_filename);
-  GPR_ASSERT(roots_filename != NULL);
-  GPR_ASSERT(roots_file != NULL);
-  GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
-  fclose(roots_file);
-  gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
-  
-  grpc_init();
-  
-}
-
-// The tearDown() function is run after all test cases finish running
-+ (void)tearDown {
-  grpc_shutdown();
-  
-  /* Cleanup. */
-  remove(roots_filename);
-  gpr_free(roots_filename);
-  
-  [super tearDown];
-}
-
-- (void)testIndividualCase:(char*)test_case {
-  char *argv[] = {"h2_ssl", test_case};
-  
-  for (int i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
-    grpc_end2end_tests(sizeof(argv) / sizeof(argv[0]), argv, configs[i]);
-  }
-}
-
-// TODO(mxyan): Use NSStringFromSelector(_cmd) to acquire test name from the
-// test case method name, so that bodies of test cases can stay identical 
-- (void)testBadHostname {
-  [self testIndividualCase:"bad_hostname"];
-}
-
-- (void)testBinaryMetadata {
-  [self testIndividualCase:"binary_metadata"];
-}
-
-- (void)testCallCreds {
-  [self testIndividualCase:"call_creds"];
-}
-
-- (void)testCancelAfterAccept {
-  [self testIndividualCase:"cancel_after_accept"];
-}
-
-- (void)testCancelAfterClientDone {
-  [self testIndividualCase:"cancel_after_client_done"];
-}
-
-- (void)testCancelAfterInvoke {
-  [self testIndividualCase:"cancel_after_invoke"];
-}
-
-- (void)testCancelBeforeInvoke {
-  [self testIndividualCase:"cancel_before_invoke"];
-}
-
-- (void)testCancelInAVacuum {
-  [self testIndividualCase:"cancel_in_a_vacuum"];
-}
-
-- (void)testCancelWithStatus {
-  [self testIndividualCase:"cancel_with_status"];
-}
-
-- (void)testCompressedPayload {
-  [self testIndividualCase:"compressed_payload"];
-}
-
-- (void)testConnectivity {
-  [self testIndividualCase:"connectivity"];
-}
-
-- (void)testDefaultHost {
-  [self testIndividualCase:"default_host"];
-}
-
-- (void)testDisappearingServer {
-  [self testIndividualCase:"disappearing_server"];
-}
-
-- (void)testEmptyBatch {
-  [self testIndividualCase:"empty_batch"];
-}
-
-- (void)testFilterCausesClose {
-  [self testIndividualCase:"filter_causes_close"];
-}
-
-- (void)testGracefulServerShutdown {
-  [self testIndividualCase:"graceful_server_shutdown"];
-}
-
-- (void)testHighInitialSeqno {
-  [self testIndividualCase:"high_initial_seqno"];
-}
-
-- (void)testHpackSize {
-  [self testIndividualCase:"hpack_size"];
-}
-
-- (void)testIdempotentRequest {
-  [self testIndividualCase:"idempotent_request"];
-}
-
-- (void)testInvokeLargeRequest {
-  [self testIndividualCase:"invoke_large_request"];
-}
-
-- (void)testLargeMetadata {
-  [self testIndividualCase:"large_metadata"];
-}
-
-- (void)testMaxConcurrentStreams {
-  [self testIndividualCase:"max_concurrent_streams"];
-}
-
-- (void)testMaxMessageLength {
-  [self testIndividualCase:"max_message_length"];
-}
-
-- (void)testNegativeDeadline {
-  [self testIndividualCase:"negative_deadline"];
-}
-
-- (void)testNetworkStatusChange {
-  [self testIndividualCase:"network_status_change"];
-}
-
-- (void)testNoOp {
-  [self testIndividualCase:"no_op"];
-}
-
-- (void)testPayload {
-  [self testIndividualCase:"payload"];
-}
-
-- (void)testPing {
-  [self testIndividualCase:"ping"];
-}
-
-- (void)testPingPongStreaming {
-  [self testIndividualCase:"ping_pong_streaming"];
-}
-
-- (void)testRegisteredCall {
-  [self testIndividualCase:"registered_call"];
-}
-
-- (void)testRequestWithFlags {
-  [self testIndividualCase:"request_with_flags"];
-}
-
-- (void)testRequestWithPayload {
-  [self testIndividualCase:"request_with_payload"];
-}
-
-- (void)testServerFinishesRequest {
-  [self testIndividualCase:"server_finishes_request"];
-}
-
-- (void)testShutdownFinishesCalls {
-  [self testIndividualCase:"shutdown_finishes_calls"];
-}
-
-- (void)testShutdownFinishesTags {
-  [self testIndividualCase:"shutdown_finishes_tags"];
-}
-
-- (void)testSimpleDelayedRequest {
-  [self testIndividualCase:"simple_delayed_request"];
-}
-
-- (void)testSimpleMetadata {
-  [self testIndividualCase:"simple_metadata"];
-}
-
-- (void)testSimpleRequest {
-  [self testIndividualCase:"simple_request"];
-}
-
-- (void)testStreamingErrorResponse {
-  [self testIndividualCase:"streaming_error_response"];
-}
-
-- (void)testTrailingMetadata {
-  [self testIndividualCase:"trailing_metadata"];
-}
-
-@end
diff --git a/src/php/ext/grpc/php7_wrapper.h b/src/php/ext/grpc/php7_wrapper.h
index fd8d356..1d78241 100644
--- a/src/php/ext/grpc/php7_wrapper.h
+++ b/src/php/ext/grpc/php7_wrapper.h
@@ -143,8 +143,7 @@
 
 #define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val)
 #define PHP_GRPC_MAKE_STD_ZVAL(pzv) \
-  zval _stack_zval_##pzv; \
-  pzv = &(_stack_zval_##pzv)
+  pzv = (zval *)emalloc(sizeof(zval));
 #define PHP_GRPC_DELREF(zv)
 
 #define PHP_GRPC_WRAP_OBJECT_START(name) \
diff --git a/src/python/grpcio_tests/tests/interop/_insecure_interop_test.py b/src/python/grpcio_tests/tests/interop/_insecure_interop_test.py
index c753d6f..936c895 100644
--- a/src/python/grpcio_tests/tests/interop/_insecure_interop_test.py
+++ b/src/python/grpcio_tests/tests/interop/_insecure_interop_test.py
@@ -29,9 +29,10 @@
 
 """Insecure client-server interoperability as a unit test."""
 
+from concurrent import futures
 import unittest
 
-from grpc.beta import implementations
+import grpc
 from src.proto.grpc.testing import test_pb2
 
 from tests.interop import _interop_test_case
@@ -44,14 +45,13 @@
     unittest.TestCase):
 
   def setUp(self):
-    self.server = test_pb2.beta_create_TestService_server(methods.TestService())
+    self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+    test_pb2.add_TestServiceServicer_to_server(
+        methods.TestService(), self.server)
     port = self.server.add_insecure_port('[::]:0')
     self.server.start()
-    self.stub = test_pb2.beta_create_TestService_stub(
-        implementations.insecure_channel('localhost', port))
-
-  def tearDown(self):
-    self.server.stop(0)
+    self.stub = test_pb2.TestServiceStub(
+        grpc.insecure_channel('localhost:{}'.format(port)))
 
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_tests/tests/interop/_secure_interop_test.py b/src/python/grpcio_tests/tests/interop/_secure_interop_test.py
index cb09f54..eaca553 100644
--- a/src/python/grpcio_tests/tests/interop/_secure_interop_test.py
+++ b/src/python/grpcio_tests/tests/interop/_secure_interop_test.py
@@ -29,17 +29,16 @@
 
 """Secure client-server interoperability as a unit test."""
 
+from concurrent import futures
 import unittest
 
-from grpc.beta import implementations
+import grpc
 from src.proto.grpc.testing import test_pb2
 
 from tests.interop import _interop_test_case
 from tests.interop import methods
 from tests.interop import resources
 
-from tests.unit.beta import test_utilities
-
 _SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
 
 
@@ -48,19 +47,18 @@
     unittest.TestCase):
 
   def setUp(self):
-    self.server = test_pb2.beta_create_TestService_server(methods.TestService())
+    self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+    test_pb2.add_TestServiceServicer_to_server(
+        methods.TestService(), self.server)
     port = self.server.add_secure_port(
-        '[::]:0', implementations.ssl_server_credentials(
+        '[::]:0', grpc.ssl_server_credentials(
             [(resources.private_key(), resources.certificate_chain())]))
     self.server.start()
-    self.stub = test_pb2.beta_create_TestService_stub(
-        test_utilities.not_really_secure_channel(
-            'localhost', port, implementations.ssl_channel_credentials(
-                resources.test_root_certificates()),
-                _SERVER_HOST_OVERRIDE))
-
-  def tearDown(self):
-    self.server.stop(0)
+    self.stub = test_pb2.TestServiceStub(
+        grpc.secure_channel(
+            'localhost:{}'.format(port),
+            grpc.ssl_channel_credentials(resources.test_root_certificates()),
+            (('grpc.ssl_target_name_override', _SERVER_HOST_OVERRIDE,),)))
 
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_tests/tests/interop/client.py b/src/python/grpcio_tests/tests/interop/client.py
index 8aa1ce3..9d61d18 100644
--- a/src/python/grpcio_tests/tests/interop/client.py
+++ b/src/python/grpcio_tests/tests/interop/client.py
@@ -32,14 +32,12 @@
 import argparse
 from oauth2client import client as oauth2client_client
 
+import grpc
 from grpc.beta import implementations
 from src.proto.grpc.testing import test_pb2
 
 from tests.interop import methods
 from tests.interop import resources
-from tests.unit.beta import test_utilities
-
-_ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
 
 def _args():
@@ -66,41 +64,49 @@
   return parser.parse_args()
 
 
+def _application_default_credentials():
+  return oauth2client_client.GoogleCredentials.get_application_default()
+
+
 def _stub(args):
+  target = '{}:{}'.format(args.server_host, args.server_port)
   if args.test_case == 'oauth2_auth_token':
-    creds = oauth2client_client.GoogleCredentials.get_application_default()
-    scoped_creds = creds.create_scoped([args.oauth_scope])
-    access_token = scoped_creds.get_access_token().access_token
-    call_creds = implementations.access_token_call_credentials(access_token)
+    google_credentials = _application_default_credentials()
+    scoped_credentials = google_credentials.create_scoped([args.oauth_scope])
+    access_token = scoped_credentials.get_access_token().access_token
+    call_credentials = grpc.access_token_call_credentials(access_token)
   elif args.test_case == 'compute_engine_creds':
-    creds = oauth2client_client.GoogleCredentials.get_application_default()
-    scoped_creds = creds.create_scoped([args.oauth_scope])
-    call_creds = implementations.google_call_credentials(scoped_creds)
+    google_credentials = _application_default_credentials()
+    scoped_credentials = google_credentials.create_scoped([args.oauth_scope])
+    # TODO(https://github.com/grpc/grpc/issues/6799): Eliminate this last
+    # remaining use of the Beta API.
+    call_credentials = implementations.google_call_credentials(
+        scoped_credentials)
   elif args.test_case == 'jwt_token_creds':
-    creds = oauth2client_client.GoogleCredentials.get_application_default()
-    call_creds = implementations.google_call_credentials(creds)
+    google_credentials = _application_default_credentials()
+    # TODO(https://github.com/grpc/grpc/issues/6799): Eliminate this last
+    # remaining use of the Beta API.
+    call_credentials = implementations.google_call_credentials(
+        google_credentials)
   else:
-    call_creds = None
+    call_credentials = None
   if args.use_tls:
     if args.use_test_ca:
       root_certificates = resources.test_root_certificates()
     else:
       root_certificates = None  # will load default roots.
 
-    channel_creds = implementations.ssl_channel_credentials(root_certificates)
-    if call_creds is not None:
-      channel_creds = implementations.composite_channel_credentials(
-          channel_creds, call_creds)
+    channel_credentials = grpc.ssl_channel_credentials(root_certificates)
+    if call_credentials is not None:
+      channel_credentials = grpc.composite_channel_credentials(
+          channel_credentials, call_credentials)
 
-    channel = test_utilities.not_really_secure_channel(
-        args.server_host, args.server_port, channel_creds,
-        args.server_host_override)
-    stub = test_pb2.beta_create_TestService_stub(channel)
+    channel = grpc.secure_channel(
+        target, channel_credentials,
+        (('grpc.ssl_target_name_override', args.server_host_override,),))
   else:
-    channel = implementations.insecure_channel(
-        args.server_host, args.server_port)
-    stub = test_pb2.beta_create_TestService_stub(channel)
-  return stub
+    channel = grpc.insecure_channel(target)
+  return test_pb2.TestServiceStub(channel)
 
 
 def _test_case_from_arg(test_case_arg):
diff --git a/src/python/grpcio_tests/tests/interop/methods.py b/src/python/grpcio_tests/tests/interop/methods.py
index 97e6c9e..7edd75c 100644
--- a/src/python/grpcio_tests/tests/interop/methods.py
+++ b/src/python/grpcio_tests/tests/interop/methods.py
@@ -29,8 +29,6 @@
 
 """Implementations of interoperability test methods."""
 
-from __future__ import print_function
-
 import enum
 import json
 import os
@@ -41,26 +39,21 @@
 
 import grpc
 from grpc.beta import implementations
-from grpc.beta import interfaces
-from grpc.framework.common import cardinality
-from grpc.framework.interfaces.face import face
 
 from src.proto.grpc.testing import empty_pb2
 from src.proto.grpc.testing import messages_pb2
 from src.proto.grpc.testing import test_pb2
 
-_TIMEOUT = 7
 
-
-class TestService(test_pb2.BetaTestServiceServicer):
+class TestService(test_pb2.TestServiceServicer):
 
   def EmptyCall(self, request, context):
     return empty_pb2.Empty()
 
   def UnaryCall(self, request, context):
     if request.HasField('response_status'):
-      context.code(request.response_status.code)
-      context.details(request.response_status.message)
+      context.set_code(request.response_status.code)
+      context.set_details(request.response_status.message)
     return messages_pb2.SimpleResponse(
         payload=messages_pb2.Payload(
             type=messages_pb2.COMPRESSABLE,
@@ -68,8 +61,8 @@
 
   def StreamingOutputCall(self, request, context):
     if request.HasField('response_status'):
-      context.code(request.response_status.code)
-      context.details(request.response_status.message)
+      context.set_code(request.response_status.code)
+      context.set_details(request.response_status.message)
     for response_parameters in request.response_parameters:
       yield messages_pb2.StreamingOutputCallResponse(
           payload=messages_pb2.Payload(
@@ -79,7 +72,7 @@
   def StreamingInputCall(self, request_iterator, context):
     aggregate_size = 0
     for request in request_iterator:
-      if request.payload and request.payload.body:
+      if request.payload is not None and request.payload.body:
         aggregate_size += len(request.payload.body)
     return messages_pb2.StreamingInputCallResponse(
         aggregated_payload_size=aggregate_size)
@@ -87,8 +80,8 @@
   def FullDuplexCall(self, request_iterator, context):
     for request in request_iterator:
       if request.HasField('response_status'):
-        context.code(request.response_status.code)
-        context.details(request.response_status.message)
+        context.set_code(request.response_status.code)
+        context.set_details(request.response_status.message)
       for response_parameters in request.response_parameters:
         yield messages_pb2.StreamingOutputCallResponse(
             payload=messages_pb2.Payload(
@@ -101,83 +94,80 @@
     return self.FullDuplexCall(request_iterator, context)
 
 
-def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope,
-                                 protocol_options=None):
-  with stub:
-    request = messages_pb2.SimpleRequest(
-        response_type=messages_pb2.COMPRESSABLE, response_size=314159,
-        payload=messages_pb2.Payload(body=b'\x00' * 271828),
-        fill_username=fill_username, fill_oauth_scope=fill_oauth_scope)
-    response_future = stub.UnaryCall.future(request, _TIMEOUT,
-                                            protocol_options=protocol_options)
-    response = response_future.result()
-    if response.payload.type is not messages_pb2.COMPRESSABLE:
-      raise ValueError(
-          'response payload type is "%s"!' % type(response.payload.type))
-    if len(response.payload.body) != 314159:
-      raise ValueError(
-          'response body of incorrect size %d!' % len(response.payload.body))
+def _large_unary_common_behavior(
+    stub, fill_username, fill_oauth_scope, call_credentials):
+  request = messages_pb2.SimpleRequest(
+      response_type=messages_pb2.COMPRESSABLE, response_size=314159,
+      payload=messages_pb2.Payload(body=b'\x00' * 271828),
+      fill_username=fill_username, fill_oauth_scope=fill_oauth_scope)
+  response_future = stub.UnaryCall.future(
+      request, credentials=call_credentials)
+  response = response_future.result()
+  if response.payload.type is not messages_pb2.COMPRESSABLE:
+    raise ValueError(
+        'response payload type is "%s"!' % type(response.payload.type))
+  elif len(response.payload.body) != 314159:
+    raise ValueError(
+        'response body of incorrect size %d!' % len(response.payload.body))
+  else:
     return response
 
 
 def _empty_unary(stub):
-  with stub:
-    response = stub.EmptyCall(empty_pb2.Empty(), _TIMEOUT)
-    if not isinstance(response, empty_pb2.Empty):
-      raise TypeError(
-          'response is of type "%s", not empty_pb2.Empty!', type(response))
+  response = stub.EmptyCall(empty_pb2.Empty())
+  if not isinstance(response, empty_pb2.Empty):
+    raise TypeError(
+        'response is of type "%s", not empty_pb2.Empty!', type(response))
 
 
 def _large_unary(stub):
-  _large_unary_common_behavior(stub, False, False)
+  _large_unary_common_behavior(stub, False, False, None)
 
 
 def _client_streaming(stub):
-  with stub:
-    payload_body_sizes = (27182, 8, 1828, 45904)
-    payloads = (
-        messages_pb2.Payload(body=b'\x00' * size)
-        for size in payload_body_sizes)
-    requests = (
-        messages_pb2.StreamingInputCallRequest(payload=payload)
-        for payload in payloads)
-    response = stub.StreamingInputCall(requests, _TIMEOUT)
-    if response.aggregated_payload_size != 74922:
-      raise ValueError(
-          'incorrect size %d!' % response.aggregated_payload_size)
+  payload_body_sizes = (27182, 8, 1828, 45904,)
+  payloads = (
+      messages_pb2.Payload(body=b'\x00' * size)
+      for size in payload_body_sizes)
+  requests = (
+      messages_pb2.StreamingInputCallRequest(payload=payload)
+      for payload in payloads)
+  response = stub.StreamingInputCall(requests)
+  if response.aggregated_payload_size != 74922:
+    raise ValueError(
+        'incorrect size %d!' % response.aggregated_payload_size)
 
 
 def _server_streaming(stub):
-  sizes = (31415, 9, 2653, 58979)
+  sizes = (31415, 9, 2653, 58979,)
 
-  with stub:
-    request = messages_pb2.StreamingOutputCallRequest(
-        response_type=messages_pb2.COMPRESSABLE,
-        response_parameters=(
-            messages_pb2.ResponseParameters(size=sizes[0]),
-            messages_pb2.ResponseParameters(size=sizes[1]),
-            messages_pb2.ResponseParameters(size=sizes[2]),
-            messages_pb2.ResponseParameters(size=sizes[3]),
-        ))
-    response_iterator = stub.StreamingOutputCall(request, _TIMEOUT)
-    for index, response in enumerate(response_iterator):
-      if response.payload.type != messages_pb2.COMPRESSABLE:
-        raise ValueError(
-            'response body of invalid type %s!' % response.payload.type)
-      if len(response.payload.body) != sizes[index]:
-        raise ValueError(
-            'response body of invalid size %d!' % len(response.payload.body))
+  request = messages_pb2.StreamingOutputCallRequest(
+      response_type=messages_pb2.COMPRESSABLE,
+      response_parameters=(
+          messages_pb2.ResponseParameters(size=sizes[0]),
+          messages_pb2.ResponseParameters(size=sizes[1]),
+          messages_pb2.ResponseParameters(size=sizes[2]),
+          messages_pb2.ResponseParameters(size=sizes[3]),
+      )
+  )
+  response_iterator = stub.StreamingOutputCall(request)
+  for index, response in enumerate(response_iterator):
+    if response.payload.type != messages_pb2.COMPRESSABLE:
+      raise ValueError(
+          'response body of invalid type %s!' % response.payload.type)
+    elif len(response.payload.body) != sizes[index]:
+      raise ValueError(
+          'response body of invalid size %d!' % len(response.payload.body))
 
 def _cancel_after_begin(stub):
-  with stub:
-    sizes = (27182, 8, 1828, 45904)
-    payloads = [messages_pb2.Payload(body=b'\x00' * size) for size in sizes]
-    requests = [messages_pb2.StreamingInputCallRequest(payload=payload)
-                for payload in payloads]
-    responses = stub.StreamingInputCall.future(requests, _TIMEOUT)
-    responses.cancel()
-    if not responses.cancelled():
-      raise ValueError('expected call to be cancelled')
+  sizes = (27182, 8, 1828, 45904,)
+  payloads = (messages_pb2.Payload(body=b'\x00' * size) for size in sizes)
+  requests = (messages_pb2.StreamingInputCallRequest(payload=payload)
+              for payload in payloads)
+  response_future = stub.StreamingInputCall.future(requests)
+  response_future.cancel()
+  if not response_future.cancelled():
+    raise ValueError('expected call to be cancelled')
 
 
 class _Pipe(object):
@@ -220,18 +210,17 @@
 
 
 def _ping_pong(stub):
-  request_response_sizes = (31415, 9, 2653, 58979)
-  request_payload_sizes = (27182, 8, 1828, 45904)
+  request_response_sizes = (31415, 9, 2653, 58979,)
+  request_payload_sizes = (27182, 8, 1828, 45904,)
 
-  with stub, _Pipe() as pipe:
-    response_iterator = stub.FullDuplexCall(pipe, _TIMEOUT)
-    print('Starting ping-pong with response iterator %s' % response_iterator)
+  with _Pipe() as pipe:
+    response_iterator = stub.FullDuplexCall(pipe)
     for response_size, payload_size in zip(
         request_response_sizes, request_payload_sizes):
       request = messages_pb2.StreamingOutputCallRequest(
           response_type=messages_pb2.COMPRESSABLE,
-          response_parameters=(messages_pb2.ResponseParameters(
-              size=response_size),),
+          response_parameters=(
+              messages_pb2.ResponseParameters(size=response_size),),
           payload=messages_pb2.Payload(body=b'\x00' * payload_size))
       pipe.add(request)
       response = next(response_iterator)
@@ -244,17 +233,17 @@
 
 
 def _cancel_after_first_response(stub):
-  request_response_sizes = (31415, 9, 2653, 58979)
-  request_payload_sizes = (27182, 8, 1828, 45904)
-  with stub, _Pipe() as pipe:
-    response_iterator = stub.FullDuplexCall(pipe, _TIMEOUT)
+  request_response_sizes = (31415, 9, 2653, 58979,)
+  request_payload_sizes = (27182, 8, 1828, 45904,)
+  with _Pipe() as pipe:
+    response_iterator = stub.FullDuplexCall(pipe)
 
     response_size = request_response_sizes[0]
     payload_size = request_payload_sizes[0]
     request = messages_pb2.StreamingOutputCallRequest(
         response_type=messages_pb2.COMPRESSABLE,
-        response_parameters=(messages_pb2.ResponseParameters(
-            size=response_size),),
+        response_parameters=(
+            messages_pb2.ResponseParameters(size=response_size),),
         payload=messages_pb2.Payload(body=b'\x00' * payload_size))
     pipe.add(request)
     response = next(response_iterator)
@@ -264,16 +253,17 @@
 
     try:
       next(response_iterator)
-    except Exception:
-      pass
+    except grpc.RpcError as rpc_error:
+      if rpc_error.code() is not grpc.StatusCode.CANCELLED:
+        raise
     else:
       raise ValueError('expected call to be cancelled')
 
 
 def _timeout_on_sleeping_server(stub):
   request_payload_size = 27182
-  with stub, _Pipe() as pipe:
-    response_iterator = stub.FullDuplexCall(pipe, 0.001)
+  with _Pipe() as pipe:
+    response_iterator = stub.FullDuplexCall(pipe, timeout=0.001)
 
     request = messages_pb2.StreamingOutputCallRequest(
         response_type=messages_pb2.COMPRESSABLE,
@@ -282,15 +272,16 @@
     time.sleep(0.1)
     try:
       next(response_iterator)
-    except face.ExpirationError:
-      pass
+    except grpc.RpcError as rpc_error:
+      if rpc_error.code() is not grpc.StatusCode.DEADLINE_EXCEEDED:
+        raise
     else:
       raise ValueError('expected call to exceed deadline')
 
 
 def _empty_stream(stub):
-  with stub, _Pipe() as pipe:
-    response_iterator = stub.FullDuplexCall(pipe, _TIMEOUT)
+  with _Pipe() as pipe:
+    response_iterator = stub.FullDuplexCall(pipe)
     pipe.close()
     try:
       next(response_iterator)
@@ -300,65 +291,64 @@
 
 
 def _status_code_and_message(stub):
-  with stub:
-    message = 'test status message'
-    code = 2
-    status = grpc.StatusCode.UNKNOWN # code = 2
-    request = messages_pb2.SimpleRequest(
-        response_type=messages_pb2.COMPRESSABLE,
-        response_size=1,
-        payload=messages_pb2.Payload(body=b'\x00'),
-        response_status=messages_pb2.EchoStatus(code=code, message=message)
-        )
-    response_future = stub.UnaryCall.future(request, _TIMEOUT)
-    if response_future.code() != status:
-      raise ValueError(
-        'expected code %s, got %s' % (status, response_future.code()))
-    if response_future.details() != message:
-      raise ValueError(
-        'expected message %s, got %s' % (message, response_future.details()))
+  message = 'test status message'
+  code = 2
+  status = grpc.StatusCode.UNKNOWN # code = 2
+  request = messages_pb2.SimpleRequest(
+      response_type=messages_pb2.COMPRESSABLE,
+      response_size=1,
+      payload=messages_pb2.Payload(body=b'\x00'),
+      response_status=messages_pb2.EchoStatus(code=code, message=message)
+  )
+  response_future = stub.UnaryCall.future(request)
+  if response_future.code() != status:
+    raise ValueError(
+      'expected code %s, got %s' % (status, response_future.code()))
+  elif response_future.details() != message:
+    raise ValueError(
+      'expected message %s, got %s' % (message, response_future.details()))
 
-    request = messages_pb2.StreamingOutputCallRequest(
-        response_type=messages_pb2.COMPRESSABLE,
-        response_parameters=(
-            messages_pb2.ResponseParameters(size=1),),
-        response_status=messages_pb2.EchoStatus(code=code, message=message))
-    response_iterator = stub.StreamingOutputCall(request, _TIMEOUT)
-    if response_future.code() != status:
-      raise ValueError(
-        'expected code %s, got %s' % (status, response_iterator.code()))
-    if response_future.details() != message:
-      raise ValueError(
-        'expected message %s, got %s' % (message, response_iterator.details()))
+  request = messages_pb2.StreamingOutputCallRequest(
+      response_type=messages_pb2.COMPRESSABLE,
+      response_parameters=(
+          messages_pb2.ResponseParameters(size=1),),
+      response_status=messages_pb2.EchoStatus(code=code, message=message))
+  response_iterator = stub.StreamingOutputCall(request)
+  if response_future.code() != status:
+    raise ValueError(
+      'expected code %s, got %s' % (status, response_iterator.code()))
+  elif response_future.details() != message:
+    raise ValueError(
+      'expected message %s, got %s' % (message, response_iterator.details()))
 
 
 def _compute_engine_creds(stub, args):
-  response = _large_unary_common_behavior(stub, True, True)
+  response = _large_unary_common_behavior(stub, True, True, None)
   if args.default_service_account != response.username:
     raise ValueError(
-        'expected username %s, got %s' % (args.default_service_account,
-                                          response.username))
+        'expected username %s, got %s' % (
+            args.default_service_account, response.username))
 
 
 def _oauth2_auth_token(stub, args):
   json_key_filename = os.environ[
       oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
   wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
-  response = _large_unary_common_behavior(stub, True, True)
+  response = _large_unary_common_behavior(stub, True, True, None)
   if wanted_email != response.username:
     raise ValueError(
         'expected username %s, got %s' % (wanted_email, response.username))
   if args.oauth_scope.find(response.oauth_scope) == -1:
     raise ValueError(
-        'expected to find oauth scope "%s" in received "%s"' %
-        (response.oauth_scope, args.oauth_scope))
+        'expected to find oauth scope "{}" in received "{}"'.format(
+            response.oauth_scope, args.oauth_scope))
 
 
 def _jwt_token_creds(stub, args):
   json_key_filename = os.environ[
       oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
   wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
-  response = _large_unary_common_behavior(stub, True, False)
+  response = _large_unary_common_behavior(stub, True, False, None)
   if wanted_email != response.username:
     raise ValueError(
         'expected username %s, got %s' % (wanted_email, response.username))
@@ -370,11 +360,11 @@
   wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
   credentials = oauth2client_client.GoogleCredentials.get_application_default()
   scoped_credentials = credentials.create_scoped([args.oauth_scope])
-  call_creds = implementations.google_call_credentials(scoped_credentials)
-  options = interfaces.grpc_call_options(disable_compression=False,
-                                         credentials=call_creds)
-  response = _large_unary_common_behavior(stub, True, False,
-                                          protocol_options=options)
+  # TODO(https://github.com/grpc/grpc/issues/6799): Eliminate this last
+  # remaining use of the Beta API.
+  call_credentials = implementations.google_call_credentials(
+      scoped_credentials)
+  response = _large_unary_common_behavior(stub, True, False, call_credentials)
   if wanted_email != response.username:
     raise ValueError(
         'expected username %s, got %s' % (wanted_email, response.username))
diff --git a/src/python/grpcio_tests/tests/interop/server.py b/src/python/grpcio_tests/tests/interop/server.py
index ab2c3c7..1ae83bc 100644
--- a/src/python/grpcio_tests/tests/interop/server.py
+++ b/src/python/grpcio_tests/tests/interop/server.py
@@ -30,10 +30,11 @@
 """The Python implementation of the GRPC interoperability test server."""
 
 import argparse
+from concurrent import futures
 import logging
 import time
 
-from grpc.beta import implementations
+import grpc
 from src.proto.grpc.testing import test_pb2
 
 from tests.interop import methods
@@ -51,12 +52,13 @@
       default=False, type=resources.parse_bool)
   args = parser.parse_args()
 
-  server = test_pb2.beta_create_TestService_server(methods.TestService())
+  server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+  test_pb2.add_TestServiceServicer_to_server(methods.TestService(), server)
   if args.use_tls:
     private_key = resources.private_key()
     certificate_chain = resources.certificate_chain()
-    credentials = implementations.ssl_server_credentials(
-        [(private_key, certificate_chain)])
+    credentials = grpc.ssl_server_credentials(
+        ((private_key, certificate_chain),))
     server.add_secure_port('[::]:{}'.format(args.port), credentials)
   else:
     server.add_insecure_port('[::]:{}'.format(args.port))
@@ -68,7 +70,7 @@
       time.sleep(_ONE_DAY_IN_SECONDS)
   except BaseException as e:
     logging.info('Caught exception "%s"; stopping server...', e)
-    server.stop(0)
+    server.stop(None)
     logging.info('Server stopped; exiting.')
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_tests/tests/stress/client.py b/src/python/grpcio_tests/tests/stress/client.py
index 0de2532..975f33b 100644
--- a/src/python/grpcio_tests/tests/stress/client.py
+++ b/src/python/grpcio_tests/tests/stress/client.py
@@ -30,9 +30,10 @@
 """Entry point for running stress tests."""
 
 import argparse
+from concurrent import futures
 import threading
 
-from grpc.beta import implementations
+import grpc
 from six.moves import queue
 from src.proto.grpc.testing import metrics_pb2
 from src.proto.grpc.testing import test_pb2
@@ -92,24 +93,24 @@
 
 def run_test(args):
   test_cases = _parse_weighted_test_cases(args.test_cases)
-  test_servers = args.server_addresses.split(',')
+  test_server_targets = args.server_addresses.split(',')
   # Propagate any client exceptions with a queue
   exception_queue = queue.Queue()
   stop_event = threading.Event()
   hist = histogram.Histogram(1, 1)
   runners = []
 
-  server = metrics_pb2.beta_create_MetricsService_server(
-      metrics_server.MetricsServer(hist))
+  server = grpc.server(futures.ThreadPoolExecutor(max_workers=25))
+  metrics_pb2.add_MetricsServiceServicer_to_server(
+      metrics_server.MetricsServer(hist), server)
   server.add_insecure_port('[::]:{}'.format(args.metrics_port))
   server.start()
 
-  for test_server in test_servers:
-    host, port = test_server.split(':', 1)
+  for test_server_target in test_server_targets:
     for _ in xrange(args.num_channels_per_server):
-      channel = implementations.insecure_channel(host, int(port))
+      channel = grpc.insecure_channel(test_server_target)
       for _ in xrange(args.num_stubs_per_channel):
-        stub = test_pb2.beta_create_TestService_stub(channel)
+        stub = test_pb2.TestServiceStub(channel)
         runner = test_runner.TestRunner(stub, test_cases, hist,
                                         exception_queue, stop_event)
         runners.append(runner)
@@ -128,8 +129,8 @@
     stop_event.set()
     for runner in runners:
       runner.join()
-      runner = None
-    server.stop(0)
+    runner = None
+    server.stop(None)
 
 if __name__ == '__main__':
   run_test(_args())
diff --git a/src/python/grpcio_tests/tests/stress/metrics_server.py b/src/python/grpcio_tests/tests/stress/metrics_server.py
index b994e46..33dd1d6 100644
--- a/src/python/grpcio_tests/tests/stress/metrics_server.py
+++ b/src/python/grpcio_tests/tests/stress/metrics_server.py
@@ -36,7 +36,7 @@
 GAUGE_NAME = 'python_overall_qps'
 
 
-class MetricsServer(metrics_pb2.BetaMetricsServiceServicer):
+class MetricsServer(metrics_pb2.MetricsServiceServicer):
 
   def __init__(self, histogram):
     self._start_time = time.time()
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 196f84f..d7cd9e6 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -62,7 +62,6 @@
       @call = call
       @marshal = marshal
       @op_notifier = nil  # signals completion on clients
-      @readq = Queue.new
       @unmarshal = unmarshal
       @metadata_received = metadata_received
       @reads_complete = false
@@ -83,8 +82,7 @@
     def run_on_client(requests, op_notifier, &blk)
       @op_notifier = op_notifier
       @enq_th = Thread.new { write_loop(requests) }
-      @loop_th = start_read_loop
-      each_queued_msg(&blk)
+      read_loop(&blk)
     end
 
     # Begins orchestration of the Bidi stream for a server generating replies.
@@ -101,14 +99,13 @@
     def run_on_server(gen_each_reply)
       # Pass in the optional call object parameter if possible
       if gen_each_reply.arity == 1
-        replys = gen_each_reply.call(each_queued_msg)
+        replys = gen_each_reply.call(read_loop(is_client: false))
       elsif gen_each_reply.arity == 2
-        replys = gen_each_reply.call(each_queued_msg, @req_view)
+        replys = gen_each_reply.call(read_loop(is_client: false), @req_view)
       else
         fail 'Illegal arity of reply generator'
       end
 
-      @loop_th = start_read_loop(is_client: false)
       write_loop(replys, is_client: false)
     end
 
@@ -145,24 +142,6 @@
       batch_result
     end
 
-    # each_queued_msg yields each message on this instances readq
-    #
-    # - messages are added to the readq by #read_loop
-    # - iteration ends when the instance itself is added
-    def each_queued_msg
-      return enum_for(:each_queued_msg) unless block_given?
-      count = 0
-      loop do
-        GRPC.logger.debug("each_queued_msg: waiting##{count}")
-        count += 1
-        req = @readq.pop
-        GRPC.logger.debug("each_queued_msg: req = #{req}")
-        fail req if req.is_a? StandardError
-        break if req.equal?(END_OF_READS)
-        yield req
-      end
-    end
-
     def write_loop(requests, is_client: true)
       GRPC.logger.debug('bidi-write-loop: starting')
       count = 0
@@ -201,47 +180,45 @@
       raise e
     end
 
-    # starts the read loop
-    def start_read_loop(is_client: true)
-      Thread.new do
-        GRPC.logger.debug('bidi-read-loop: starting')
-        begin
-          count = 0
-          # queue the initial read before beginning the loop
-          loop do
-            GRPC.logger.debug("bidi-read-loop: #{count}")
-            count += 1
-            batch_result = read_using_run_batch
+    # Provides an enumerator that yields results of remote reads
+    def read_loop(is_client: true)
+      return enum_for(:read_loop,
+                      is_client: is_client) unless block_given?
+      GRPC.logger.debug('bidi-read-loop: starting')
+      begin
+        count = 0
+        # queue the initial read before beginning the loop
+        loop do
+          GRPC.logger.debug("bidi-read-loop: #{count}")
+          count += 1
+          batch_result = read_using_run_batch
 
-            # handle the next message
-            if batch_result.message.nil?
-              GRPC.logger.debug("bidi-read-loop: null batch #{batch_result}")
+          # handle the next message
+          if batch_result.message.nil?
+            GRPC.logger.debug("bidi-read-loop: null batch #{batch_result}")
 
-              if is_client
-                batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil)
-                @call.status = batch_result.status
-                batch_result.check_status
-                GRPC.logger.debug("bidi-read-loop: done status #{@call.status}")
-              end
-
-              @readq.push(END_OF_READS)
-              GRPC.logger.debug('bidi-read-loop: done reading!')
-              break
+            if is_client
+              batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil)
+              @call.status = batch_result.status
+              batch_result.check_status
+              GRPC.logger.debug("bidi-read-loop: done status #{@call.status}")
             end
 
-            # push the latest read onto the queue and continue reading
-            res = @unmarshal.call(batch_result.message)
-            @readq.push(res)
+            GRPC.logger.debug('bidi-read-loop: done reading!')
+            break
           end
-        rescue StandardError => e
-          GRPC.logger.warn('bidi: read-loop failed')
-          GRPC.logger.warn(e)
-          @readq.push(e)  # let each_queued_msg terminate with this error
+
+          res = @unmarshal.call(batch_result.message)
+          yield res
         end
-        GRPC.logger.debug('bidi-read-loop: finished')
-        @reads_complete = true
-        finished
+      rescue StandardError => e
+        GRPC.logger.warn('bidi: read-loop failed')
+        GRPC.logger.warn(e)
+        raise e
       end
+      GRPC.logger.debug('bidi-read-loop: finished')
+      @reads_complete = true
+      finished
     end
   end
 end
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 9afc656..6a7805c 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -694,13 +694,6 @@
   NO_DEPS = true
   endif
 
-  INSTALL_OK = false
-  ifeq ($(HAS_VALID_PROTOC),true)
-  ifeq ($(HAS_SYSTEM_PROTOBUF_VERIFY),true)
-  INSTALL_OK = true
-  endif
-  endif
-
   .SECONDARY = %.pb.h %.pb.cc
 
   ifeq ($(DEP_MISSING),)
@@ -1193,7 +1186,7 @@
   	$(Q) mkdir -p `dirname $@`
   	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
-  install: install_c install_cxx install-plugins install-certs verify-install
+  install: install_c install_cxx install-plugins install-certs
 
   install_c: install-headers_c install-static_c install-shared_c
 
@@ -1311,28 +1304,6 @@
   	$(Q) $(INSTALL) -d $(prefix)/share/grpc
   	$(Q) $(INSTALL) etc/roots.pem $(prefix)/share/grpc/roots.pem
 
-  verify-install:
-  ifeq ($(INSTALL_OK),true)
-  	@echo "Your system looks ready to go."
-  	@echo
-  else
-  	@echo "Warning: it looks like protoc 3.0.0+ isn't installed on your system,"
-  	@echo "which means that you won't be able to compile .proto files for use"
-  	@echo "with gRPC."
-  	@echo
-  	@echo "If you are just using pre-compiled protocol buffers, or you otherwise"
-  	@echo "have no need to compile .proto files, you can ignore this."
-  	@echo
-  	@echo "If you do need protobuf for some reason, you can download and install"
-  	@echo "it from:"
-  	@echo
-  	@echo "   https://github.com/google/protobuf/releases"
-  	@echo
-  	@echo "Once you've done so, you can re-run this check by doing:"
-  	@echo
-  	@echo "   make verify-install"
-  endif
-
   clean:
   	$(E) "[CLEAN]   Cleaning build directories."
   	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) cache.mk
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index ce775ff..f95adaf 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -29,7 +29,7 @@
     s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
     s.platform      = Gem::Platform::RUBY
 
-    s.add_dependency 'google-protobuf', '~> 3.0.0.alpha.5.0.3'
+    s.add_dependency 'google-protobuf', '~> 3.0'
     s.add_dependency 'googleauth',      '~> 0.5.1'
 
     s.add_development_dependency 'bundler',            '~> 1.9'
diff --git a/templates/package.json.template b/templates/package.json.template
index f68f64d..e9596d4 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -37,7 +37,7 @@
     "devDependencies": {
       "async": "^1.5.0",
       "google-auth-library": "^0.9.2",
-      "google-protobuf": "^3.0.0-alpha.5",
+      "google-protobuf": "^3.0.0",
       "istanbul": "^0.3.21",
       "jsdoc": "^3.3.2",
       "jshint": "^2.5.0",
diff --git a/templates/package.xml.template b/templates/package.xml.template
index 87b1038..43d3aa2 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -12,7 +12,7 @@
     <email>grpc-packages@google.com</email>
     <active>yes</active>
    </lead>
-   <date>2016-07-28</date>
+   <date>2016-08-09</date>
    <time>16:06:07</time>
    <version>
     <release>${settings.php_version.php()}</release>
@@ -24,7 +24,7 @@
    </stability>
    <license>BSD</license>
    <notes>
-  - PHP7 Support continued, reduce code duplication #7543
+  - Fixed Ubuntu compile error #7571, #7642
    </notes>
    <contents>
     <dir baseinstalldir="/" name="/">
@@ -249,5 +249,20 @@
   - PHP7 Support continued, reduce code duplication #7543
      </notes>
     </release>
+    <release>
+     <version>
+      <release>1.0.0RC4</release>
+      <api>1.0.0RC4</api>
+     </version>
+     <stability>
+      <release>stable</release>
+      <api>stable</api>
+     </stability>
+     <date>2016-08-09</date>
+     <license>BSD</license>
+     <notes>
+  - Fixed Ubuntu compile error #7571, #7642
+     </notes>
+    </release>
    </changelog>
   </package>
diff --git a/templates/src/csharp/Grpc.Auth/project.json.template b/templates/src/csharp/Grpc.Auth/project.json.template
index b3244e4..19d4b42 100644
--- a/templates/src/csharp/Grpc.Auth/project.json.template
+++ b/templates/src/csharp/Grpc.Auth/project.json.template
@@ -25,13 +25,13 @@
     },
     "dependencies": {
       "Grpc.Core": "${settings.csharp_version}",
-      "Google.Apis.Auth": "1.11.1"
+      "Google.Apis.Auth": "1.15.0"
     },
     "frameworks": {
       "net45": { },
       "netstandard1.5": {
         "imports": [
-          "net45"
+          "portable-net45"
         ],
         "dependencies": {
           "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
diff --git a/templates/src/csharp/Grpc.Examples.MathClient/project.json.template b/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
index 51c5e85..67151db 100644
--- a/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
+++ b/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
@@ -1,7 +1,7 @@
 %YAML 1.2
 --- |
   {
-    <%include file="../build_options.include" args="executable=True,includeRuntimes=False"/>
+    <%include file="../build_options.include" args="executable=True"/>
     "dependencies": {
       "Grpc.Examples": {
         "target": "project"
diff --git a/templates/src/csharp/Grpc.Examples.MathServer/project.json.template b/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
index 51c5e85..67151db 100644
--- a/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
+++ b/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
@@ -1,7 +1,7 @@
 %YAML 1.2
 --- |
   {
-    <%include file="../build_options.include" args="executable=True,includeRuntimes=False"/>
+    <%include file="../build_options.include" args="executable=True"/>
     "dependencies": {
       "Grpc.Examples": {
         "target": "project"
diff --git a/templates/src/csharp/Grpc.Examples/project.json.template b/templates/src/csharp/Grpc.Examples/project.json.template
index d5d63f6..117f842 100644
--- a/templates/src/csharp/Grpc.Examples/project.json.template
+++ b/templates/src/csharp/Grpc.Examples/project.json.template
@@ -15,11 +15,12 @@
           "System.IO": ""
         }
       },
-      "netstandard1.5": {
+      "netcoreapp1.0": {
         "imports": [
           "portable-net45"
         ],
         "dependencies": {
+          "Microsoft.NETCore.App": "1.0.0",
           "NETStandard.Library": "1.6.0"
         }
       }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
index af1ee42..93151f2 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
@@ -1,7 +1,7 @@
 %YAML 1.2
 --- |
   {
-    <%include file="../build_options.include" args="executable=True,includeData=True,includeRuntimes=False"/>
+    <%include file="../build_options.include" args="executable=True,includeData=True"/>
     "dependencies": {
       "Grpc.IntegrationTesting": {
         "target": "project"
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
index af1ee42..93151f2 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
@@ -1,7 +1,7 @@
 %YAML 1.2
 --- |
   {
-    <%include file="../build_options.include" args="executable=True,includeData=True,includeRuntimes=False"/>
+    <%include file="../build_options.include" args="executable=True,includeData=True"/>
     "dependencies": {
       "Grpc.IntegrationTesting": {
         "target": "project"
diff --git a/templates/src/csharp/Grpc.IntegrationTesting/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
index 0a7d5e9..1cb5ca4 100644
--- a/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
+++ b/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
@@ -10,7 +10,7 @@
         "target": "project"
       },
       "Google.Protobuf": "3.0.0-beta3",
-      "CommandLineParser": "1.9.71",
+      "CommandLineParser.Unofficial": "2.0.275",
       "NUnit": "3.2.0",
       "NUnitLite": "3.2.0-*"
     },
diff --git a/templates/src/csharp/build_options.include b/templates/src/csharp/build_options.include
index a200897..8597ae3 100644
--- a/templates/src/csharp/build_options.include
+++ b/templates/src/csharp/build_options.include
@@ -1,4 +1,4 @@
-<%page args="executable=False,includeData=False,includeRuntimes=True"/>\
+<%page args="executable=False,includeData=False"/>\
 "buildOptions": {
   % if executable:
     "emitEntryPoint": true
@@ -52,10 +52,8 @@
     }
   },
   %endif
-  % if includeRuntimes:
   "runtimes": {
     "win7-x64": { },
     "debian.8-x64": { },
     "osx.10.11-x64": { }
   },
-  % endif
\ No newline at end of file
diff --git a/templates/src/csharp/build_packages.bat.template b/templates/src/csharp/build_packages.bat.template
index ea2acb6..5cbd8e3 100644
--- a/templates/src/csharp/build_packages.bat.template
+++ b/templates/src/csharp/build_packages.bat.template
@@ -33,10 +33,7 @@
   
   @rem Current package versions
   set VERSION=${settings.csharp_version}
-  set PROTOBUF_VERSION=3.0.0-beta3
-  
-  @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
-  set VERSION_WITH_BETA=%VERSION%-beta
+  set PROTOBUF_VERSION=3.0.0
   
   @rem Adjust the location of nuget.exe
   set NUGET=C:\nuget\nuget.exe
@@ -60,7 +57,6 @@
   
   @rem Fetch all dependencies
   %%NUGET% restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error
-  %%NUGET% restore Grpc.sln || goto :error
   
   setlocal
   
@@ -75,7 +71,7 @@
   
   %%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
   %%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
-  %%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
+  %%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
   %%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
   %%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
   
diff --git a/templates/src/node/health_check/package.json.template b/templates/src/node/health_check/package.json.template
index 96b9748..c2bb232 100644
--- a/templates/src/node/health_check/package.json.template
+++ b/templates/src/node/health_check/package.json.template
@@ -17,9 +17,9 @@
       }
     ],
     "dependencies": {
-      "grpc": "^0.15.0",
+      "grpc": "^${settings.node_version}",
       "lodash": "^3.9.3",
-      "google-protobuf": "^3.0.0-alpha.5"
+      "google-protobuf": "^3.0.0"
     },
     "files": [
       "LICENSE",
diff --git a/test/cpp/util/cli_credentials.cc b/test/cpp/util/cli_credentials.cc
new file mode 100644
index 0000000..8de9393
--- /dev/null
+++ b/test/cpp/util/cli_credentials.cc
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/cpp/util/cli_credentials.h"
+
+#include <gflags/gflags.h>
+
+DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
+DEFINE_bool(use_auth, false, "Whether to create default google credentials.");
+
+namespace grpc {
+namespace testing {
+
+std::shared_ptr<grpc::ChannelCredentials> CliCredentials::GetCredentials()
+    const {
+  if (!FLAGS_enable_ssl) {
+    return grpc::InsecureChannelCredentials();
+  } else {
+    if (FLAGS_use_auth) {
+      return grpc::GoogleDefaultCredentials();
+    } else {
+      return grpc::SslCredentials(grpc::SslCredentialsOptions());
+    }
+  }
+}
+
+const grpc::string CliCredentials::GetCredentialUsage() const {
+  return "    --enable_ssl             ; Set whether to use tls\n"
+         "    --use_auth               ; Set whether to create default google"
+         " credentials\n";
+}
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/util/cli_credentials.h b/test/cpp/util/cli_credentials.h
new file mode 100644
index 0000000..581b77a
--- /dev/null
+++ b/test/cpp/util/cli_credentials.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
+#define GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
+
+#include <grpc++/security/credentials.h>
+#include <grpc++/support/config.h>
+
+namespace grpc {
+namespace testing {
+
+class CliCredentials {
+ public:
+  virtual ~CliCredentials() {}
+  virtual std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const;
+  virtual const grpc::string GetCredentialUsage() const;
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
diff --git a/test/cpp/util/config_grpc_cli.h b/test/cpp/util/config_grpc_cli.h
new file mode 100644
index 0000000..ea8231a
--- /dev/null
+++ b/test/cpp/util/config_grpc_cli.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
+#define GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
+
+#include <grpc++/impl/codegen/config_protobuf.h>
+
+#ifndef GRPC_CUSTOM_DYNAMICMESSAGEFACTORY
+#include <google/protobuf/dynamic_message.h>
+#define GRPC_CUSTOM_DYNAMICMESSAGEFACTORY \
+  ::google::protobuf::DynamicMessageFactory
+#endif
+
+#ifndef GRPC_CUSTOM_DESCRIPTORPOOLDATABASE
+#include <google/protobuf/descriptor.h>
+#define GRPC_CUSTOM_DESCRIPTORPOOLDATABASE \
+  ::google::protobuf::DescriptorPoolDatabase
+#define GRPC_CUSTOM_MERGEDDESCRIPTORDATABASE \
+  ::google::protobuf::MergedDescriptorDatabase
+#endif
+
+#ifndef GRPC_CUSTOM_TEXTFORMAT
+#include <google/protobuf/text_format.h>
+#define GRPC_CUSTOM_TEXTFORMAT ::google::protobuf::TextFormat
+#endif
+
+#ifndef GRPC_CUSTOM_DISKSOURCETREE
+#include <google/protobuf/compiler/importer.h>
+#define GRPC_CUSTOM_DISKSOURCETREE ::google::protobuf::compiler::DiskSourceTree
+#define GRPC_CUSTOM_IMPORTER ::google::protobuf::compiler::Importer
+#define GRPC_CUSTOM_MULTIFILEERRORCOLLECTOR \
+  ::google::protobuf::compiler::MultiFileErrorCollector
+#endif
+
+namespace grpc {
+namespace protobuf {
+
+typedef GRPC_CUSTOM_DYNAMICMESSAGEFACTORY DynamicMessageFactory;
+
+typedef GRPC_CUSTOM_DESCRIPTORPOOLDATABASE DescriptorPoolDatabase;
+typedef GRPC_CUSTOM_MERGEDDESCRIPTORDATABASE MergedDescriptorDatabase;
+
+typedef GRPC_CUSTOM_TEXTFORMAT TextFormat;
+
+namespace compiler {
+typedef GRPC_CUSTOM_DISKSOURCETREE DiskSourceTree;
+typedef GRPC_CUSTOM_IMPORTER Importer;
+typedef GRPC_CUSTOM_MULTIFILEERRORCOLLECTOR MultiFileErrorCollector;
+}  // namespace importer
+
+}  // namespace protobuf
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc
index 53529da..fe24860 100644
--- a/test/cpp/util/grpc_cli.cc
+++ b/test/cpp/util/grpc_cli.cc
@@ -33,12 +33,14 @@
 
 /*
   A command line tool to talk to a grpc server.
+  Run `grpc_cli help` command to see its usage information.
+
   Example of talking to grpc interop server:
   grpc_cli call localhost:50051 UnaryCall "response_size:10" \
       --protofiles=src/proto/grpc/testing/test.proto --enable_ssl=false
 
   Options:
-    1. --protofiles, use this flag to provide a proto file if the server does
+    1. --protofiles, use this flag to provide proto files if the server does
        does not have the reflection service.
     2. --proto_path, if your proto file is not under current working directory,
        use this flag to provide a search root. It should work similar to the
@@ -48,15 +50,17 @@
        --metadata="MyHeaderKey1:Value1:MyHeaderKey2:Value2"
     4. --enable_ssl, whether to use tls.
     5. --use_auth, if set to true, attach a GoogleDefaultCredentials to the call
-    6. --input_binary_file, a file containing the serialized request. The file
-       can be generated by calling something like:
+    6. --infile, input filename (defaults to stdin)
+    7. --outfile, output filename (defaults to stdout)
+    8. --binary_input, use the serialized request as input. The serialized
+       request can be generated by calling something like:
        protoc --proto_path=src/proto/grpc/testing/ \
          --encode=grpc.testing.SimpleRequest \
          src/proto/grpc/testing/messages.proto \
          < input.txt > input.bin
        If this is used and no proto file is provided in the argument list, the
        method string has to be exact in the form of /package.service/method.
-    7. --output_binary_file, a file to write binary format response into, it can
+    9. --binary_output, use binary format response as output, it can
        be later decoded using protoc:
        protoc --proto_path=src/proto/grpc/testing/ \
        --decode=grpc.testing.SimpleResponse \
@@ -64,182 +68,34 @@
        < output.bin > output.txt
 */
 
-#include <unistd.h>
 #include <fstream>
+#include <functional>
 #include <iostream>
-#include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/support/string_ref.h>
-#include <grpc/grpc.h>
-
-#include "test/cpp/util/cli_call.h"
-#include "test/cpp/util/proto_file_parser.h"
-#include "test/cpp/util/string_ref_helper.h"
+#include <grpc++/support/config.h>
+#include "test/cpp/util/cli_credentials.h"
+#include "test/cpp/util/grpc_tool.h"
 #include "test/cpp/util/test_config.h"
 
-DEFINE_bool(enable_ssl, true, "Whether to use ssl/tls.");
-DEFINE_bool(use_auth, false, "Whether to create default google credentials.");
-DEFINE_string(input_binary_file, "",
-              "Path to input file containing serialized request.");
-DEFINE_string(output_binary_file, "",
-              "Path to output file to write serialized response.");
-DEFINE_string(metadata, "",
-              "Metadata to send to server, in the form of key1:val1:key2:val2");
-DEFINE_string(proto_path, ".", "Path to look for the proto file.");
-// TODO(zyc): support a list of input proto files
-DEFINE_string(protofiles, "", "Name of the proto file.");
+DEFINE_string(outfile, "", "Output file (default is stdout)");
 
-void ParseMetadataFlag(
-    std::multimap<grpc::string, grpc::string>* client_metadata) {
-  if (FLAGS_metadata.empty()) {
-    return;
+static bool SimplePrint(const grpc::string& outfile,
+                        const grpc::string& output) {
+  if (outfile.empty()) {
+    std::cout << output;
+  } else {
+    std::ofstream output_file(outfile, std::ios::trunc | std::ios::binary);
+    output_file << output;
+    output_file.close();
   }
-  std::vector<grpc::string> fields;
-  const char* delim = ":";
-  size_t cur, next = -1;
-  do {
-    cur = next + 1;
-    next = FLAGS_metadata.find_first_of(delim, cur);
-    fields.push_back(FLAGS_metadata.substr(cur, next - cur));
-  } while (next != grpc::string::npos);
-  if (fields.size() % 2) {
-    std::cout << "Failed to parse metadata flag" << std::endl;
-    exit(1);
-  }
-  for (size_t i = 0; i < fields.size(); i += 2) {
-    client_metadata->insert(
-        std::pair<grpc::string, grpc::string>(fields[i], fields[i + 1]));
-  }
-}
-
-template <typename T>
-void PrintMetadata(const T& m, const grpc::string& message) {
-  if (m.empty()) {
-    return;
-  }
-  std::cout << message << std::endl;
-  grpc::string pair;
-  for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
-    pair.clear();
-    pair.append(iter->first.data(), iter->first.size());
-    pair.append(" : ");
-    pair.append(iter->second.data(), iter->second.size());
-    std::cout << pair << std::endl;
-  }
+  return true;
 }
 
 int main(int argc, char** argv) {
   grpc::testing::InitTest(&argc, &argv, true);
 
-  if (argc < 4 || grpc::string(argv[1]) != "call") {
-    std::cout << "Usage: grpc_cli call server_host:port method_name "
-              << "[proto file] [text format request] [<options>]" << std::endl;
-    return 1;
-  }
-
-  grpc::string request_text;
-  grpc::string server_address(argv[2]);
-  grpc::string method_name(argv[3]);
-  std::unique_ptr<grpc::testing::ProtoFileParser> parser;
-  grpc::string serialized_request_proto;
-
-  if (argc == 5) {
-    request_text = argv[4];
-  }
-
-  std::shared_ptr<grpc::ChannelCredentials> creds;
-  if (!FLAGS_enable_ssl) {
-    creds = grpc::InsecureChannelCredentials();
-  } else {
-    if (FLAGS_use_auth) {
-      creds = grpc::GoogleDefaultCredentials();
-    } else {
-      creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
-    }
-  }
-  std::shared_ptr<grpc::Channel> channel =
-      grpc::CreateChannel(server_address, creds);
-
-  if (request_text.empty() && FLAGS_input_binary_file.empty()) {
-    if (isatty(STDIN_FILENO)) {
-      std::cout << "reading request message from stdin..." << std::endl;
-    }
-    std::stringstream input_stream;
-    input_stream << std::cin.rdbuf();
-    request_text = input_stream.str();
-  }
-
-  if (!request_text.empty()) {
-    if (!FLAGS_protofiles.empty()) {
-      parser.reset(new grpc::testing::ProtoFileParser(
-          FLAGS_proto_path, FLAGS_protofiles, method_name));
-    } else {
-      parser.reset(new grpc::testing::ProtoFileParser(channel, method_name));
-    }
-    method_name = parser->GetFullMethodName();
-    if (parser->HasError()) {
-      return 1;
-    }
-
-    if (!FLAGS_input_binary_file.empty()) {
-      std::cout
-          << "warning: request given in argv, ignoring --input_binary_file"
-          << std::endl;
-    }
-  }
-
-  if (parser) {
-    serialized_request_proto =
-        parser->GetSerializedProto(request_text, true /* is_request */);
-    if (parser->HasError()) {
-      return 1;
-    }
-  } else if (!FLAGS_input_binary_file.empty()) {
-    std::ifstream input_file(FLAGS_input_binary_file,
-                             std::ios::in | std::ios::binary);
-    std::stringstream input_stream;
-    input_stream << input_file.rdbuf();
-    serialized_request_proto = input_stream.str();
-  }
-  std::cout << "connecting to " << server_address << std::endl;
-
-  grpc::string serialized_response_proto;
-  std::multimap<grpc::string, grpc::string> client_metadata;
-  std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata,
-      server_trailing_metadata;
-  ParseMetadataFlag(&client_metadata);
-  PrintMetadata(client_metadata, "Sending client initial metadata:");
-  grpc::Status s = grpc::testing::CliCall::Call(
-      channel, method_name, serialized_request_proto,
-      &serialized_response_proto, client_metadata, &server_initial_metadata,
-      &server_trailing_metadata);
-  PrintMetadata(server_initial_metadata,
-                "Received initial metadata from server:");
-  PrintMetadata(server_trailing_metadata,
-                "Received trailing metadata from server:");
-  if (s.ok()) {
-    std::cout << "Rpc succeeded with OK status" << std::endl;
-    if (parser) {
-      grpc::string response_text = parser->GetTextFormat(
-          serialized_response_proto, false /* is_request */);
-      if (parser->HasError()) {
-        return 1;
-      }
-      std::cout << "Response: \n " << response_text << std::endl;
-    }
-    if (!FLAGS_output_binary_file.empty()) {
-      std::ofstream output_file(FLAGS_output_binary_file,
-                                std::ios::trunc | std::ios::binary);
-      output_file << serialized_response_proto;
-    }
-  } else {
-    std::cout << "Rpc failed with status code " << s.error_code()
-              << ", error message: " << s.error_message() << std::endl;
-  }
-
-  return 0;
+  return grpc::testing::GrpcToolMainLib(
+      argc, (const char**)argv, grpc::testing::CliCredentials(),
+      std::bind(SimplePrint, FLAGS_outfile, std::placeholders::_1));
 }
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
new file mode 100644
index 0000000..f06053c
--- /dev/null
+++ b/test/cpp/util/grpc_tool.cc
@@ -0,0 +1,365 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/cpp/util/grpc_tool.h"
+
+#include <unistd.h>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include <gflags/gflags.h>
+#include <grpc++/channel.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/grpc++.h>
+#include <grpc++/security/credentials.h>
+#include <grpc++/support/string_ref.h>
+#include <grpc/grpc.h>
+
+#include "test/cpp/util/cli_call.h"
+#include "test/cpp/util/proto_file_parser.h"
+#include "test/cpp/util/proto_reflection_descriptor_database.h"
+#include "test/cpp/util/test_config.h"
+
+DEFINE_bool(remotedb, true, "Use server types to parse and format messages");
+DEFINE_string(metadata, "",
+              "Metadata to send to server, in the form of key1:val1:key2:val2");
+DEFINE_string(proto_path, ".", "Path to look for the proto file.");
+DEFINE_string(proto_file, "", "Name of the proto file.");
+DEFINE_bool(binary_input, false, "Input in binary format");
+DEFINE_bool(binary_output, false, "Output in binary format");
+DEFINE_string(infile, "", "Input file (default is stdin)");
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class GrpcTool {
+ public:
+  explicit GrpcTool();
+  virtual ~GrpcTool() {}
+
+  bool Help(int argc, const char** argv, CliCredentials cred,
+            GrpcToolOutputCallback callback);
+  bool CallMethod(int argc, const char** argv, CliCredentials cred,
+                  GrpcToolOutputCallback callback);
+  // TODO(zyc): implement the following methods
+  // bool ListServices(int argc, const char** argv, GrpcToolOutputCallback
+  // callback);
+  // bool PrintType(int argc, const char** argv, GrpcToolOutputCallback
+  // callback);
+  // bool PrintTypeId(int argc, const char** argv, GrpcToolOutputCallback
+  // callback);
+  // bool ParseMessage(int argc, const char** argv, GrpcToolOutputCallback
+  // callback);
+  // bool ToText(int argc, const char** argv, GrpcToolOutputCallback callback);
+  // bool ToBinary(int argc, const char** argv, GrpcToolOutputCallback
+  // callback);
+
+  void SetPrintCommandMode(int exit_status) {
+    print_command_usage_ = true;
+    usage_exit_status_ = exit_status;
+  }
+
+ private:
+  void CommandUsage(const grpc::string& usage) const;
+  bool print_command_usage_;
+  int usage_exit_status_;
+  const grpc::string cred_usage_;
+};
+
+template <typename T>
+std::function<bool(GrpcTool*, int, const char**, const CliCredentials,
+                   GrpcToolOutputCallback)>
+BindWith5Args(T&& func) {
+  return std::bind(std::forward<T>(func), std::placeholders::_1,
+                   std::placeholders::_2, std::placeholders::_3,
+                   std::placeholders::_4, std::placeholders::_5);
+}
+
+template <typename T>
+size_t ArraySize(T& a) {
+  return ((sizeof(a) / sizeof(*(a))) /
+          static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
+}
+
+void ParseMetadataFlag(
+    std::multimap<grpc::string, grpc::string>* client_metadata) {
+  if (FLAGS_metadata.empty()) {
+    return;
+  }
+  std::vector<grpc::string> fields;
+  const char* delim = ":";
+  size_t cur, next = -1;
+  do {
+    cur = next + 1;
+    next = FLAGS_metadata.find_first_of(delim, cur);
+    fields.push_back(FLAGS_metadata.substr(cur, next - cur));
+  } while (next != grpc::string::npos);
+  if (fields.size() % 2) {
+    fprintf(stderr, "Failed to parse metadata flag.\n");
+    exit(1);
+  }
+  for (size_t i = 0; i < fields.size(); i += 2) {
+    client_metadata->insert(
+        std::pair<grpc::string, grpc::string>(fields[i], fields[i + 1]));
+  }
+}
+
+template <typename T>
+void PrintMetadata(const T& m, const grpc::string& message) {
+  if (m.empty()) {
+    return;
+  }
+  fprintf(stderr, "%s\n", message.c_str());
+  grpc::string pair;
+  for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
+    pair.clear();
+    pair.append(iter->first.data(), iter->first.size());
+    pair.append(" : ");
+    pair.append(iter->second.data(), iter->second.size());
+    fprintf(stderr, "%s\n", pair.c_str());
+  }
+}
+
+struct Command {
+  const char* command;
+  std::function<bool(GrpcTool*, int, const char**, const CliCredentials,
+                     GrpcToolOutputCallback)>
+      function;
+  int min_args;
+  int max_args;
+};
+
+const Command ops[] = {
+    {"help", BindWith5Args(&GrpcTool::Help), 0, INT_MAX},
+    // {"ls", BindWith5Args(&GrpcTool::ListServices), 1, 3},
+    // {"list", BindWith5Args(&GrpcTool::ListServices), 1, 3},
+    {"call", BindWith5Args(&GrpcTool::CallMethod), 2, 3},
+    // {"type", BindWith5Args(&GrpcTool::PrintType), 2, 2},
+    // {"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
+    // {"totext", BindWith5Args(&GrpcTool::ToText), 2, 3},
+    // {"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3},
+};
+
+void Usage(const grpc::string& msg) {
+  fprintf(
+      stderr,
+      "%s\n"
+      // "  grpc_cli ls ...         ; List services\n"
+      "  grpc_cli call ...       ; Call method\n"
+      // "  grpc_cli type ...       ; Print type\n"
+      // "  grpc_cli parse ...      ; Parse message\n"
+      // "  grpc_cli totext ...     ; Convert binary message to text\n"
+      // "  grpc_cli tobinary ...   ; Convert text message to binary\n"
+      "  grpc_cli help ...       ; Print this message, or per-command usage\n"
+      "\n",
+      msg.c_str());
+
+  exit(1);
+}
+
+const Command* FindCommand(const grpc::string& name) {
+  for (int i = 0; i < (int)ArraySize(ops); i++) {
+    if (name == ops[i].command) {
+      return &ops[i];
+    }
+  }
+  return NULL;
+}
+}  // namespace
+
+int GrpcToolMainLib(int argc, const char** argv, const CliCredentials cred,
+                    GrpcToolOutputCallback callback) {
+  if (argc < 2) {
+    Usage("No command specified");
+  }
+
+  grpc::string command = argv[1];
+  argc -= 2;
+  argv += 2;
+
+  const Command* cmd = FindCommand(command);
+  if (cmd != NULL) {
+    GrpcTool grpc_tool;
+    if (argc < cmd->min_args || argc > cmd->max_args) {
+      // Force the command to print its usage message
+      fprintf(stderr, "\nWrong number of arguments for %s\n", command.c_str());
+      grpc_tool.SetPrintCommandMode(1);
+      return cmd->function(&grpc_tool, -1, NULL, cred, callback);
+    }
+    const bool ok = cmd->function(&grpc_tool, argc, argv, cred, callback);
+    return ok ? 0 : 1;
+  } else {
+    Usage("Invalid command '" + grpc::string(command.c_str()) + "'");
+  }
+  return 1;
+}
+
+GrpcTool::GrpcTool() : print_command_usage_(false), usage_exit_status_(0) {}
+
+void GrpcTool::CommandUsage(const grpc::string& usage) const {
+  if (print_command_usage_) {
+    fprintf(stderr, "\n%s%s\n", usage.c_str(),
+            (usage.empty() || usage[usage.size() - 1] != '\n') ? "\n" : "");
+    exit(usage_exit_status_);
+  }
+}
+
+bool GrpcTool::Help(int argc, const char** argv, const CliCredentials cred,
+                    GrpcToolOutputCallback callback) {
+  CommandUsage(
+      "Print help\n"
+      "  grpc_cli help [subcommand]\n");
+
+  if (argc == 0) {
+    Usage("");
+  } else {
+    const Command* cmd = FindCommand(argv[0]);
+    if (cmd == NULL) {
+      Usage("Unknown command '" + grpc::string(argv[0]) + "'");
+    }
+    SetPrintCommandMode(0);
+    cmd->function(this, -1, NULL, cred, callback);
+  }
+  return true;
+}
+
+bool GrpcTool::CallMethod(int argc, const char** argv,
+                          const CliCredentials cred,
+                          GrpcToolOutputCallback callback) {
+  CommandUsage(
+      "Call method\n"
+      "  grpc_cli call <address> <service>[.<method>] <request>\n"
+      "    <address>                ; host:port\n"
+      "    <service>                ; Exported service name\n"
+      "    <method>                 ; Method name\n"
+      "    <request>                ; Text protobuffer (overrides infile)\n"
+      "    --proto_file             ; Comma separated proto files used as a"
+      " fallback when parsing request/response\n"
+      "    --proto_path             ; The search path of proto files, valid"
+      " only when --proto_file is given\n"
+      "    --metadata               ; The metadata to be sent to the server\n"
+      "    --infile                 ; Input filename (defaults to stdin)\n"
+      "    --outfile                ; Output filename (defaults to stdout)\n"
+      "    --binary_input           ; Input in binary format\n"
+      "    --binary_output          ; Output in binary format\n" +
+      cred.GetCredentialUsage());
+
+  std::stringstream output_ss;
+  grpc::string request_text;
+  grpc::string server_address(argv[0]);
+  grpc::string method_name(argv[1]);
+  std::unique_ptr<grpc::testing::ProtoFileParser> parser;
+  grpc::string serialized_request_proto;
+
+  if (argc == 3) {
+    request_text = argv[2];
+    if (!FLAGS_infile.empty()) {
+      fprintf(stderr, "warning: request given in argv, ignoring --infile\n");
+    }
+  } else {
+    std::stringstream input_stream;
+    if (FLAGS_infile.empty()) {
+      if (isatty(STDIN_FILENO)) {
+        fprintf(stderr, "reading request message from stdin...\n");
+      }
+      input_stream << std::cin.rdbuf();
+    } else {
+      std::ifstream input_file(FLAGS_infile, std::ios::in | std::ios::binary);
+      input_stream << input_file.rdbuf();
+      input_file.close();
+    }
+    request_text = input_stream.str();
+  }
+
+  std::shared_ptr<grpc::Channel> channel =
+      grpc::CreateChannel(server_address, cred.GetCredentials());
+  if (!FLAGS_binary_input || !FLAGS_binary_output) {
+    parser.reset(
+        new grpc::testing::ProtoFileParser(FLAGS_remotedb ? channel : nullptr,
+                                           FLAGS_proto_path, FLAGS_proto_file));
+    if (parser->HasError()) {
+      return false;
+    }
+  }
+
+  if (FLAGS_binary_input) {
+    serialized_request_proto = request_text;
+  } else {
+    serialized_request_proto = parser->GetSerializedProtoFromMethod(
+        method_name, request_text, true /* is_request */);
+    if (parser->HasError()) {
+      return false;
+    }
+  }
+  fprintf(stderr, "connecting to %s\n", server_address.c_str());
+
+  grpc::string serialized_response_proto;
+  std::multimap<grpc::string, grpc::string> client_metadata;
+  std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata,
+      server_trailing_metadata;
+  ParseMetadataFlag(&client_metadata);
+  PrintMetadata(client_metadata, "Sending client initial metadata:");
+  grpc::Status status = grpc::testing::CliCall::Call(
+      channel, parser->GetFormatedMethodName(method_name),
+      serialized_request_proto, &serialized_response_proto, client_metadata,
+      &server_initial_metadata, &server_trailing_metadata);
+  PrintMetadata(server_initial_metadata,
+                "Received initial metadata from server:");
+  PrintMetadata(server_trailing_metadata,
+                "Received trailing metadata from server:");
+  if (status.ok()) {
+    fprintf(stderr, "Rpc succeeded with OK status\n");
+    if (FLAGS_binary_output) {
+      output_ss << serialized_response_proto;
+    } else {
+      grpc::string response_text = parser->GetTextFormatFromMethod(
+          method_name, serialized_response_proto, false /* is_request */);
+      if (parser->HasError()) {
+        return false;
+      }
+      output_ss << "Response: \n " << response_text << std::endl;
+    }
+  } else {
+    fprintf(stderr, "Rpc failed with status code %d, error message: %s\n",
+            status.error_code(), status.error_message().c_str());
+  }
+
+  return callback(output_ss.str());
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/util/grpc_tool.h b/test/cpp/util/grpc_tool.h
new file mode 100644
index 0000000..3da8693
--- /dev/null
+++ b/test/cpp/util/grpc_tool.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
+#define GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
+
+#include <functional>
+
+#include <grpc++/support/config.h>
+
+#include "test/cpp/util/cli_credentials.h"
+
+namespace grpc {
+namespace testing {
+
+typedef std::function<bool(const grpc::string &)> GrpcToolOutputCallback;
+
+int GrpcToolMainLib(int argc, const char **argv, CliCredentials cred,
+                    GrpcToolOutputCallback callback);
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc
new file mode 100644
index 0000000..b96afaf
--- /dev/null
+++ b/test/cpp/util/grpc_tool_test.cc
@@ -0,0 +1,227 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/cpp/util/grpc_tool.h"
+
+#include <sstream>
+
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/ext/proto_server_reflection_plugin.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc/grpc.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "src/proto/grpc/testing/echo.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/cli_credentials.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+using grpc::testing::EchoRequest;
+using grpc::testing::EchoResponse;
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class TestCliCredentials GRPC_FINAL : public grpc::testing::CliCredentials {
+ public:
+  std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const
+      GRPC_OVERRIDE {
+    return InsecureChannelCredentials();
+  }
+  const grpc::string GetCredentialUsage() const GRPC_OVERRIDE { return ""; }
+};
+
+}  // namespame
+
+class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
+ public:
+  Status Echo(ServerContext* context, const EchoRequest* request,
+              EchoResponse* response) GRPC_OVERRIDE {
+    if (!context->client_metadata().empty()) {
+      for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+               iter = context->client_metadata().begin();
+           iter != context->client_metadata().end(); ++iter) {
+        context->AddInitialMetadata(ToString(iter->first),
+                                    ToString(iter->second));
+      }
+    }
+    context->AddTrailingMetadata("trailing_key", "trailing_value");
+    response->set_message(request->message());
+    return Status::OK;
+  }
+};
+
+class GrpcToolTest : public ::testing::Test {
+ protected:
+  GrpcToolTest() {}
+
+  // SetUpServer cannot be used with EXPECT_EXIT. grpc_pick_unused_port_or_die()
+  // uses atexit() to free chosen ports, and it will spawn a new thread in
+  // resolve_address_posix.c:192 at exit time.
+  const grpc::string SetUpServer() {
+    std::ostringstream server_address;
+    int port = grpc_pick_unused_port_or_die();
+    server_address << "localhost:" << port;
+    // Setup server
+    ServerBuilder builder;
+    builder.AddListeningPort(server_address.str(), InsecureServerCredentials());
+    builder.RegisterService(&service_);
+    server_ = builder.BuildAndStart();
+    return server_address.str();
+  }
+
+  void ShutdownServer() { server_->Shutdown(); }
+
+  std::unique_ptr<Server> server_;
+  TestServiceImpl service_;
+  reflection::ProtoServerReflectionPlugin plugin_;
+};
+
+static bool PrintStream(std::stringstream* ss, const grpc::string& output) {
+  (*ss) << output << std::endl;
+  return true;
+}
+
+template <typename T>
+static size_t ArraySize(T& a) {
+  return ((sizeof(a) / sizeof(*(a))) /
+          static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
+}
+
+#define USAGE_REGEX "(  grpc_cli .+\n){2,10}"
+
+TEST_F(GrpcToolTest, NoCommand) {
+  // Test input "grpc_cli"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli"};
+  // Exit with 1, print usage instruction in stderr
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, InvalidCommand) {
+  // Test input "grpc_cli"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "abc"};
+  // Exit with 1, print usage instruction in stderr
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, HelpCommand) {
+  // Test input "grpc_cli help"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "help"};
+  // Exit with 1, print usage instruction in stderr
+  EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+                              std::bind(PrintStream, &output_stream,
+                                        std::placeholders::_1)),
+              ::testing::ExitedWithCode(1), USAGE_REGEX);
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, CallCommand) {
+  // Test input "grpc_cli call Echo"
+  std::stringstream output_stream;
+
+  const grpc::string server_address = SetUpServer();
+  const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+                        "message: 'Hello'"};
+
+  EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+                                   std::bind(PrintStream, &output_stream,
+                                             std::placeholders::_1)));
+  // Expected output: "message: \"Hello\""
+  EXPECT_TRUE(NULL !=
+              strstr(output_stream.str().c_str(), "message: \"Hello\""));
+  ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, TooFewArguments) {
+  // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "call", "Echo"};
+
+  // Exit with 1
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, TooManyArguments) {
+  // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "call", "localhost:10000",
+                        "Echo",     "Echo", "message: 'Hello'"};
+
+  // Exit with 1
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc
index 5b0d925..0c88c24 100644
--- a/test/cpp/util/proto_file_parser.cc
+++ b/test/cpp/util/proto_file_parser.cc
@@ -37,7 +37,6 @@
 #include <iostream>
 #include <sstream>
 
-#include <google/protobuf/text_format.h>
 #include <grpc++/support/config.h>
 
 namespace grpc {
@@ -56,8 +55,7 @@
 }
 }  // namespace
 
-class ErrorPrinter
-    : public google::protobuf::compiler::MultiFileErrorCollector {
+class ErrorPrinter : public protobuf::compiler::MultiFileErrorCollector {
  public:
   explicit ErrorPrinter(ProtoFileParser* parser) : parser_(parser) {}
 
@@ -71,7 +69,7 @@
 
   void AddWarning(const grpc::string& filename, int line, int column,
                   const grpc::string& message) GRPC_OVERRIDE {
-    std::cout << "warning " << filename << " " << line << " " << column << " "
+    std::cerr << "warning " << filename << " " << line << " " << column << " "
               << message << std::endl;
   }
 
@@ -79,62 +77,69 @@
   ProtoFileParser* parser_;  // not owned
 };
 
-ProtoFileParser::ProtoFileParser(const grpc::string& proto_path,
-                                 const grpc::string& file_name,
-                                 const grpc::string& method)
-    : has_error_(false) {
-  source_tree_.MapPath("", proto_path);
-  error_printer_.reset(new ErrorPrinter(this));
-  importer_.reset(new google::protobuf::compiler::Importer(
-      &source_tree_, error_printer_.get()));
-  const auto* file_desc = importer_->Import(file_name);
-  if (!file_desc) {
-    LogError("");
-    return;
-  }
-  dynamic_factory_.reset(
-      new google::protobuf::DynamicMessageFactory(importer_->pool()));
-
-  std::vector<const google::protobuf::ServiceDescriptor*> service_desc_list;
-  for (int i = 0; i < file_desc->service_count(); i++) {
-    service_desc_list.push_back(file_desc->service(i));
-  }
-  InitProtoFileParser(method, service_desc_list);
-}
-
 ProtoFileParser::ProtoFileParser(std::shared_ptr<grpc::Channel> channel,
-                                 const grpc::string& method)
-    : has_error_(false),
-      desc_db_(new grpc::ProtoReflectionDescriptorDatabase(channel)),
-      desc_pool_(new google::protobuf::DescriptorPool(desc_db_.get())) {
+                                 const grpc::string& proto_path,
+                                 const grpc::string& protofiles)
+    : has_error_(false) {
   std::vector<std::string> service_list;
-  if (!desc_db_->GetServices(&service_list)) {
-    LogError(
-        "Failed to get services from the server, "
-        "it may not have the reflection service.\n"
-        "Please try to use the --protofiles option to provide a proto file.");
+  if (channel) {
+    reflection_db_.reset(new grpc::ProtoReflectionDescriptorDatabase(channel));
+    reflection_db_->GetServices(&service_list);
   }
-  if (has_error_) {
+
+  if (!protofiles.empty()) {
+    source_tree_.MapPath("", proto_path);
+    error_printer_.reset(new ErrorPrinter(this));
+    importer_.reset(
+        new protobuf::compiler::Importer(&source_tree_, error_printer_.get()));
+
+    grpc::string file_name;
+    std::stringstream ss(protofiles);
+    while (std::getline(ss, file_name, ',')) {
+      const auto* file_desc = importer_->Import(file_name);
+      if (file_desc) {
+        for (int i = 0; i < file_desc->service_count(); i++) {
+          service_desc_list_.push_back(file_desc->service(i));
+        }
+      } else {
+        std::cerr << file_name << " not found" << std::endl;
+      }
+    }
+
+    file_db_.reset(new protobuf::DescriptorPoolDatabase(*importer_->pool()));
+  }
+
+  if (!reflection_db_ && !file_db_) {
+    LogError("No available proto database");
     return;
   }
-  dynamic_factory_.reset(
-      new google::protobuf::DynamicMessageFactory(desc_pool_.get()));
 
-  std::vector<const google::protobuf::ServiceDescriptor*> service_desc_list;
-  for (auto it = service_list.begin(); it != service_list.end(); it++) {
-    service_desc_list.push_back(desc_pool_->FindServiceByName(*it));
+  if (!reflection_db_) {
+    desc_db_ = std::move(file_db_);
+  } else if (!file_db_) {
+    desc_db_ = std::move(reflection_db_);
+  } else {
+    desc_db_.reset(new protobuf::MergedDescriptorDatabase(reflection_db_.get(),
+                                                          file_db_.get()));
   }
-  InitProtoFileParser(method, service_desc_list);
+
+  desc_pool_.reset(new protobuf::DescriptorPool(desc_db_.get()));
+  dynamic_factory_.reset(new protobuf::DynamicMessageFactory(desc_pool_.get()));
+
+  for (auto it = service_list.begin(); it != service_list.end(); it++) {
+    if (const protobuf::ServiceDescriptor* service_desc =
+            desc_pool_->FindServiceByName(*it)) {
+      service_desc_list_.push_back(service_desc);
+    }
+  }
 }
 
 ProtoFileParser::~ProtoFileParser() {}
 
-void ProtoFileParser::InitProtoFileParser(
-    const grpc::string& method,
-    const std::vector<const google::protobuf::ServiceDescriptor*>
-        service_desc_list) {
-  const google::protobuf::MethodDescriptor* method_descriptor = nullptr;
-  for (auto it = service_desc_list.begin(); it != service_desc_list.end();
+grpc::string ProtoFileParser::GetFullMethodName(const grpc::string& method) {
+  has_error_ = false;
+  const protobuf::MethodDescriptor* method_descriptor = nullptr;
+  for (auto it = service_desc_list_.begin(); it != service_desc_list_.end();
        it++) {
     const auto* service_desc = *it;
     for (int j = 0; j < service_desc->method_count(); j++) {
@@ -154,28 +159,82 @@
     LogError("Method name not found");
   }
   if (has_error_) {
-    return;
+    return "";
   }
-  full_method_name_ = method_descriptor->full_name();
-  size_t last_dot = full_method_name_.find_last_of('.');
-  if (last_dot != grpc::string::npos) {
-    full_method_name_[last_dot] = '/';
-  }
-  full_method_name_.insert(full_method_name_.begin(), '/');
 
-  request_prototype_.reset(
-      dynamic_factory_->GetPrototype(method_descriptor->input_type())->New());
-  response_prototype_.reset(
-      dynamic_factory_->GetPrototype(method_descriptor->output_type())->New());
+  return method_descriptor->full_name();
 }
 
-grpc::string ProtoFileParser::GetSerializedProto(
-    const grpc::string& text_format_proto, bool is_request) {
+grpc::string ProtoFileParser::GetFormatedMethodName(
+    const grpc::string& method) {
+  has_error_ = false;
+  grpc::string formated_method_name = GetFullMethodName(method);
+  if (has_error_) {
+    return "";
+  }
+  size_t last_dot = formated_method_name.find_last_of('.');
+  if (last_dot != grpc::string::npos) {
+    formated_method_name[last_dot] = '/';
+  }
+  formated_method_name.insert(formated_method_name.begin(), '/');
+  return formated_method_name;
+}
+
+grpc::string ProtoFileParser::GetMessageTypeFromMethod(
+    const grpc::string& method, bool is_request) {
+  has_error_ = false;
+  grpc::string full_method_name = GetFullMethodName(method);
+  if (has_error_) {
+    return "";
+  }
+  const protobuf::MethodDescriptor* method_desc =
+      desc_pool_->FindMethodByName(full_method_name);
+  if (!method_desc) {
+    LogError("Method not found");
+    return "";
+  }
+
+  return is_request ? method_desc->input_type()->full_name()
+                    : method_desc->output_type()->full_name();
+}
+
+grpc::string ProtoFileParser::GetSerializedProtoFromMethod(
+    const grpc::string& method, const grpc::string& text_format_proto,
+    bool is_request) {
+  has_error_ = false;
+  grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
+  if (has_error_) {
+    return "";
+  }
+  return GetSerializedProtoFromMessageType(message_type_name,
+                                           text_format_proto);
+}
+
+grpc::string ProtoFileParser::GetTextFormatFromMethod(
+    const grpc::string& method, const grpc::string& serialized_proto,
+    bool is_request) {
+  has_error_ = false;
+  grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
+  if (has_error_) {
+    return "";
+  }
+  return GetTextFormatFromMessageType(message_type_name, serialized_proto);
+}
+
+grpc::string ProtoFileParser::GetSerializedProtoFromMessageType(
+    const grpc::string& message_type_name,
+    const grpc::string& text_format_proto) {
+  has_error_ = false;
   grpc::string serialized;
-  grpc::protobuf::Message* msg =
-      is_request ? request_prototype_.get() : response_prototype_.get();
-  bool ok =
-      google::protobuf::TextFormat::ParseFromString(text_format_proto, msg);
+  const protobuf::Descriptor* desc =
+      desc_pool_->FindMessageTypeByName(message_type_name);
+  if (!desc) {
+    LogError("Message type not found");
+    return "";
+  }
+  std::unique_ptr<grpc::protobuf::Message> msg(
+      dynamic_factory_->GetPrototype(desc)->New());
+  bool ok = protobuf::TextFormat::ParseFromString(text_format_proto, msg.get());
   if (!ok) {
     LogError("Failed to parse text format to proto.");
     return "";
@@ -188,16 +247,24 @@
   return serialized;
 }
 
-grpc::string ProtoFileParser::GetTextFormat(
-    const grpc::string& serialized_proto, bool is_request) {
-  grpc::protobuf::Message* msg =
-      is_request ? request_prototype_.get() : response_prototype_.get();
+grpc::string ProtoFileParser::GetTextFormatFromMessageType(
+    const grpc::string& message_type_name,
+    const grpc::string& serialized_proto) {
+  has_error_ = false;
+  const protobuf::Descriptor* desc =
+      desc_pool_->FindMessageTypeByName(message_type_name);
+  if (!desc) {
+    LogError("Message type not found");
+    return "";
+  }
+  std::unique_ptr<grpc::protobuf::Message> msg(
+      dynamic_factory_->GetPrototype(desc)->New());
   if (!msg->ParseFromString(serialized_proto)) {
     LogError("Failed to deserialize proto.");
     return "";
   }
   grpc::string text_format;
-  if (!google::protobuf::TextFormat::PrintToString(*msg, &text_format)) {
+  if (!protobuf::TextFormat::PrintToString(*msg.get(), &text_format)) {
     LogError("Failed to print proto message to text format");
     return "";
   }
@@ -206,7 +273,7 @@
 
 void ProtoFileParser::LogError(const grpc::string& error_msg) {
   if (!error_msg.empty()) {
-    std::cout << error_msg << std::endl;
+    std::cerr << error_msg << std::endl;
   }
   has_error_ = true;
 }
diff --git a/test/cpp/util/proto_file_parser.h b/test/cpp/util/proto_file_parser.h
index b442d77..eda3991 100644
--- a/test/cpp/util/proto_file_parser.h
+++ b/test/cpp/util/proto_file_parser.h
@@ -36,11 +36,9 @@
 
 #include <memory>
 
-#include <google/protobuf/compiler/importer.h>
-#include <google/protobuf/dynamic_message.h>
 #include <grpc++/channel.h>
 
-#include "src/compiler/config.h"
+#include "test/cpp/util/config_grpc_cli.h"
 #include "test/cpp/util/proto_reflection_descriptor_database.h"
 
 namespace grpc {
@@ -50,44 +48,63 @@
 // Find method and associated request/response types.
 class ProtoFileParser {
  public:
-  // The given proto file_name will be searched in a source tree rooted from
-  // proto_path. The method could be a partial string such as Service.Method or
-  // even just Method. It will log an error if there is ambiguity.
-  ProtoFileParser(const grpc::string& proto_path, const grpc::string& file_name,
-                  const grpc::string& method);
-
+  // The parser will search proto files using the server reflection service
+  // provided on the given channel. The given protofiles in a source tree rooted
+  // from proto_path will also be searched.
   ProtoFileParser(std::shared_ptr<grpc::Channel> channel,
-                  const grpc::string& method);
+                  const grpc::string& proto_path,
+                  const grpc::string& protofiles);
+
   ~ProtoFileParser();
 
-  grpc::string GetFullMethodName() const { return full_method_name_; }
+  // The input method name in the following four functions could be a partial
+  // string such as Service.Method or even just Method. It will log an error if
+  // there is ambiguity.
+  // Full method name is in the form of Service.Method, it's good to be used in
+  // descriptor database queries.
+  grpc::string GetFullMethodName(const grpc::string& method);
 
-  grpc::string GetSerializedProto(const grpc::string& text_format_proto,
-                                  bool is_request);
+  // Formated method name is in the form of /Service/Method, it's good to be
+  // used as the argument of Stub::Call()
+  grpc::string GetFormatedMethodName(const grpc::string& method);
 
-  grpc::string GetTextFormat(const grpc::string& serialized_proto,
-                             bool is_request);
+  grpc::string GetSerializedProtoFromMethod(
+      const grpc::string& method, const grpc::string& text_format_proto,
+      bool is_request);
+
+  grpc::string GetTextFormatFromMethod(const grpc::string& method,
+                                       const grpc::string& serialized_proto,
+                                       bool is_request);
+
+  grpc::string GetSerializedProtoFromMessageType(
+      const grpc::string& message_type_name,
+      const grpc::string& text_format_proto);
+
+  grpc::string GetTextFormatFromMessageType(
+      const grpc::string& message_type_name,
+      const grpc::string& serialized_proto);
 
   bool HasError() const { return has_error_; }
 
   void LogError(const grpc::string& error_msg);
 
  private:
-  void InitProtoFileParser(
-      const grpc::string& method,
-      const std::vector<const google::protobuf::ServiceDescriptor*> services);
+  grpc::string GetMessageTypeFromMethod(const grpc::string& method,
+                                        bool is_request);
 
   bool has_error_;
   grpc::string request_text_;
-  grpc::string full_method_name_;
-  google::protobuf::compiler::DiskSourceTree source_tree_;
+  protobuf::compiler::DiskSourceTree source_tree_;
   std::unique_ptr<ErrorPrinter> error_printer_;
-  std::unique_ptr<google::protobuf::compiler::Importer> importer_;
-  std::unique_ptr<grpc::ProtoReflectionDescriptorDatabase> desc_db_;
-  std::unique_ptr<google::protobuf::DescriptorPool> desc_pool_;
-  std::unique_ptr<google::protobuf::DynamicMessageFactory> dynamic_factory_;
+  std::unique_ptr<protobuf::compiler::Importer> importer_;
+  std::unique_ptr<grpc::ProtoReflectionDescriptorDatabase> reflection_db_;
+  std::unique_ptr<protobuf::DescriptorPoolDatabase> file_db_;
+  std::unique_ptr<protobuf::DescriptorDatabase> desc_db_;
+  std::unique_ptr<protobuf::DescriptorPool> desc_pool_;
+  std::unique_ptr<protobuf::DynamicMessageFactory> dynamic_factory_;
   std::unique_ptr<grpc::protobuf::Message> request_prototype_;
   std::unique_ptr<grpc::protobuf::Message> response_prototype_;
+  std::vector<const protobuf::ServiceDescriptor*> service_desc_list_;
 };
 
 }  // namespace testing
diff --git a/test/cpp/util/proto_reflection_descriptor_database.cc b/test/cpp/util/proto_reflection_descriptor_database.cc
index 8fd466f..f0d14c6 100644
--- a/test/cpp/util/proto_reflection_descriptor_database.cc
+++ b/test/cpp/util/proto_reflection_descriptor_database.cc
@@ -58,7 +58,7 @@
     stream_->WritesDone();
     Status status = stream_->Finish();
     if (!status.ok()) {
-      gpr_log(GPR_ERROR,
+      gpr_log(GPR_INFO,
               "ServerReflectionInfo rpc failed. Error code: %d, details: %s",
               (int)status.error_code(), status.error_message().c_str());
     }
diff --git a/test/distrib/csharp/DistribTest/App.config b/test/distrib/csharp/DistribTest/App.config
deleted file mode 100644
index 30d3e09..0000000
--- a/test/distrib/csharp/DistribTest/App.config
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
-    </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/test/distrib/csharp/DistribTest/DistribTest.csproj b/test/distrib/csharp/DistribTest/DistribTest.csproj
index 1acb34d..6ca03b2 100644
--- a/test/distrib/csharp/DistribTest/DistribTest.csproj
+++ b/test/distrib/csharp/DistribTest/DistribTest.csproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -41,6 +41,8 @@
     <ErrorReport>prompt</ErrorReport>
     <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
     <Prefer32Bit>true</Prefer32Bit>
+    <WarningLevel>4</WarningLevel>
+    <Optimize>false</Optimize>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
     <OutputPath>bin\x64\Release\</OutputPath>
@@ -51,39 +53,15 @@
     <ErrorReport>prompt</ErrorReport>
     <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
     <Prefer32Bit>true</Prefer32Bit>
+    <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="BouncyCastle.Crypto">
-      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth">
-      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices">
-      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core">
-      <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
-    </Reference>
     <Reference Include="Grpc.Auth">
       <HintPath>..\packages\Grpc.Auth.__GRPC_NUGET_VERSION__\lib\net45\Grpc.Auth.dll</HintPath>
     </Reference>
     <Reference Include="Grpc.Core">
       <HintPath>..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\lib\net45\Grpc.Core.dll</HintPath>
     </Reference>
-    <Reference Include="Microsoft.Threading.Tasks">
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Threading.Tasks.Extensions">
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Interactive.Async">
@@ -91,25 +69,33 @@
     </Reference>
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.Extensions">
-      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Net.Http.Primitives">
-      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
-    </Reference>
     <Reference Include="System.Net.Http.WebRequest" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.15.0\lib\net45\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.15.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
-    <None Include="App.config" />
     <None Include="packages.config" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
@@ -119,9 +105,7 @@
       <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
     </PropertyGroup>
     <Error Condition="!Exists('..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\build\net45\Grpc.Core.targets'))" />
-    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
   </Target>
-  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
diff --git a/test/distrib/csharp/DistribTest/packages.config b/test/distrib/csharp/DistribTest/packages.config
index 6963019..e5d2d9d 100644
--- a/test/distrib/csharp/DistribTest/packages.config
+++ b/test/distrib/csharp/DistribTest/packages.config
@@ -1,15 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.15.0" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.15.0" targetFramework="net45" />
   <package id="Grpc" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
   <package id="Grpc.Auth" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
   <package id="Grpc.Core" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
   <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
-  <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
-  <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
   <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
 </packages>
diff --git a/test/distrib/python/distribtest.py b/test/distrib/python/distribtest.py
index dc20688..0125ee6 100644
--- a/test/distrib/python/distribtest.py
+++ b/test/distrib/python/distribtest.py
@@ -27,10 +27,10 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-from grpc.beta import implementations
+import grpc
 
 # This code doesn't do much but makes sure the native extension is loaded
 # which is what we are testing here.
-channel = implementations.insecure_channel('localhost', 1000)
+channel = grpc.insecure_channel('localhost:1000')
 del channel
 print 'Success!'
diff --git a/third_party/thrift b/third_party/thrift
new file mode 160000
index 0000000..bcad917
--- /dev/null
+++ b/third_party/thrift
@@ -0,0 +1 @@
+Subproject commit bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c
diff --git a/tools/gce/create_linux_worker.sh b/tools/gce/create_linux_worker.sh
index 8a2df40..7bf8b24 100755
--- a/tools/gce/create_linux_worker.sh
+++ b/tools/gce/create_linux_worker.sh
@@ -43,8 +43,8 @@
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
     --machine-type n1-standard-8 \
-    --image-family=ubuntu-1510 \
-    --image-project=ubuntu-os-cloud \
+    --image=ubuntu-1510 \
+    --image-project=grpc-testing \
     --boot-disk-size 1000
 
 echo 'Created GCE instance, waiting 60 seconds for it to come online.'
diff --git a/tools/gource/gen-all-logs.sh b/tools/gource/gen-all-logs.sh
index 85352c5..ab60c3c 100755
--- a/tools/gource/gen-all-logs.sh
+++ b/tools/gource/gen-all-logs.sh
@@ -41,7 +41,6 @@
   git clone https://github.com/grpc/$repo.git
   cd $repo
   gource --output-custom-log $tmpdir/logs/$repo
-  sed -i .backup "s,\|/,\|/$repo/,g" $tmpdir/logs/$repo
+  sed -i "s,|/,|/$repo/,g" $tmpdir/logs/$repo
 done
-rm $tmpdir/logs/*.backup
 cat $tmpdir/logs/* | sort -n > $outdir/all-logs.txt
diff --git a/tools/gource/gource.sh b/tools/gource/gource.sh
index b3dad5d..5529b32 100755
--- a/tools/gource/gource.sh
+++ b/tools/gource/gource.sh
@@ -34,7 +34,7 @@
   --max-file-lag 0.05           \
   --max-files 0                 \
   -e 0.01                       \
-  --hide filenames,dirnames     \
+  --hide filenames,dirnames,mouse,progress     \
   --disable-auto-rotate         \
   --file-filter '/grpc/doc/ref' \
   $*
diff --git a/tools/gource/make-video.sh b/tools/gource/make-video.sh
index 02d79df..cde0437 100755
--- a/tools/gource/make-video.sh
+++ b/tools/gource/make-video.sh
@@ -37,7 +37,7 @@
   --stop-at-end         \
   --output-ppm-stream - \
   $@ |                  \
-ffmpeg                  \
+avconv                  \
   -y                    \
   -r 60                 \
   -f image2pipe         \
diff --git a/examples/ruby/lib/helloworld_services.rb b/tools/grift/Dockerfile
similarity index 60%
copy from examples/ruby/lib/helloworld_services.rb
copy to tools/grift/Dockerfile
index fbec667..223ee93 100644
--- a/examples/ruby/lib/helloworld_services.rb
+++ b/tools/grift/Dockerfile
@@ -1,7 +1,4 @@
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# Source: helloworld.proto for package 'helloworld'
-# Original file comments:
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +26,42 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
 
-require 'grpc'
-require 'helloworld'
+FROM ubuntu:14.04
 
-module Helloworld
-  module Greeter
-    # The greeting service definition.
-    class Service
+RUN apt-get update && \
+  apt-get install -y \
+  git build-essential \
+  pkg-config flex \
+  bison \
+  libkrb5-dev \
+  libsasl2-dev \
+  libnuma-dev \
+  pkg-config \
+  libssl-dev \
+  autoconf libtool \
+  cmake \
+  libiberty-dev \
+  g++ unzip \
+  curl make automake libtool libboost-dev
 
-      include GRPC::GenericService
+# Configure git
+RUN git config --global user.name "Jenkins" && \
+  git config --global user.email "jenkins@grpc"
 
-      self.marshal_class_method = :encode
-      self.unmarshal_class_method = :decode
-      self.service_name = 'helloworld.Greeter'
+# Clone gRPC
+RUN git clone https://github.com/grpc/grpc
 
-      # Sends a greeting
-      rpc :SayHello, HelloRequest, HelloReply
-    end
+# Update Submodules
+RUN cd grpc && git submodule update --init
 
-    Stub = Service.rpc_stub_class
-  end
-end
+# Install protobuf
+RUN cd grpc/third_party/protobuf && ./autogen.sh && ./configure && \
+  make -j && make check -j && make install && ldconfig
+
+# Install gRPC
+RUN cd grpc && make -j && make install
+
+# Install thrift
+RUN cd grpc/third_party/thrift && git am --signoff < ../../tools/grift/grpc_plugins_generator.patch && \
+  ./bootstrap.sh && ./configure && make -j && make install
\ No newline at end of file
diff --git a/tools/grift/README.md b/tools/grift/README.md
new file mode 100644
index 0000000..7cbbdc5
--- /dev/null
+++ b/tools/grift/README.md
@@ -0,0 +1,26 @@
+Copyright 2016 Google Inc.
+
+#Documentation
+
+grift is integration of [Apache Thrift](https://github.com/apache/thrift.git) Serializer with gRPC.
+
+This integration allows you to use grpc to send thrift messages in C++ and java.
+
+grift uses Compact Protocol to serialize thrift messages. 
+
+##generating grpc plugins for thrift services
+
+###CPP
+```sh
+ $ thrift --gen cpp <thrift-file>
+```
+
+###JAVA
+```sh
+ $ thrift --gen java <thrift-file>
+```
+
+#Installation
+
+Before Installing thrift make sure to apply this [patch](grpc_plugins_generator.patch) to third_party/thrift.
+Go to third_party/thrift and follow the [INSTALLATION](https://github.com/apache/thrift.git) instructions to install thrift with commit id bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c.
\ No newline at end of file
diff --git a/tools/grift/grpc_plugins_generator.patch b/tools/grift/grpc_plugins_generator.patch
new file mode 100644
index 0000000..de82a01
--- /dev/null
+++ b/tools/grift/grpc_plugins_generator.patch
@@ -0,0 +1,2505 @@
+From 0894590b5020c38106d4ebb2291994668c64f9dd Mon Sep 17 00:00:00 2001
+From: chedeti <chedeti@google.com>
+Date: Sun, 31 Jul 2016 15:47:47 -0700
+Subject: [PATCH 1/3] don't build tests
+
+---
+ Makefile.am         | 7 ++-----
+ lib/cpp/Makefile.am | 7 ++-----
+ 2 files changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 10fe49a..d49caac 100755
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -21,10 +21,6 @@ ACLOCAL_AMFLAGS = -I ./aclocal
+ 
+ SUBDIRS = compiler/cpp lib
+ 
+-if WITH_TESTS
+-SUBDIRS += test
+-endif
+-
+ if WITH_TUTORIAL
+ SUBDIRS += tutorial
+ endif
+@@ -117,4 +113,5 @@ EXTRA_DIST = \
+ 	CHANGES \
+ 	NOTICE \
+ 	README.md \
+-	Thrift.podspec
++	Thrift.podspec \
++	test
+diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
+index 6fd15d2..7de1fad 100755
+--- a/lib/cpp/Makefile.am
++++ b/lib/cpp/Makefile.am
+@@ -27,10 +27,6 @@ moc__%.cpp: %.h
+ 
+ SUBDIRS = .
+ 
+-if WITH_TESTS
+-SUBDIRS += test
+-endif
+-
+ pkgconfigdir = $(libdir)/pkgconfig
+ 
+ lib_LTLIBRARIES = libthrift.la
+@@ -277,7 +273,8 @@ EXTRA_DIST = \
+              thrift-qt.pc.in \
+              thrift-qt5.pc.in \
+              src/thrift/qt/CMakeLists.txt \
+-             $(WINDOWS_DIST)
++             $(WINDOWS_DIST) \
++             test
+ 
+ style-local:
+ 	$(CPPSTYLE_CMD)
+-- 
+2.8.0.rc3.226.g39d4020
+
+
+From 387e4300bc9d98176a92a7c010621443a538e7f2 Mon Sep 17 00:00:00 2001
+From: chedeti <chedeti@google.com>
+Date: Sun, 31 Jul 2016 16:16:40 -0700
+Subject: [PATCH 2/3] grpc cpp plugins generator with example
+
+---
+ compiler/cpp/src/generate/t_cpp_generator.cc | 489 +++++++++++++++++++++++----
+ tutorial/cpp/CMakeLists.txt                  |  53 ---
+ tutorial/cpp/CppClient.cpp                   |  80 -----
+ tutorial/cpp/CppServer.cpp                   | 181 ----------
+ tutorial/cpp/GriftClient.cpp                 |  93 +++++
+ tutorial/cpp/GriftServer.cpp                 |  93 +++++
+ tutorial/cpp/Makefile.am                     |  66 ++--
+ tutorial/cpp/test.thrift                     |  13 +
+ 8 files changed, 652 insertions(+), 416 deletions(-)
+ delete mode 100644 tutorial/cpp/CMakeLists.txt
+ delete mode 100644 tutorial/cpp/CppClient.cpp
+ delete mode 100644 tutorial/cpp/CppServer.cpp
+ create mode 100644 tutorial/cpp/GriftClient.cpp
+ create mode 100644 tutorial/cpp/GriftServer.cpp
+ create mode 100644 tutorial/cpp/test.thrift
+
+diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
+index 6c04899..1557241 100644
+--- a/compiler/cpp/src/generate/t_cpp_generator.cc
++++ b/compiler/cpp/src/generate/t_cpp_generator.cc
+@@ -162,6 +162,8 @@ public:
+                                  bool specialized = false);
+   void generate_function_helpers(t_service* tservice, t_function* tfunction);
+   void generate_service_async_skeleton(t_service* tservice);
++  void generate_service_stub_interface(t_service* tservice);
++  void generate_service_stub(t_service* tservice);
+ 
+   /**
+    * Serialization constructs
+@@ -883,10 +885,10 @@ void t_cpp_generator::generate_struct_declaration(ofstream& out,
+                                                   bool is_user_struct) {
+   string extends = "";
+   if (is_exception) {
+-    extends = " : public ::apache::thrift::TException";
++    extends = " : public apache::thrift::TException";
+   } else {
+-    if (is_user_struct && !gen_templates_) {
+-      extends = " : public virtual ::apache::thrift::TBase";
++    if (!gen_templates_) {
++      extends = " : public virtual apache::thrift::TBase";
+     }
+   }
+ 
+@@ -1130,9 +1132,15 @@ void t_cpp_generator::generate_struct_definition(ofstream& out,
+   vector<t_field*>::const_iterator m_iter;
+   const vector<t_field*>& members = tstruct->get_members();
+ 
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
++
+   // Destructor
+   if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
+-    force_cpp_out << endl << indent() << tstruct->get_name() << "::~" << tstruct->get_name()
++    force_cpp_out << endl << indent() << method_prefix <<
++    tstruct->get_name() << "::~" << tstruct->get_name()
+                   << "() throw() {" << endl;
+     indent_up();
+ 
+@@ -1145,12 +1153,14 @@ void t_cpp_generator::generate_struct_definition(ofstream& out,
+     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+       if (is_reference((*m_iter))) {
+         std::string type = type_name((*m_iter)->get_type());
+-        out << endl << indent() << "void " << tstruct->get_name() << "::__set_"
++        out << endl << indent() << "void " << method_prefix
++            << tstruct->get_name() << "::__set_"
+             << (*m_iter)->get_name() << "(boost::shared_ptr<"
+             << type_name((*m_iter)->get_type(), false, false) << ">";
+         out << " val) {" << endl;
+       } else {
+-        out << endl << indent() << "void " << tstruct->get_name() << "::__set_"
++        out << endl << indent() << "void " << method_prefix
++            << tstruct->get_name() << "::__set_"
+             << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type(), false, true);
+         out << " val) {" << endl;
+       }
+@@ -1177,11 +1187,16 @@ void t_cpp_generator::generate_struct_definition(ofstream& out,
+  * @param tstruct The struct
+  */
+ void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct, bool pointers) {
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
++
+   if (gen_templates_) {
+     out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+-        << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl;
++        << method_prefix << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl;
+   } else {
+-    indent(out) << "uint32_t " << tstruct->get_name()
++    indent(out) << "uint32_t " << method_prefix << tstruct->get_name()
+                 << "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl;
+   }
+   indent_up();
+@@ -1301,14 +1316,18 @@ void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct, b
+  */
+ void t_cpp_generator::generate_struct_writer(ofstream& out, t_struct* tstruct, bool pointers) {
+   string name = tstruct->get_name();
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
+   const vector<t_field*>& fields = tstruct->get_sorted_members();
+   vector<t_field*>::const_iterator f_iter;
+ 
+   if (gen_templates_) {
+     out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+-        << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
++        << method_prefix << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
+   } else {
+-    indent(out) << "uint32_t " << tstruct->get_name()
++    indent(out) << "uint32_t " << method_prefix << tstruct->get_name()
+                 << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+   }
+   indent_up();
+@@ -1369,14 +1388,18 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+                                                     t_struct* tstruct,
+                                                     bool pointers) {
+   string name = tstruct->get_name();
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
+   const vector<t_field*>& fields = tstruct->get_sorted_members();
+   vector<t_field*>::const_iterator f_iter;
+ 
+   if (gen_templates_) {
+     out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+-        << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
++        << method_prefix << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
+   } else {
+-    indent(out) << "uint32_t " << tstruct->get_name()
++    indent(out) << "uint32_t " << method_prefix << tstruct->get_name()
+                 << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+   }
+   indent_up();
+@@ -1385,18 +1408,7 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+ 
+   indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
+ 
+-  bool first = true;
+   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+-    if (first) {
+-      first = false;
+-      out << endl << indent() << "if ";
+-    } else {
+-      out << " else if ";
+-    }
+-
+-    out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
+-
+-    indent_up();
+ 
+     // Write field header
+     out << indent() << "xfer += oprot->writeFieldBegin("
+@@ -1410,9 +1422,6 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+     }
+     // Write field closer
+     indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
+-
+-    indent_down();
+-    indent(out) << "}";
+   }
+ 
+   // Write the struct map
+@@ -1478,9 +1487,13 @@ void t_cpp_generator::generate_struct_ostream_operator(std::ofstream& out, t_str
+ }
+ 
+ void t_cpp_generator::generate_struct_print_method_decl(std::ofstream& out, t_struct* tstruct) {
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
+   out << "void ";
+   if (tstruct) {
+-    out << tstruct->get_name() << "::";
++    out << method_prefix << tstruct->get_name() << "::";
+   }
+   out << "printTo(std::ostream& out) const";
+ }
+@@ -1601,11 +1614,13 @@ void t_cpp_generator::generate_exception_what_method(std::ofstream& out, t_struc
+  */
+ void t_cpp_generator::generate_service(t_service* tservice) {
+   string svcname = tservice->get_name();
++  string ns = tservice->get_program()->get_namespace("cpp");
+ 
+   // Make output files
+-  string f_header_name = get_out_dir() + svcname + ".h";
++  string f_header_name = get_out_dir() + svcname + ".grpc.thrift.h";
+   f_header_.open(f_header_name.c_str());
+ 
++
+   // Print header file includes
+   f_header_ << autogen_comment();
+   f_header_ << "#ifndef " << svcname << "_H" << endl << "#define " << svcname << "_H" << endl
+@@ -1621,15 +1636,38 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     f_header_ << "#include <thrift/async/TAsyncDispatchProcessor.h>" << endl;
+   }
+   f_header_ << "#include <thrift/async/TConcurrentClientSyncInfo.h>" << endl;
++
+   f_header_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\""
+             << endl;
+ 
+   t_service* extends_service = tservice->get_extends();
+-  if (extends_service != NULL) {
++  if (extends_service) {
+     f_header_ << "#include \"" << get_include_prefix(*(extends_service->get_program()))
+-              << extends_service->get_name() << ".h\"" << endl;
++              << extends_service->get_name() << ".grpc.thrift.h\"" << endl;
+   }
+ 
++
++  f_header_  <<
++      "#include <grpc++/impl/codegen/async_stream.h>" << endl <<
++      "#include <grpc++/impl/codegen/async_unary_call.h>"  << endl <<
++      "#include <grpc++/impl/codegen/thrift_utils.h>" << endl <<
++      "#include <grpc++/impl/codegen/rpc_method.h>"  << endl <<
++      "#include <grpc++/impl/codegen/service_type.h>"  << endl <<
++      "#include <grpc++/impl/codegen/status.h>" << endl <<
++      "#include <grpc++/impl/codegen/stub_options.h>" << endl <<
++      "#include <grpc++/impl/codegen/sync_stream.h>" << endl;
++
++
++  f_header_  <<
++      endl <<
++      "namespace grpc {" << endl <<
++      "class CompletionQueue;"  << endl <<
++      "class Channel;"  << endl <<
++      "class RpcService;"  << endl <<
++      "class ServerCompletionQueue;"  << endl <<
++      "class ServerContext;" << endl <<
++      "}" << endl;
++
+   f_header_ << endl << ns_open_ << endl << endl;
+ 
+   f_header_ << "#ifdef _WIN32\n"
+@@ -1638,10 +1676,13 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+                "#endif\n\n";
+ 
+   // Service implementation file includes
+-  string f_service_name = get_out_dir() + svcname + ".cpp";
++  string f_service_name = get_out_dir() + svcname + ".grpc.thrift.cpp";
+   f_service_.open(f_service_name.c_str());
+   f_service_ << autogen_comment();
+-  f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl;
++
++  f_service_ << "#include \"" <<
++    get_include_prefix(*get_program()) << svcname << ".grpc.thrift.h\"" << endl;
++
+   if (gen_cob_style_) {
+     f_service_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl;
+   }
+@@ -1652,7 +1693,7 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     string f_service_tcc_name = get_out_dir() + svcname + ".tcc";
+     f_service_tcc_.open(f_service_tcc_name.c_str());
+     f_service_tcc_ << autogen_comment();
+-    f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\""
++    f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".grpc.thrift.h\""
+                    << endl;
+ 
+     f_service_tcc_ << "#ifndef " << svcname << "_TCC" << endl << "#define " << svcname << "_TCC"
+@@ -1663,19 +1704,69 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     }
+   }
+ 
++  f_service_ <<
++    endl <<
++    "#include <grpc++/impl/codegen/async_stream.h>" << endl <<
++    "#include <grpc++/impl/codegen/async_unary_call.h>" << endl <<
++    "#include <grpc++/impl/codegen/channel_interface.h>" << endl <<
++    "#include <grpc++/impl/codegen/client_unary_call.h>" << endl <<
++    "#include <grpc++/impl/codegen/method_handler_impl.h>" << endl <<
++    "#include <grpc++/impl/codegen/rpc_service_method.h>" << endl <<
++    "#include <grpc++/impl/codegen/service_type.h>" << endl <<
++    "#include <grpc++/impl/codegen/sync_stream.h>" << endl <<
++    endl;
++
+   f_service_ << endl << ns_open_ << endl << endl;
+   f_service_tcc_ << endl << ns_open_ << endl << endl;
+ 
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++
++  f_service_ <<
++    "static const char* " << service_name_ << "_method_names[] = {" << endl;
++
++
++  indent_up();
++
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "\"/" << ns << "." << service_name_ << "/" << (*f_iter)->get_name() << "\"," << endl;
++  }
++
++
++  t_service* service_iter = extends_service;  
++  while (service_iter) {
++    vector<t_function*> functions = service_iter->get_functions();
++    vector<t_function*>::iterator f_iter;
++
++    for ( f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++      indent() << "\"/" << service_iter->get_program()->get_namespace("cpp") <<
++      "." << service_iter->get_name() << "/" << (*f_iter)->get_name() << "\"," << endl;
++    }
++    service_iter = service_iter->get_extends();
++  }
++
++  indent_down();
++  f_service_ <<
++  "};" << endl;
++
++  // Generate service class
++  if ( extends_service) {
++    f_header_ << "class " << service_name_ << " : public " <<
++      type_name(extends_service) << " {" << endl <<
++      "public:" << endl;
++  }
++  else {
++    f_header_ << "class " << service_name_ << "{" << endl <<
++      "public:" << endl;
++  }
++
+   // Generate all the components
+-  generate_service_interface(tservice, "");
+-  generate_service_interface_factory(tservice, "");
+-  generate_service_null(tservice, "");
+   generate_service_helpers(tservice);
+-  generate_service_client(tservice, "");
+-  generate_service_processor(tservice, "");
+-  generate_service_multiface(tservice);
+-  generate_service_skeleton(tservice);
+-  generate_service_client(tservice, "Concurrent");
++  generate_service_interface(tservice, "");
++  generate_service_stub_interface(tservice);
++  generate_service_stub(tservice);
+ 
+   // Generate all the cob components
+   if (gen_cob_style_) {
+@@ -1688,10 +1779,14 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     generate_service_async_skeleton(tservice);
+   }
+ 
++   // Close service class
++  f_header_ << "};" << endl;
++
+   f_header_ << "#ifdef _WIN32\n"
+                "  #pragma warning( pop )\n"
+                "#endif\n\n";
+ 
++
+   // Close the namespace
+   f_service_ << ns_close_ << endl << endl;
+   f_service_tcc_ << ns_close_ << endl << endl;
+@@ -1729,15 +1824,11 @@ void t_cpp_generator::generate_service_helpers(t_service* tservice) {
+     string name_orig = ts->get_name();
+ 
+     // TODO(dreiss): Why is this stuff not in generate_function_helpers?
+-    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
++    ts->set_name((*f_iter)->get_name() + "Req");
+     generate_struct_declaration(f_header_, ts, false);
+-    generate_struct_definition(out, f_service_, ts, false);
++    generate_struct_definition(out, f_service_, ts, true);
+     generate_struct_reader(out, ts);
+     generate_struct_writer(out, ts);
+-    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
+-    generate_struct_declaration(f_header_, ts, false, true, false, true);
+-    generate_struct_definition(out, f_service_, ts, false);
+-    generate_struct_writer(out, ts, true);
+     ts->set_name(name_orig);
+ 
+     generate_function_helpers(tservice, *f_iter);
+@@ -1745,13 +1836,218 @@ void t_cpp_generator::generate_service_helpers(t_service* tservice) {
+ }
+ 
+ /**
++ *  Generates a service Stub Interface
++ *
++ * @param tservice The service to generate a stub for.
++ *
++ */
++void t_cpp_generator::generate_service_stub_interface(t_service* tservice) {
++
++    string extends = "";
++    if (tservice->get_extends()) {
++      extends = " : virtual public " + type_name(tservice->get_extends()) + "::StubInterface";
++    }
++
++    f_header_ <<
++    endl <<
++    "class StubInterface " << extends << " {" << endl;
++    indent_up();
++    f_header_ <<
++    " public:" << endl <<
++    indent() << "virtual ~StubInterface() {}" << endl;
++
++    vector<t_function*> functions = tservice->get_functions();
++    vector<t_function*>::iterator f_iter;
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_header_ <<
++        indent() << "virtual ::grpc::Status " << function_name <<
++        "(::grpc::ClientContext* context, const " << function_name <<
++        "Req& request, " << function_name << "Resp* response) = 0;" << endl;
++    }
++    indent_down();
++    f_header_ <<
++      "};" << endl << endl;
++
++}
++void t_cpp_generator::generate_service_stub(t_service* tservice) {
++    f_header_ <<
++    endl <<
++    "class Stub : public StubInterface {" <<
++    endl;
++
++    indent_up();
++    f_header_ <<
++    " public:" << endl <<
++    indent() << "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);" <<
++    endl;
++
++    vector<t_function*> functions = tservice->get_functions();
++    vector<t_function*>::iterator f_iter;
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_header_ <<
++        indent() << "::grpc::Status " << function_name <<
++        "(::grpc::ClientContext* context, const " << function_name <<
++        "Req& request, " << function_name << "Resp* response) override;" << endl;
++    }
++
++    t_service* extends_service = tservice->get_extends();
++    t_service* service_iter = extends_service;
++    while (service_iter) {
++      // generate inherited methods
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++        string function_name = (*f_iter)->get_name();
++        f_header_ <<
++          indent() << "::grpc::Status " << function_name <<
++          "(::grpc::ClientContext* context, const " << function_name <<
++          "Req& request, " << function_name << "Resp* response) override;" << endl;
++      }
++      service_iter = service_iter->get_extends();
++    }
++
++    f_header_ <<
++    endl <<
++    " private:" << endl <<
++    indent() << "std::shared_ptr< ::grpc::ChannelInterface> channel_;" <<
++    endl;
++
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_header_ <<
++        indent() << "const ::grpc::RpcMethod rpcmethod_" << (*f_iter)->get_name() << "_;" << endl;
++    }
++
++    service_iter = extends_service;
++    while (service_iter) {
++      // generate inherited methods
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++        f_header_ <<
++          indent() << "const ::grpc::RpcMethod rpcmethod_" << (*f_iter)->get_name() << "_;" << endl;
++      }
++      service_iter = service_iter->get_extends();
++    }
++
++    indent_down();
++    f_header_ <<
++      "};" << endl << endl;
++
++    // generate the implementaion of Stub
++    f_service_ <<
++      endl <<
++      service_name_ << "::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel)" << endl;
++
++    indent_up();
++    f_service_ <<
++    indent() << ": channel_(channel)" << endl;
++    int i=0;
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter , ++i) {
++      f_service_ <<
++        indent() <<
++        ", rpcmethod_" << (*f_iter)->get_name() << "_(" <<
++        service_name_ << "_method_names[" << i << "], ::grpc::RpcMethod::NORMAL_RPC, channel)" << endl;
++    }
++
++    service_iter = extends_service;
++    while (service_iter) {
++      // generate inherited methods
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter, ++i) {
++        f_service_ <<
++        indent() <<
++        ", rpcmethod_" << (*f_iter)->get_name() << "_(" <<
++        service_name_ << "_method_names[" << i << "], ::grpc::RpcMethod::NORMAL_RPC, channel)" << endl;
++      }
++      service_iter = service_iter->get_extends();
++    }
++    f_service_ <<
++    indent() << "{}" << endl;
++    indent_down();
++
++    // generate NewStub
++    f_header_ <<
++    endl <<
++    "static std::unique_ptr<Stub> NewStub(const std::shared_ptr\
++    < ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());" <<
++    endl;
++
++    // generate NewStub Implementation
++    f_service_ <<
++    endl <<
++    "std::unique_ptr< " << service_name_ << "::Stub> " << service_name_ << "::NewStub(const std::shared_ptr\
++    < ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {" << endl;
++
++    indent_up();
++    f_service_ <<
++    indent() << "std::unique_ptr< " << service_name_ << "::Stub> stub(new " << service_name_ <<
++    "::Stub(channel));" << endl <<
++    indent() << "return stub;" << endl;
++    indent_down();
++    f_service_ <<
++    "}" << endl;
++
++    // generate stub methods
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_service_ <<
++        endl <<
++        "::grpc::Status " << service_name_ << "::Stub::" <<  function_name <<
++        "(::grpc::ClientContext* context, const " << service_name_ << "::" <<
++        function_name << "Req& request, " << service_name_ << "::" <<
++        function_name << "Resp* response) {" << endl;
++
++      indent_up();
++      f_service_ <<
++      indent() << "return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_" <<
++      function_name << "_, context, request, response);" << endl;
++      indent_down();
++
++      f_service_ <<
++      "}" << endl;
++
++    }
++
++    service_iter = extends_service;
++    while (service_iter) {
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++        string function_name = (*f_iter)->get_name();
++        f_service_ <<
++          endl <<
++          "::grpc::Status " << service_name_ << "::Stub::" <<  function_name <<
++          "(::grpc::ClientContext* context, const " << service_name_ << "::" <<
++          function_name << "Req& request, " << service_name_ << "::" <<
++          function_name << "Resp* response) {" << endl;
++
++        indent_up();
++        f_service_ <<
++        indent() << "return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_" <<
++        function_name << "_, context, request, response);" << endl;
++        indent_down();
++
++        f_service_ <<
++        "}" << endl;
++
++      }
++      service_iter = service_iter->get_extends();
++    }
++
++}
++
++
++/**
+  * Generates a service interface definition.
+  *
+  * @param tservice The service to generate a header definition for
+  */
+ void t_cpp_generator::generate_service_interface(t_service* tservice, string style) {
+ 
+-  string service_if_name = service_name_ + style + "If";
++  string service_if_name = "Service";
+   if (style == "CobCl") {
+     // Forward declare the client.
+     string client_name = service_name_ + "CobClient";
+@@ -1764,13 +2060,15 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+   }
+ 
+   string extends = "";
+-  if (tservice->get_extends() != NULL) {
+-    extends = " : virtual public " + type_name(tservice->get_extends()) + style + "If";
++  if (tservice->get_extends()) {
++    extends = " : virtual public " + type_name(tservice->get_extends()) + style + "::Service";
+     if (style == "CobCl" && gen_templates_) {
+       // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
+       // parent services were also generated with templates enabled.
+       extends += "T<Protocol_>";
+     }
++  } else {
++    extends = " : public ::grpc::Service";
+   }
+ 
+   if (style == "CobCl" && gen_templates_) {
+@@ -1778,7 +2076,9 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+   }
+   f_header_ << "class " << service_if_name << extends << " {" << endl << " public:" << endl;
+   indent_up();
+-  f_header_ << indent() << "virtual ~" << service_if_name << "() {}" << endl;
++
++  f_header_ << indent() << "Service();" << endl;
++  f_header_ << indent() << "virtual ~Service();" << endl;
+ 
+   vector<t_function*> functions = tservice->get_functions();
+   vector<t_function*>::iterator f_iter;
+@@ -1786,7 +2086,12 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+     if ((*f_iter)->has_doc())
+       f_header_ << endl;
+     generate_java_doc(f_header_, *f_iter);
+-    f_header_ << indent() << "virtual " << function_signature(*f_iter, style) << " = 0;" << endl;
++
++    string function_name = (*f_iter)->get_name();
++    f_header_ <<
++      indent() << "virtual ::grpc::Status " << function_name <<
++      "(::grpc::ServerContext* context, const "<< function_name <<
++      "Req* request, "<< function_name << "Resp* response);" << endl;
+   }
+   indent_down();
+   f_header_ << "};" << endl << endl;
+@@ -1797,6 +2102,66 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+     f_header_ << "typedef " << service_if_name << "< ::apache::thrift::protocol::TProtocol> "
+               << service_name_ << style << "If;" << endl << endl;
+   }
++
++   // generate the service interface implementations
++
++    f_service_ <<
++    endl <<
++    service_name_ << "::Service::Service() {" << endl;
++    indent_up();
++    f_service_ <<
++    indent() << "(void)" << service_name_ << "_method_names;" << endl;
++    uint32_t i=0;
++    for(i=0;i<functions.size(); i++) {
++      string function_name = functions[i]->get_name();
++      f_service_ <<
++        endl <<
++        indent() << "AddMethod(new ::grpc::RpcServiceMethod(" << endl;
++        indent_up();
++
++      f_service_ <<
++        indent() << service_name_ << "_method_names[" << i << "]," << endl <<
++        indent() << "::grpc::RpcMethod::NORMAL_RPC," << endl <<
++        indent() << "new ::grpc::RpcMethodHandler< " << service_name_ << "::Service, " <<
++        service_name_ << "::" << function_name << "Req, " << service_name_ << "::" <<
++        function_name << "Resp>(" << endl;
++
++      indent_up();
++      f_service_ <<
++        indent() << "std::mem_fn(&" << service_name_ << "::Service::" << function_name << "), this)));" << endl;
++
++      indent_down();
++      indent_down();
++    }
++
++    indent_down();
++    f_service_ <<
++    "}" << endl;
++
++    f_service_ <<
++    endl <<
++    service_name_ << "::Service::~Service() {" << endl <<
++    "}" << endl;
++
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_service_ <<
++        endl <<
++        "::grpc::Status " << service_name_ << "::Service::" << function_name <<
++        "(::grpc::ServerContext* context, const " << service_name_ << "::" << function_name <<
++        "Req* request, " << service_name_ << "::" << function_name << "Resp* response) {" << endl;
++      indent_up();
++      f_service_ <<
++      indent() << "(void) context;" << endl <<
++      indent() << "(void) request;" << endl <<
++      indent() << "(void) response;" << endl <<
++      indent() << "return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED,\"\");" << endl;
++      indent_down();
++
++      f_service_ <<
++      "}" << endl;
++    }
++
+ }
+ 
+ /**
+@@ -3095,7 +3460,7 @@ void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function*
+ 
+   std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
+ 
+-  t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result");
++  t_struct result(program_, tfunction->get_name() + "Resp");
+   t_field success(tfunction->get_returntype(), "success", 0);
+   if (!tfunction->get_returntype()->is_void()) {
+     result.append(&success);
+@@ -3109,17 +3474,9 @@ void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function*
+   }
+ 
+   generate_struct_declaration(f_header_, &result, false);
+-  generate_struct_definition(out, f_service_, &result, false);
++  generate_struct_definition(out, f_service_, &result, true);
+   generate_struct_reader(out, &result);
+   generate_struct_result_writer(out, &result);
+-
+-  result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
+-  generate_struct_declaration(f_header_, &result, false, true, true, gen_cob_style_);
+-  generate_struct_definition(out, f_service_, &result, false);
+-  generate_struct_reader(out, &result, true);
+-  if (gen_cob_style_) {
+-    generate_struct_writer(out, &result, true);
+-  }
+ }
+ 
+ /**
+@@ -3162,8 +3519,8 @@ void t_cpp_generator::generate_process_function(t_service* tservice,
+         << endl;
+     scope_up(out);
+ 
+-    string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
+-    string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
++    string argsname = tfunction->get_name() + "Req";
++    string resultname = tfunction->get_name() + "Resp";
+ 
+     if (tfunction->is_oneway() && !unnamed_oprot_seqid) {
+       out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl;
+@@ -3320,7 +3677,7 @@ void t_cpp_generator::generate_process_function(t_service* tservice,
+       out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl;
+     }
+ 
+-    out << indent() << tservice->get_name() + "_" + tfunction->get_name() << "_args args;" << endl
++    out << indent() << tfunction->get_name() << "Req args;" << endl
+         << indent() << "void* ctx = NULL;" << endl << indent()
+         << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+         << "  ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl
+@@ -3487,7 +3844,7 @@ void t_cpp_generator::generate_process_function(t_service* tservice,
+           << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl;
+ 
+       // Throw the TDelayedException, and catch the result
+-      out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_result result;"
++      out << indent() << tfunction->get_name() << "Resp result;"
+           << endl << endl << indent() << "try {" << endl;
+       indent_up();
+       out << indent() << "_throw->throw_it();" << endl << indent() << "return cob(false);"
+diff --git a/tutorial/cpp/CMakeLists.txt b/tutorial/cpp/CMakeLists.txt
+deleted file mode 100644
+index 8a3d085..0000000
+--- a/tutorial/cpp/CMakeLists.txt
++++ /dev/null
+@@ -1,53 +0,0 @@
+-#
+-# 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.
+-#
+-
+-find_package(Boost 1.53.0 REQUIRED)
+-include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+-
+-#Make sure gen-cpp files can be included
+-include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+-include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
+-include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
+-
+-include(ThriftMacros)
+-
+-set(tutorialgencpp_SOURCES 
+-    gen-cpp/Calculator.cpp
+-    gen-cpp/SharedService.cpp
+-    gen-cpp/shared_constants.cpp
+-    gen-cpp/shared_types.cpp
+-    gen-cpp/tutorial_constants.cpp
+-    gen-cpp/tutorial_types.cpp
+-)
+-add_library(tutorialgencpp STATIC ${tutorialgencpp_SOURCES})
+-LINK_AGAINST_THRIFT_LIBRARY(tutorialgencpp thrift)
+-
+-add_custom_command(OUTPUT gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp
+-    COMMAND ${THRIFT_COMPILER} --gen cpp -r ${PROJECT_SOURCE_DIR}/tutorial/tutorial.thrift
+-)
+-
+-add_executable(TutorialServer CppServer.cpp)
+-target_link_libraries(TutorialServer tutorialgencpp)
+-LINK_AGAINST_THRIFT_LIBRARY(TutorialServer thrift)
+-target_link_libraries(TutorialServer ${ZLIB_LIBRARIES})
+-
+-add_executable(TutorialClient CppClient.cpp)
+-target_link_libraries(TutorialClient tutorialgencpp)
+-LINK_AGAINST_THRIFT_LIBRARY(TutorialClient thrift)
+-target_link_libraries(TutorialClient ${ZLIB_LIBRARIES})
+diff --git a/tutorial/cpp/CppClient.cpp b/tutorial/cpp/CppClient.cpp
+deleted file mode 100644
+index 2763fee..0000000
+--- a/tutorial/cpp/CppClient.cpp
++++ /dev/null
+@@ -1,80 +0,0 @@
+-/*
+- * 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.
+- */
+-
+-#include <iostream>
+-
+-#include <thrift/protocol/TBinaryProtocol.h>
+-#include <thrift/transport/TSocket.h>
+-#include <thrift/transport/TTransportUtils.h>
+-
+-#include "../gen-cpp/Calculator.h"
+-
+-using namespace std;
+-using namespace apache::thrift;
+-using namespace apache::thrift::protocol;
+-using namespace apache::thrift::transport;
+-
+-using namespace tutorial;
+-using namespace shared;
+-
+-int main() {
+-  boost::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
+-  boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
+-  boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
+-  CalculatorClient client(protocol);
+-
+-  try {
+-    transport->open();
+-
+-    client.ping();
+-    cout << "ping()" << endl;
+-
+-    cout << "1 + 1 = " << client.add(1, 1) << endl;
+-
+-    Work work;
+-    work.op = Operation::DIVIDE;
+-    work.num1 = 1;
+-    work.num2 = 0;
+-
+-    try {
+-      client.calculate(1, work);
+-      cout << "Whoa? We can divide by zero!" << endl;
+-    } catch (InvalidOperation& io) {
+-      cout << "InvalidOperation: " << io.why << endl;
+-      // or using generated operator<<: cout << io << endl;
+-      // or by using std::exception native method what(): cout << io.what() << endl;
+-    }
+-
+-    work.op = Operation::SUBTRACT;
+-    work.num1 = 15;
+-    work.num2 = 10;
+-    int32_t diff = client.calculate(1, work);
+-    cout << "15 - 10 = " << diff << endl;
+-
+-    // Note that C++ uses return by reference for complex types to avoid
+-    // costly copy construction
+-    SharedStruct ss;
+-    client.getStruct(ss, 1);
+-    cout << "Received log: " << ss << endl;
+-
+-    transport->close();
+-  } catch (TException& tx) {
+-    cout << "ERROR: " << tx.what() << endl;
+-  }
+-}
+diff --git a/tutorial/cpp/CppServer.cpp b/tutorial/cpp/CppServer.cpp
+deleted file mode 100644
+index eafffa9..0000000
+--- a/tutorial/cpp/CppServer.cpp
++++ /dev/null
+@@ -1,181 +0,0 @@
+-/*
+- * 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.
+- */
+-
+-#include <thrift/concurrency/ThreadManager.h>
+-#include <thrift/concurrency/PlatformThreadFactory.h>
+-#include <thrift/protocol/TBinaryProtocol.h>
+-#include <thrift/server/TSimpleServer.h>
+-#include <thrift/server/TThreadPoolServer.h>
+-#include <thrift/server/TThreadedServer.h>
+-#include <thrift/transport/TServerSocket.h>
+-#include <thrift/transport/TSocket.h>
+-#include <thrift/transport/TTransportUtils.h>
+-#include <thrift/TToString.h>
+-
+-#include <boost/make_shared.hpp>
+-
+-#include <iostream>
+-#include <stdexcept>
+-#include <sstream>
+-
+-#include "../gen-cpp/Calculator.h"
+-
+-using namespace std;
+-using namespace apache::thrift;
+-using namespace apache::thrift::concurrency;
+-using namespace apache::thrift::protocol;
+-using namespace apache::thrift::transport;
+-using namespace apache::thrift::server;
+-
+-using namespace tutorial;
+-using namespace shared;
+-
+-class CalculatorHandler : public CalculatorIf {
+-public:
+-  CalculatorHandler() {}
+-
+-  void ping() { cout << "ping()" << endl; }
+-
+-  int32_t add(const int32_t n1, const int32_t n2) {
+-    cout << "add(" << n1 << ", " << n2 << ")" << endl;
+-    return n1 + n2;
+-  }
+-
+-  int32_t calculate(const int32_t logid, const Work& work) {
+-    cout << "calculate(" << logid << ", " << work << ")" << endl;
+-    int32_t val;
+-
+-    switch (work.op) {
+-    case Operation::ADD:
+-      val = work.num1 + work.num2;
+-      break;
+-    case Operation::SUBTRACT:
+-      val = work.num1 - work.num2;
+-      break;
+-    case Operation::MULTIPLY:
+-      val = work.num1 * work.num2;
+-      break;
+-    case Operation::DIVIDE:
+-      if (work.num2 == 0) {
+-        InvalidOperation io;
+-        io.whatOp = work.op;
+-        io.why = "Cannot divide by 0";
+-        throw io;
+-      }
+-      val = work.num1 / work.num2;
+-      break;
+-    default:
+-      InvalidOperation io;
+-      io.whatOp = work.op;
+-      io.why = "Invalid Operation";
+-      throw io;
+-    }
+-
+-    SharedStruct ss;
+-    ss.key = logid;
+-    ss.value = to_string(val);
+-
+-    log[logid] = ss;
+-
+-    return val;
+-  }
+-
+-  void getStruct(SharedStruct& ret, const int32_t logid) {
+-    cout << "getStruct(" << logid << ")" << endl;
+-    ret = log[logid];
+-  }
+-
+-  void zip() { cout << "zip()" << endl; }
+-
+-protected:
+-  map<int32_t, SharedStruct> log;
+-};
+-
+-/*
+-  CalculatorIfFactory is code generated.
+-  CalculatorCloneFactory is useful for getting access to the server side of the
+-  transport.  It is also useful for making per-connection state.  Without this
+-  CloneFactory, all connections will end up sharing the same handler instance.
+-*/
+-class CalculatorCloneFactory : virtual public CalculatorIfFactory {
+- public:
+-  virtual ~CalculatorCloneFactory() {}
+-  virtual CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo)
+-  {
+-    boost::shared_ptr<TSocket> sock = boost::dynamic_pointer_cast<TSocket>(connInfo.transport);
+-    cout << "Incoming connection\n";
+-    cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
+-    cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
+-    cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
+-    cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
+-    return new CalculatorHandler;
+-  }
+-  virtual void releaseHandler( ::shared::SharedServiceIf* handler) {
+-    delete handler;
+-  }
+-};
+-
+-int main() {
+-  TThreadedServer server(
+-    boost::make_shared<CalculatorProcessorFactory>(boost::make_shared<CalculatorCloneFactory>()),
+-    boost::make_shared<TServerSocket>(9090), //port
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>());
+-
+-  /*
+-  // if you don't need per-connection state, do the following instead
+-  TThreadedServer server(
+-    boost::make_shared<CalculatorProcessor>(boost::make_shared<CalculatorHandler>()),
+-    boost::make_shared<TServerSocket>(9090), //port
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>());
+-  */
+-
+-  /**
+-   * Here are some alternate server types...
+-
+-  // This server only allows one connection at a time, but spawns no threads
+-  TSimpleServer server(
+-    boost::make_shared<CalculatorProcessor>(boost::make_shared<CalculatorHandler>()),
+-    boost::make_shared<TServerSocket>(9090),
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>());
+-
+-  const int workerCount = 4;
+-
+-  boost::shared_ptr<ThreadManager> threadManager =
+-    ThreadManager::newSimpleThreadManager(workerCount);
+-  threadManager->threadFactory(
+-    boost::make_shared<PlatformThreadFactory>());
+-  threadManager->start();
+-
+-  // This server allows "workerCount" connection at a time, and reuses threads
+-  TThreadPoolServer server(
+-    boost::make_shared<CalculatorProcessorFactory>(boost::make_shared<CalculatorCloneFactory>()),
+-    boost::make_shared<TServerSocket>(9090),
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>(),
+-    threadManager);
+-  */
+-
+-  cout << "Starting the server..." << endl;
+-  server.serve();
+-  cout << "Done." << endl;
+-  return 0;
+-}
+diff --git a/tutorial/cpp/GriftClient.cpp b/tutorial/cpp/GriftClient.cpp
+new file mode 100644
+index 0000000..647a683
+--- /dev/null
++++ b/tutorial/cpp/GriftClient.cpp
+@@ -0,0 +1,93 @@
++/*
++ *
++ * Copyright 2016, Google Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are
++ * met:
++ *
++ *     * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other materials provided with the
++ * distribution.
++ *     * Neither the name of Google Inc. nor the names of its
++ * contributors may be used to endorse or promote products derived from
++ * this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ */
++
++#include <iostream>
++#include <memory>
++#include <string>
++
++#include <grpc++/grpc++.h>
++
++#include "gen-cpp/Greeter.grpc.thrift.h"
++
++using grpc::Channel;
++using grpc::ClientContext;
++using grpc::Status;
++using test::Greeter;
++
++class GreeterClient {
++ public:
++  GreeterClient(std::shared_ptr<Channel> channel)
++      : stub_(Greeter::NewStub(channel)) {}
++
++  // Assembles the client's payload, sends it and presents the response back
++  // from the server.
++  std::string SayHello(const std::string& user) {
++    // Data we are sending to the server.
++    Greeter::SayHelloReq req;
++    req.request.name = user;
++
++    // Container for the data we expect from the server.
++    Greeter::SayHelloResp reply;
++
++    // Context for the client. It could be used to convey extra information to
++    // the server and/or tweak certain RPC behaviors.
++    ClientContext context;
++
++    // The actual RPC.
++    Status status = stub_->SayHello(&context, req, &reply);
++
++    // Act upon its status.
++    if (status.ok()) {
++      return reply.success.message;
++    } else {
++      return "RPC failed";
++    }
++  }
++
++ private:
++  std::unique_ptr<Greeter::Stub> stub_;
++};
++
++int main() {
++  // Instantiate the client. It requires a channel, out of which the actual RPCs
++  // are created. This channel models a connection to an endpoint (in this case,
++  // localhost at port 50051). We indicate that the channel isn't authenticated
++  // (use of InsecureChannelCredentials()).
++  GreeterClient greeter(grpc::CreateChannel(
++      "localhost:50051", grpc::InsecureChannelCredentials()));
++  std::string user("world");
++  std::string reply = greeter.SayHello(user);
++  std::cout << "Greeter received: " << reply << std::endl;
++
++  return 0;
++}
+diff --git a/tutorial/cpp/GriftServer.cpp b/tutorial/cpp/GriftServer.cpp
+new file mode 100644
+index 0000000..7c01606
+--- /dev/null
++++ b/tutorial/cpp/GriftServer.cpp
+@@ -0,0 +1,93 @@
++/*
++ *
++ * Copyright 2016, Google Inc.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are
++ * met:
++ *
++ *     * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *     * Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other materials provided with the
++ * distribution.
++ *     * Neither the name of Google Inc. nor the names of its
++ * contributors may be used to endorse or promote products derived from
++ * this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ */
++
++#include <iostream>
++#include <memory>
++#include <string>
++
++#include <grpc++/grpc++.h>
++
++#include "gen-cpp/Greeter.grpc.thrift.h"
++#include <grpc++/server_builder.h>
++
++using grpc::Server;
++using grpc::ServerBuilder;
++using grpc::ServerContext;
++using grpc::Status;
++using test::Greeter;
++
++// Logic and data behind the server's behavior.
++class GreeterServiceImpl final : public Greeter::Service {
++ public:
++  ~GreeterServiceImpl() {
++    // shutdown server
++    server->Shutdown();
++  }
++
++  Status SayHello(ServerContext* context,const Greeter::SayHelloReq* request,
++                  Greeter::SayHelloResp* reply) override {
++    std::string prefix("Hello ");
++
++    reply->success.message = prefix + request->request.name;
++
++    return Status::OK;
++  }
++
++  void RunServer() {
++    std::string server_address("0.0.0.0:50051");
++
++    ServerBuilder builder;
++    // Listen on the given address without any authentication mechanism.
++    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
++    // Register "service" as the instance through which we'll communicate with
++    // clients. In this case it corresponds to an *synchronous* service.
++    builder.RegisterService(this);
++    // Finally assemble the server.
++    server = builder.BuildAndStart();
++    std::cout << "Server listening on " << server_address << std::endl;
++
++    // Wait for the server to shutdown. Note that some other thread must be
++    // responsible for shutting down the server for this call to ever return.
++    server->Wait();
++  }
++
++ private:
++  std::unique_ptr<Server> server;
++};
++
++int main() {
++  GreeterServiceImpl service;
++  service.RunServer();
++
++  return 0;
++}
+diff --git a/tutorial/cpp/Makefile.am b/tutorial/cpp/Makefile.am
+index 184a69d..6f91e28 100755
+--- a/tutorial/cpp/Makefile.am
++++ b/tutorial/cpp/Makefile.am
+@@ -18,44 +18,38 @@
+ #
+ AUTOMAKE_OPTIONS = subdir-objects serial-tests
+ 
+-BUILT_SOURCES = gen-cpp/shared_types.cpp \
+-                gen-cpp/tutorial_types.cpp
++BUILT_SOURCES = gen-cpp/test_types.cpp
+ 
+-noinst_LTLIBRARIES = libtutorialgencpp.la
+-nodist_libtutorialgencpp_la_SOURCES = \
+-	gen-cpp/Calculator.cpp \
+-	gen-cpp/Calculator.h \
+-	gen-cpp/SharedService.cpp \
+-	gen-cpp/SharedService.h \
+-	gen-cpp/shared_constants.cpp \
+-	gen-cpp/shared_constants.h \
+-	gen-cpp/shared_types.cpp \
+-	gen-cpp/shared_types.h \
+-	gen-cpp/tutorial_constants.cpp \
+-	gen-cpp/tutorial_constants.h \
+-	gen-cpp/tutorial_types.cpp \
+-	gen-cpp/tutorial_types.h
++#noinst_LTLIBRARIES = libtutorialgencpp.la
++noinst_LTLIBRARIES = libtestgencpp.la
++nodist_libtestgencpp_la_SOURCES = \
++	gen-cpp/Greeter.grpc.thrift.cpp \
++	gen-cpp/Greeter.grpc.thrift.h \
++	gen-cpp/test_constants.cpp \
++	gen-cpp/test_constants.h \
++	gen-cpp/test_types.cpp \
++	gen-cpp/test_types.h
+ 
+ 
+ 
+-libtutorialgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
++libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
+ 
+ noinst_PROGRAMS = \
+-	TutorialServer \
+-	TutorialClient
++	TestServer \
++	TestClient
+ 
+-TutorialServer_SOURCES = \
+-	CppServer.cpp
++TestServer_SOURCES = \
++	GriftServer.cpp
+ 
+-TutorialServer_LDADD = \
+-	libtutorialgencpp.la \
++TestServer_LDADD = \
++	libtestgencpp.la \
+ 	$(top_builddir)/lib/cpp/libthrift.la
+ 
+-TutorialClient_SOURCES = \
+-	CppClient.cpp
++TestClient_SOURCES = \
++	GriftClient.cpp
+ 
+-TutorialClient_LDADD = \
+-	libtutorialgencpp.la \
++TestClient_LDADD = \
++	libtestgencpp.la \
+ 	$(top_builddir)/lib/cpp/libthrift.la
+ 
+ #
+@@ -63,26 +57,26 @@ TutorialClient_LDADD = \
+ #
+ THRIFT = $(top_builddir)/compiler/cpp/thrift
+ 
+-gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp: $(top_srcdir)/tutorial/tutorial.thrift
++gen-cpp/Greeter.grpc.thrift.cpp gen-cpp/test_constants.cpp gen-cpp/test_types.cpp: $(top_srcdir)/tutorial/cpp/test.thrift
+ 	$(THRIFT) --gen cpp -r $<
+ 
+ AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp
+ AM_CXXFLAGS = -Wall -Wextra -pedantic
+-AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS)
++AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) `pkg-config --libs grpc++ grpc` -lpthread -ldl -lgrpc
+ 
+ clean-local:
+-	$(RM) gen-cpp/*
++	$(RM) -r gen-cpp
+ 
+-tutorialserver: all
+-	./TutorialServer
++testserver: all
++	./TestServer
+ 
+-tutorialclient: all
+-	./TutorialClient
++testclient: all
++	./TestClient
+ 
+ style-local:
+ 	$(CPPSTYLE_CMD)
+ 
+ EXTRA_DIST = \
+ 	CMakeLists.txt \
+-	CppClient.cpp \
+-	CppServer.cpp
++	GriftClient.cpp \
++	GriftServer.cpp
+diff --git a/tutorial/cpp/test.thrift b/tutorial/cpp/test.thrift
+new file mode 100644
+index 0000000..de3c9a4
+--- /dev/null
++++ b/tutorial/cpp/test.thrift
+@@ -0,0 +1,13 @@
++namespace cpp test
++
++struct HelloRequest {
++	1:string name
++}
++
++struct HelloResponse {
++	1:string message
++}
++
++service Greeter {
++	HelloResponse SayHello(1:HelloRequest request);
++}
+\ No newline at end of file
+-- 
+2.8.0.rc3.226.g39d4020
+
+
+From 3e4d75a2e2c474ee7700e7c9acaf89fdb768bedc Mon Sep 17 00:00:00 2001
+From: chedeti <chedeti@google.com>
+Date: Sun, 31 Jul 2016 16:23:53 -0700
+Subject: [PATCH 3/3] grpc java plugins generator
+
+for examples refer to https://github.com/grpc/grpc-java/tree/master/examples/thrift
+---
+ compiler/cpp/src/generate/t_java_generator.cc | 906 +++++++++++++++++++++++++-
+ tutorial/Makefile.am                          |   8 +-
+ 2 files changed, 887 insertions(+), 27 deletions(-)
+
+diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
+index 2db8cb8..8b28fe2 100644
+--- a/compiler/cpp/src/generate/t_java_generator.cc
++++ b/compiler/cpp/src/generate/t_java_generator.cc
+@@ -97,10 +97,10 @@ public:
+         } else if(iter->second.compare("suppress") == 0) {
+           suppress_generated_annotations_ = true;
+         } else {
+-          throw "unknown option java:" + iter->first + "=" + iter->second; 
++          throw "unknown option java:" + iter->first + "=" + iter->second;
+         }
+       } else {
+-        throw "unknown option java:" + iter->first; 
++        throw "unknown option java:" + iter->first;
+       }
+     }
+ 
+@@ -195,6 +195,17 @@ public:
+   void generate_service_async_server(t_service* tservice);
+   void generate_process_function(t_service* tservice, t_function* tfunction);
+   void generate_process_async_function(t_service* tservice, t_function* tfunction);
++  void generate_service_impl_base(t_service* tservice);
++  void generate_method_descriptors(t_service* tservice);
++  void generate_stub(t_service* tservice);
++  void generate_blocking_stub(t_service* tservice);
++  void generate_future_stub(t_service* tservice);
++  void generate_method_ids(t_service* tservice);
++  void generate_method_handlers(t_service* tservice);
++  void generate_service_descriptors(t_service* tservice);
++  void generate_service_builder(t_service* tservice);
++  void generate_arg_ids(t_service* tservice);
++  void generate_message_factory(t_service* tservice);
+ 
+   void generate_java_union(t_struct* tstruct);
+   void generate_union_constructor(ofstream& out, t_struct* tstruct);
+@@ -307,6 +318,8 @@ public:
+   std::string java_package();
+   std::string java_type_imports();
+   std::string java_suppressions();
++  std::string grpc_imports();
++  std::string import_extended_service(t_service* tservice);
+   std::string type_name(t_type* ttype,
+                         bool in_container = false,
+                         bool in_init = false,
+@@ -368,7 +381,7 @@ private:
+   bool use_option_type_;
+   bool undated_generated_annotations_;
+   bool suppress_generated_annotations_;
+-  
++
+ };
+ 
+ /**
+@@ -456,6 +469,35 @@ string t_java_generator::java_suppressions() {
+   return "@SuppressWarnings({\"cast\", \"rawtypes\", \"serial\", \"unchecked\", \"unused\"})\n";
+ }
+ 
++string t_java_generator::grpc_imports() {
++  return
++    string() +
++    "import static io.grpc.stub.ClientCalls.asyncUnaryCall;\n" +
++    "import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.blockingUnaryCall;\n" +
++    "import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.futureUnaryCall;\n" +
++    "import static io.grpc.MethodDescriptor.generateFullMethodName;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncUnaryCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;\n" +
++    "import io.grpc.thrift.ThriftUtils;\n\n";
++}
++
++string t_java_generator::import_extended_service(t_service* tservice) {
++  if (!tservice) {
++    return string() + "\n";
++  }
++  string ns = tservice->get_program()->get_namespace("java");
++  string extend_service_name = tservice->get_name() + "Grpc";
++  return string() + "import " + ns + "." + extend_service_name + ";\n\n";
++}
++
+ /**
+  * Nothing in Java
+  */
+@@ -2772,25 +2814,51 @@ void t_java_generator::generate_field_value_meta_data(std::ofstream& out, t_type
+  */
+ void t_java_generator::generate_service(t_service* tservice) {
+   // Make output file
+-  string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + ".java";
++  string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + "Grpc.java";
+   f_service_.open(f_service_name.c_str());
+ 
+-  f_service_ << autogen_comment() << java_package() << java_type_imports() << java_suppressions();
++  f_service_ <<
++      autogen_comment() <<
++      java_package() <<
++      java_type_imports() <<
++      grpc_imports() <<
++      import_extended_service(tservice->get_extends());
++      java_suppressions();
++
++  f_service_ <<
++    "public class " << service_name_ << "Grpc {" << endl <<
++    endl;
+ 
+-  if (!suppress_generated_annotations_) {
+-    generate_javax_generated_annotation(f_service_);
+-  }
+-  f_service_ << "public class " << service_name_ << " {" << endl << endl;
+   indent_up();
+ 
++  // generate constructor
++  f_service_ <<
++    indent() << "private " << service_name_ <<
++    "Grpc() {}" << endl << endl;
++
++  f_service_ <<
++    indent() << "public static final String SERVICE_NAME = " <<
++    "\"" << package_name_ << "." << service_name_ << "\";" << endl << endl;
++
+   // Generate the three main parts of the service
+   generate_service_interface(tservice);
+-  generate_service_async_interface(tservice);
+-  generate_service_client(tservice);
+-  generate_service_async_client(tservice);
+-  generate_service_server(tservice);
+-  generate_service_async_server(tservice);
++  generate_arg_ids(tservice);
++  generate_message_factory(tservice);
++  generate_service_impl_base(tservice);
++  //generate_service_async_interface(tservice);
++  //generate_service_client(tservice);
++  //generate_service_async_client(tservice);
++  //generate_service_server(tservice);
++  //generate_service_async_server(tservice);
+   generate_service_helpers(tservice);
++  generate_method_descriptors(tservice);
++  generate_stub(tservice);
++  generate_blocking_stub(tservice);
++  generate_future_stub(tservice);
++  generate_method_ids(tservice);
++  generate_method_handlers(tservice);
++  generate_service_descriptors(tservice);
++  generate_service_builder(tservice);
+ 
+   indent_down();
+   f_service_ << "}" << endl;
+@@ -2805,24 +2873,820 @@ void t_java_generator::generate_service(t_service* tservice) {
+ void t_java_generator::generate_service_interface(t_service* tservice) {
+   string extends = "";
+   string extends_iface = "";
+-  if (tservice->get_extends() != NULL) {
+-    extends = type_name(tservice->get_extends());
+-    extends_iface = " extends " + extends + ".Iface";
+-  }
+ 
+   generate_java_doc(f_service_, tservice);
+-  f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl;
++  f_service_ << indent() <<
++    "@java.lang.Deprecated public static interface " << service_name_;
++
++  if (tservice->get_extends()) {
++    f_service_ << " extends " << tservice->get_extends()->get_name() + "Grpc." <<
++      tservice->get_extends()->get_name() << endl;
++  }
++  f_service_ << " {" << endl;
++
++  indent_up();
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    //generate_java_doc(f_service_, *f_iter);
++    f_service_ <<
++      indent() << "public void " << (*f_iter)->get_name() << "(" << (*f_iter)->get_name() <<
++      "_args request," << endl <<
++      indent() << "    io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() <<
++      "_result> responseObserver);" << endl << endl;
++  }
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_arg_ids(t_service* tservice) {
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  int i=0;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ << indent() <<
++      "private static final int ARG_IN_METHOD_" <<
++      (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++    f_service_ << indent() <<
++      "private static final int ARG_OUT_METHOD_" <<
++      (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++  }
++  f_service_ << endl;
++
++  if (tservice->get_extends()) {
++    f_service_ << indent() << "// ARG IDs for extended service" << endl;
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ << indent() <<
++        "private static final int ARG_IN_METHOD_" <<
++        (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++      f_service_ << indent() <<
++        "private static final int ARG_OUT_METHOD_" <<
++        (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++    }
++    f_service_ << endl;
++  }
++}
++
++void t_java_generator::generate_message_factory(t_service* tservice) {
++  f_service_ << indent() <<
++    "private static final class ThriftMessageFactory<T extends " <<
++    "org.apache.thrift.TBase<T,?>>" << endl << indent() <<
++    "    implements io.grpc.thrift.MessageFactory<T> {" << endl;
++  indent_up();
++  f_service_ << indent() <<
++      "private final int id;" << endl << endl;
++  f_service_ << endl;
++
++  f_service_ << indent() <<
++    "ThriftMessageFactory(int id) {" << endl <<
++    indent() << "  this.id = id;" << endl <<
++    indent() << "}" << endl;
++
++  f_service_ << indent() <<
++    "@java.lang.Override" << endl <<
++    indent() << "public T newInstance() {" << endl;
++  indent_up();
++
++  f_service_ << indent() <<
++    "Object o;" << endl <<
++    indent() << "switch (id) {" << endl;
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ << indent() <<
++      "case ARG_IN_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++      indent() << "  o = new " << (*f_iter)->get_name() << "_args();" <<
++      endl << indent() << "  break;" << endl;
++    f_service_ << indent() <<
++      "case ARG_OUT_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++      indent() << " o = new " << (*f_iter)->get_name() << "_result();" <<
++      endl << indent() << "  break;" << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for (f_iter = functions.begin(); f_iter!= functions.end(); ++f_iter) {
++      f_service_ << indent() <<
++        "case ARG_IN_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++        indent() << "  o = new " << extend_service_name << "." << (*f_iter)->get_name() << "_args();" <<
++        endl << indent() << "  break;" << endl;
++      f_service_ << indent() <<
++        "case ARG_OUT_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++        indent() << " o = new " << extend_service_name << "." << (*f_iter)->get_name() << "_result();" <<
++        endl << indent() << "  break;" << endl;
++    }
++  }
++
++  f_service_  << indent() <<
++    "default:" << endl << indent() <<
++    "  throw new AssertionError();" << endl << indent() <<
++    "}" << endl;
++
++  f_service_ << indent() <<
++    "@java.lang.SuppressWarnings(\"unchecked\")" << endl <<
++    indent() << "T t = (T) o;" << endl << indent() <<
++    "return t;" << endl;
++
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl;
++
++  indent_down();
++  f_service_ << indent() << "}" << endl;
++}
++
++void t_java_generator::generate_service_impl_base(t_service* tservice) {
++  f_service_ <<
++    indent() << "public static abstract class " << service_name_ <<
++    "ImplBase implements " << service_name_ << ", io.grpc.BindableService {" << endl;
++  indent_up();
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public void " << (*f_iter)->get_name() << "(" << (*f_iter)->get_name() <<
++      "_args request, " << endl <<
++      indent() << "    io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() <<
++      "_result> responseObserver) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "asyncUnimplementedUnaryCall(METHOD_" << (*f_iter)->get_name() <<
++      ", responseObserver);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc" ;
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public void " << (*f_iter)->get_name() << "(" <<
++        extend_service_name << "." << (*f_iter)->get_name() <<
++        "_args request, " << endl <<
++        indent() << "    io.grpc.stub.StreamObserver<" << extend_service_name
++        << "." << (*f_iter)->get_name() << "_result> responseObserver) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "asyncUnimplementedUnaryCall(METHOD_" << (*f_iter)->get_name() <<
++        ", responseObserver);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++
++  f_service_ <<
++    indent() << "@java.lang.Override" <<
++    " public io.grpc.ServerServiceDefinition bindService() {" << endl;
+   indent_up();
++  f_service_ <<
++    indent() << "return " << service_name_ << "Grpc.bindService(this);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Abstract Service
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static abstract class Abstract" << service_name_ <<
++    " extends " << service_name_ << "ImplBase {}" << endl << endl;
++}
++
++void t_java_generator::generate_method_descriptors(t_service* tservice) {
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for( f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "public static final io.grpc.MethodDescriptor<" <<
++      (*f_iter)->get_name() << "_args," << endl <<
++      indent() << "    " << (*f_iter)->get_name() << "_result> METHOD_" << (*f_iter)->get_name() <<
++      " = " << endl << indent() << "    io.grpc.MethodDescriptor.create(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    io.grpc.MethodDescriptor.MethodType.UNARY," << endl <<
++      indent() << "    generateFullMethodName(" << "\"" << package_name_ << "." <<
++      service_name_ << "\" , \"" << (*f_iter)->get_name() << "\")," << endl <<
++      indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++      indent() << "    new ThriftMessageFactory<" << (*f_iter)->get_name() <<
++      "_args>( ARG_IN_METHOD_" << (*f_iter)->get_name() << "))," << endl <<
++      indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++      indent() << "    new ThriftMessageFactory<" << (*f_iter)->get_name() <<
++      "_result>( ARG_OUT_METHOD_" << (*f_iter)->get_name() << ")));" << endl << endl;
++    indent_down();
++  }
++
++  if(tservice->get_extends()) {
++    t_service* extends_service = tservice->get_extends();
++    functions = extends_service->get_functions();
++    string extend_service_name = extends_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "public static final io.grpc.MethodDescriptor<" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_args," << endl <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() << "_result> METHOD_"
++        << (*f_iter)->get_name() << " = " << endl << indent() <<
++        "    io.grpc.MethodDescriptor.create(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    io.grpc.MethodDescriptor.MethodType.UNARY," << endl <<
++        indent() << "    generateFullMethodName(" << "\"" << package_name_ << "." <<
++        service_name_ << "\" , \"" << (*f_iter)->get_name() << "\")," << endl <<
++        indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++        indent() << "    new ThriftMessageFactory<" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_args>( ARG_IN_METHOD_" << (*f_iter)->get_name() << "))," << endl <<
++        indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++        indent() << "    new ThriftMessageFactory<" << extend_service_name << "." << (*f_iter)->get_name() <<
++        "_result>( ARG_OUT_METHOD_" << (*f_iter)->get_name() << ")));" << endl << endl;
++      indent_down();
++    }
++  }
++}
++
++void t_java_generator::generate_stub(t_service* tservice) {
++  f_service_ <<
++    indent() <<
++    "public static " << service_name_ <<
++    "Stub newStub(io.grpc.Channel channel) {" <<
++    endl;
++
++  indent_up();
++  f_service_ <<
++    indent() <<
++    "return new " << service_name_ << "Stub(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Stub impl
++
++  f_service_ <<
++    indent() << "public static class " <<
++    service_name_ << "Stub extends io.grpc.stub.AbstractStub<" <<
++    service_name_ << "Stub>" << endl <<
++    indent() << "    implements " << service_name_ << "{" << endl;
++  indent_up();
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "Stub(io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "Stub(io.grpc.Channel channel, " << endl <<
++    indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "protected " << service_name_ << "Stub build(io.grpc.Channel channel, " <<
++    endl << indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "Stub(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public void " << (*f_iter)->get_name() << "(" <<
++      (*f_iter)->get_name() << "_args request," << endl << indent() <<
++      "    io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() <<
++      "_result> responseObserver) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "asyncUnaryCall(" << endl <<
++      indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++      ", getCallOptions()), request, responseObserver);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public void " << (*f_iter)->get_name() << "(" <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_args request,"
++        << endl << indent() << "    io.grpc.stub.StreamObserver<" <<
++        extend_service_name << "." << (*f_iter)->get_name() <<
++        "_result> responseObserver) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "asyncUnaryCall(" << endl <<
++        indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++        ", getCallOptions()), request, responseObserver);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_blocking_stub(t_service* tservice) {
++  f_service_ <<
++    indent() << "public static " << service_name_ <<
++    "BlockingStub newBlockingStub(" << endl <<
++    indent() << "    io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "BlockingStub(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Blocking Client
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static interface " << service_name_ <<
++    "BlockingClient " ;
++  
++  if (tservice->get_extends()) {
++    string extend_service_name = tservice->get_extends()->get_name();
++    f_service_ << endl << indent() << "    extends " << extend_service_name << "Grpc." <<
++        extend_service_name << "BlockingClient " ;
++  }
++
++  f_service_ << "{" << endl;
++
++  indent_up();
++
+   vector<t_function*> functions = tservice->get_functions();
+   vector<t_function*>::iterator f_iter;
+   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+-    generate_java_doc(f_service_, *f_iter);
+-    indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
++    f_service_ <<
++      indent() << "public " << (*f_iter)->get_name() << "_result " <<
++      (*f_iter)->get_name() << "(" << (*f_iter)->get_name() << "_args request);" << endl << endl;
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Blocking Stub impl
++
++  f_service_ <<
++    indent() << "public static class " <<
++    service_name_ << "BlockingStub extends io.grpc.stub.AbstractStub<" <<
++    service_name_ << "BlockingStub>" << endl <<
++    indent() << "    implements " << service_name_ << "BlockingClient {";
++
++  indent_up();
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "BlockingStub(io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "BlockingStub(io.grpc.Channel channel, " << endl <<
++    indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "protected " << service_name_ << "BlockingStub build(io.grpc.Channel channel, " <<
++    endl << indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "BlockingStub(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public " << (*f_iter)->get_name() << "_result " << (*f_iter)->get_name() << "(" <<
++      (*f_iter)->get_name() << "_args request) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "return blockingUnaryCall(" << endl <<
++      indent() << "    getChannel(), METHOD_" << (*f_iter)->get_name() <<
++      ", getCallOptions(), request);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public " << extend_service_name << "." << (*f_iter)->get_name() <<
++        "_result " << (*f_iter)->get_name() << "(" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_args request) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "return blockingUnaryCall(" << endl <<
++        indent() << "    getChannel(), METHOD_" << (*f_iter)->get_name() <<
++        ", getCallOptions(), request);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_future_stub(t_service* tservice) {
++  f_service_ <<
++    indent() << "public static " << service_name_ <<
++    "FutureStub newFutureStub(" << endl <<
++    indent() << "    io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "FutureStub(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Future Client
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static interface " << service_name_ <<
++    "FutureClient " ;
++
++  if (tservice->get_extends()) {
++    string extend_service_name = tservice->get_extends()->get_name();
++    f_service_ << endl << indent() << "    extends " << extend_service_name << "Grpc." <<
++        extend_service_name << "FutureClient " ; 
++  }
++  f_service_ << "{" << endl;
++
++  indent_up();
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++      (*f_iter)->get_name() << "_result> " << (*f_iter)->get_name() << "(" << endl <<
++      indent() << "    " << (*f_iter)->get_name() << "_args request);" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_result> " <<
++        (*f_iter)->get_name() << "(" << endl <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() <<
++        "_args request);" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Stub impl
++
++  f_service_ <<
++    indent() << "public static class " <<
++    service_name_ << "FutureStub extends io.grpc.stub.AbstractStub<" <<
++    service_name_ << "FutureStub>" << endl <<
++    indent() << "    implements " << service_name_ << "FutureClient {" << endl;
++  indent_up();
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "FutureStub(io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "FutureStub(io.grpc.Channel channel, " << endl <<
++    indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "protected " << service_name_ << "FutureStub build(io.grpc.Channel channel, " <<
++    endl << indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "FutureStub(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  functions = tservice->get_functions();
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++      (*f_iter)->get_name() << "_result> " << (*f_iter)->get_name() << "(" <<
++      endl << indent() << "    " << (*f_iter)->get_name() << "_args request) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "return futureUnaryCall(" << endl <<
++      indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++      ", getCallOptions()), request);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_result> " <<
++        (*f_iter)->get_name() << "(" << endl << indent() << "    " <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_args request) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "return futureUnaryCall(" << endl <<
++        indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++        ", getCallOptions()), request);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_method_ids(t_service* tservice) {
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  int i=0;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter, ++i) {
++    f_service_ <<
++      indent() << "private static final int METHODID_" <<
++      (*f_iter)->get_name() << " = " << i << ";" << endl;
++  }
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter, ++i) {
++      f_service_ <<
++        indent() << "private static final int METHODID_" <<
++        (*f_iter)->get_name() << " = " << i << ";" << endl;
++    }
++  }
++  f_service_ << endl;
++}
++
++void t_java_generator::generate_method_handlers(t_service* tservice) {
++  f_service_ <<
++    indent() << "private static class MethodHandlers<Req, Resp> implements" <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>," <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>," <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>," <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {" <<
++    endl;
++  indent_up();
++  f_service_ <<
++    indent() << "private final " << service_name_ << " serviceImpl;" << endl <<
++    indent() << "private final int methodId;" << endl << endl;
++
++  f_service_ <<
++    indent() << "public MethodHandlers(" << service_name_ << " serviceImpl, int " <<
++    "methodId) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "this.serviceImpl = serviceImpl;" << endl <<
++    indent() << "this.methodId = methodId;" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // invoke
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "@java.lang.SuppressWarnings(\"unchecked\")" << endl <<
++    indent() << "public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {" <<
++    endl;
++  indent_up();
++  f_service_ <<
++    indent() << "switch (methodId) {" << endl;
++  indent_up();
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "case METHODID_" << (*f_iter)->get_name() << ":" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "serviceImpl." << (*f_iter)->get_name() << "((" << (*f_iter)->get_name() <<
++      "_args) request," << endl <<
++      indent() << "    (io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() << "_result>)" <<
++      " responseObserver);" << endl <<
++      indent() << "break;" << endl << endl;
++    indent_down();
++  }
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "case METHODID_" << (*f_iter)->get_name() << ":" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "serviceImpl." << (*f_iter)->get_name() << "((" << extend_service_name <<
++        "." << (*f_iter)->get_name() << "_args) request," << endl <<
++        indent() << "    (io.grpc.stub.StreamObserver<" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_result>)" << " responseObserver);" << endl <<
++        indent() << "break;" << endl << endl;
++      indent_down();
++    }
+   }
++  f_service_ <<
++    indent() << "default:" << endl <<
++    indent() << "  throw new AssertionError();" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // invoke
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "@java.lang.SuppressWarnings(\"unchecked\")" << endl <<
++    indent() << "public io.grpc.stub.StreamObserver<Req> invoke(" << endl <<
++    indent() << "    io.grpc.stub.StreamObserver<Resp> responseObserver) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "switch (methodId) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "default:" << endl;
++  f_service_ <<
++    indent() << "  throw new AssertionError();" << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl;
+   indent_down();
+   f_service_ << indent() << "}" << endl << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++
+ }
+ 
++void t_java_generator::generate_service_descriptors(t_service* tservice) {
++  // generate service descriptor
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  f_service_ <<
++    indent() << "public static io.grpc.ServiceDescriptor getServiceDescriptor() {" <<
++    endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new io.grpc.ServiceDescriptor(SERVICE_NAME";
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "," << endl <<
++      indent() << "    METHOD_" << (*f_iter)->get_name();
++  }
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "," << endl <<
++        indent() << "    METHOD_" << (*f_iter)->get_name();
++    }
++  }
++  f_service_ << ");" << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_service_builder(t_service* tservice) {
++  // bind Service
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static io.grpc.ServerServiceDefinition" <<
++    " bindService(" << endl <<
++    indent() << "    final " << service_name_ << " serviceImpl) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())" <<
++    endl;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "    .addMethod(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    METHOD_" << (*f_iter)->get_name() << "," << endl <<
++      indent() << "    asyncUnaryCall(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    new MethodHandlers<" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    " << (*f_iter)->get_name() << "_args," << endl <<
++      indent() << "    " << (*f_iter)->get_name() << "_result>(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    serviceImpl, METHODID_" << (*f_iter)->get_name() << ")))" << endl;
++    indent_down();
++    indent_down();
++    indent_down();
++    indent_down();
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "    .addMethod(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    METHOD_" << (*f_iter)->get_name() << "," << endl <<
++        indent() << "    asyncUnaryCall(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    new MethodHandlers<" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() << "_args," << endl <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() << "_result>(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    serviceImpl, METHODID_" << (*f_iter)->get_name() << ")))" << endl;
++      indent_down();
++      indent_down();
++      indent_down();
++      indent_down();
++    }
++  }
++  f_service_ <<
++    indent() << "    .build();" << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++}
++
++
+ void t_java_generator::generate_service_async_interface(t_service* tservice) {
+   string extends = "";
+   string extends_iface = "";
+diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
+index 5865c54..1cffbe6 100755
+--- a/tutorial/Makefile.am
++++ b/tutorial/Makefile.am
+@@ -35,11 +35,6 @@ if WITH_D
+ SUBDIRS += d
+ endif
+ 
+-if WITH_JAVA
+-SUBDIRS += java
+-SUBDIRS += js
+-endif
+-
+ if WITH_PYTHON
+ SUBDIRS += py
+ SUBDIRS += py.twisted
+@@ -95,4 +90,5 @@ EXTRA_DIST = \
+ 	php \
+ 	shared.thrift \
+ 	tutorial.thrift \
+-	README.md
++	README.md \
++	java
+-- 
+2.8.0.rc3.226.g39d4020
+
diff --git a/tools/run_tests/build_package_node.sh b/tools/run_tests/build_package_node.sh
index f20daea..a5636cf 100755
--- a/tools/run_tests/build_package_node.sh
+++ b/tools/run_tests/build_package_node.sh
@@ -50,7 +50,6 @@
 mkdir -p bin
 
 cd $base/src/node/health_check
-npm update
 npm pack
 cp grpc-health-check-*.tgz $artifacts/
 
diff --git a/tools/run_tests/package_targets.py b/tools/run_tests/package_targets.py
index ce3f08d..5e6de2e 100644
--- a/tools/run_tests/package_targets.py
+++ b/tools/run_tests/package_targets.py
@@ -81,7 +81,14 @@
       self.labels += ['windows']
 
   def pre_build_jobspecs(self):
-    return []
+    if 'windows' in self.labels:
+      return [create_jobspec('prebuild_%s' % self.name,
+                             ['tools\\run_tests\\pre_build_csharp.bat'],
+                             shell=True,
+                             flake_retries=5,
+                             timeout_retries=2)]
+    else:
+      return []
 
   def build_jobspec(self):
     if self.use_coreclr:
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 04123ee..d2ab5b0 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -47,6 +47,7 @@
  f8ac463766281625ad710900479130c7fcb4d63b third_party/nanopb (nanopb-0.3.4-29-gf8ac463)
  e8ae137c96444ea313485ed1118c5e43b2099cf1 third_party/protobuf (v3.0.0-beta-4-74-ge8ae137)
  50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
+ bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift
 EOF
 
 diff -u $submodules $want_submodules
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 4071eba..e5946cc 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -2164,14 +2164,11 @@
   {
     "deps": [
       "gpr", 
-      "gpr_test_util", 
       "grpc", 
       "grpc++", 
       "grpc++_reflection", 
       "grpc++_test_config", 
-      "grpc++_test_util", 
-      "grpc_cli_libs", 
-      "grpc_test_util"
+      "grpc_cli_libs"
     ], 
     "headers": [], 
     "language": "c++", 
@@ -2262,6 +2259,35 @@
   }, 
   {
     "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_codegen_proto", 
+      "grpc++_config_proto", 
+      "grpc++_reflection", 
+      "grpc_cli_libs", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "src/proto/grpc/testing/echo.grpc.pb.h", 
+      "src/proto/grpc/testing/echo.pb.h", 
+      "src/proto/grpc/testing/echo_messages.grpc.pb.h", 
+      "src/proto/grpc/testing/echo_messages.pb.h", 
+      "test/cpp/util/string_ref_helper.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc_tool_test", 
+    "src": [
+      "test/cpp/util/grpc_tool_test.cc", 
+      "test/cpp/util/string_ref_helper.cc", 
+      "test/cpp/util/string_ref_helper.h"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "grpc", 
       "grpc++", 
       "grpc++_test_util", 
@@ -4468,7 +4494,8 @@
       "grpc++_codegen_base_src", 
       "grpc++_codegen_proto", 
       "grpc++_config_proto", 
-      "grpc_test_util"
+      "grpc_test_util", 
+      "thrift_util"
     ], 
     "headers": [
       "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h", 
@@ -4525,10 +4552,13 @@
     "deps": [
       "grpc++", 
       "grpc++_reflection", 
-      "grpc_plugin_support"
+      "grpc++_test_config"
     ], 
     "headers": [
       "test/cpp/util/cli_call.h", 
+      "test/cpp/util/cli_credentials.h", 
+      "test/cpp/util/config_grpc_cli.h", 
+      "test/cpp/util/grpc_tool.h", 
       "test/cpp/util/proto_file_parser.h", 
       "test/cpp/util/proto_reflection_descriptor_database.h"
     ], 
@@ -4537,6 +4567,11 @@
     "src": [
       "test/cpp/util/cli_call.cc", 
       "test/cpp/util/cli_call.h", 
+      "test/cpp/util/cli_credentials.cc", 
+      "test/cpp/util/cli_credentials.h", 
+      "test/cpp/util/config_grpc_cli.h", 
+      "test/cpp/util/grpc_tool.cc", 
+      "test/cpp/util/grpc_tool.h", 
       "test/cpp/util/proto_file_parser.cc", 
       "test/cpp/util/proto_file_parser.h", 
       "test/cpp/util/proto_reflection_descriptor_database.cc", 
@@ -6870,5 +6905,22 @@
     ], 
     "third_party": false, 
     "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "grpc++_codegen_base"
+    ], 
+    "headers": [
+      "include/grpc++/impl/codegen/thrift_serializer.h", 
+      "include/grpc++/impl/codegen/thrift_utils.h"
+    ], 
+    "language": "c++", 
+    "name": "thrift_util", 
+    "src": [
+      "include/grpc++/impl/codegen/thrift_serializer.h", 
+      "include/grpc++/impl/codegen/thrift_utils.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
   }
 ]
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 11fb460..b0c09ac 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -2324,6 +2324,27 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "grpc_tool_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "grpclb_api_test", 
     "platforms": [
       "linux", 
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
index d0fca9b..c2c7d00 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
@@ -200,6 +200,8 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_serializer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_utils.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.h" />
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
index cc98c60..9b8c8dd 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
@@ -192,6 +192,12 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_serializer.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.h">
diff --git a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj
index d25c692..425b66f 100644
--- a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj
+++ b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj
@@ -148,12 +148,19 @@
 
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\config_grpc_cli.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\proto_reflection_descriptor_database.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_call.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\proto_reflection_descriptor_database.cc">
@@ -166,8 +173,8 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
       <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_plugin_support\grpc_plugin_support.vcxproj">
-      <Project>{B6E81D84-2ACB-41B8-8781-493A944C7817}</Project>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_config\grpc++_test_config.vcxproj">
+      <Project>{3F7D093D-11F9-C4BC-BEB7-18EB28E3F290}</Project>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters
index 4add8ed..b2128c2 100644
--- a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters
@@ -4,6 +4,12 @@
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_call.cc">
       <Filter>test\cpp\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.cc">
       <Filter>test\cpp\util</Filter>
     </ClCompile>
@@ -15,6 +21,15 @@
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_call.h">
       <Filter>test\cpp\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\config_grpc_cli.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.h">
       <Filter>test\cpp\util</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj b/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj
index 9c8cdc5..78a0a63 100644
--- a/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj
+++ b/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj
@@ -167,12 +167,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_cli_libs\grpc_cli_libs.vcxproj">
       <Project>{86E35862-43E8-F59E-F906-AFE0348AD3D2}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
-      <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
-      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_reflection\grpc++_reflection.vcxproj">
       <Project>{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}</Project>
     </ProjectReference>
@@ -182,9 +176,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
       <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
new file mode 100644
index 0000000..c6f65aa
--- /dev/null
+++ b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
@@ -0,0 +1,286 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{F00D82D4-E988-6D2F-F0B9-9E82BCC2A2B2}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\cpptest.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>grpc_tool_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>grpc_tool_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\create_auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool_test.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_cli_libs\grpc_cli_libs.vcxproj">
+      <Project>{86E35862-43E8-F59E-F906-AFE0348AD3D2}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_reflection\grpc++_reflection.vcxproj">
+      <Project>{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+      <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters
new file mode 100644
index 0000000..731eb2e
--- /dev/null
+++ b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool_test.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\create_auth_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="include">
+      <UniqueIdentifier>{89fed779-17c5-23da-c8a2-9e868ff34480}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc">
+      <UniqueIdentifier>{96e4a1a8-0b91-1a6d-ae4d-ddf33abb93c0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++">
+      <UniqueIdentifier>{1d9dcc6f-7c1b-cdc3-4c35-73d5968dfd92}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl">
+      <UniqueIdentifier>{5eca7690-973a-c8ed-84d6-5325f8de43ac}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen">
+      <UniqueIdentifier>{5789073e-5b84-0ec9-af06-47866647874d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen\security">
+      <UniqueIdentifier>{d3f3293f-204f-7771-fcdf-de673f6b06b6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{7e90f37b-f9cc-0725-b2c1-12aa7d4809ba}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{7e4b71ef-8125-6446-bfc1-9bc90beed59c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src">
+      <UniqueIdentifier>{169774bd-5c6c-6827-66a4-326b4aef44d6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{1b609b37-ef2a-e5eb-e1ba-ad9e79c77438}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{cd1e35d8-8a61-62fe-6ce1-c8936872d1ef}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\testing">
+      <UniqueIdentifier>{f7ee4df5-1f47-1e7f-c91e-350382c1b729}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test">
+      <UniqueIdentifier>{f2166b83-6b0b-d53b-b58b-627bd9efcad2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{bbe36cbc-7fbe-2817-0bd0-d03726f323e6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\util">
+      <UniqueIdentifier>{e106cd7b-cfa0-0645-f1a9-2acedc23afe7}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+