Merge branch 'master' of github.com:grpc/grpc into freebsd
diff --git a/.gitmodules b/.gitmodules
index 97b7197..5573210 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -11,4 +11,4 @@
 	branch = v3.0.0-alpha-1
 [submodule "third_party/gflags"]
 	path = third_party/gflags
-	url = https://code.google.com/p/gflags
+	url = https://github.com/gflags/gflags.git
diff --git a/.travis.yml b/.travis.yml
index e43a89e..165f892 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,9 +19,12 @@
     - CONFIG=opt TEST=python
     - CONFIG=gcov TEST=c
     - CONFIG=gcov TEST=c++
+    - USE_GCC=4.4 CONFIG=opt TEST=build
+    - USE_GCC=4.5 CONFIG=opt TEST=build
 script:
   - rvm use $RUBY_VERSION
   - gem install bundler
+  - if [ ! -z "$USE_GCC" ] ; then export CC=gcc-$USE_GCC ; export CXX=g++-$USE_GCC ; fi
   - ./tools/run_tests/run_tests.py -l $TEST -t -j 16 -c $CONFIG -s 4.0
 after_success:
   - if [ "$CONFIG" = "gcov" ] ; then coveralls --exclude third_party --exclude gens -b. --gcov-options '\-p' ; fi
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..233cf65
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,813 @@
+# GRPC Bazel BUILD file.
+# This currently builds C and C++ code.
+
+# 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.
+
+licenses(["notice"])  # 3-clause BSD
+
+package(default_visibility = ["//visibility:public"])
+
+
+
+
+cc_library(
+  name = "gpr",
+  srcs = [
+    "src/core/support/env.h",
+    "src/core/support/file.h",
+    "src/core/support/murmur_hash.h",
+    "src/core/support/string.h",
+    "src/core/support/string_win32.h",
+    "src/core/support/thd_internal.h",
+    "src/core/support/alloc.c",
+    "src/core/support/cancellable.c",
+    "src/core/support/cmdline.c",
+    "src/core/support/cpu_iphone.c",
+    "src/core/support/cpu_linux.c",
+    "src/core/support/cpu_posix.c",
+    "src/core/support/cpu_windows.c",
+    "src/core/support/env_linux.c",
+    "src/core/support/env_posix.c",
+    "src/core/support/env_win32.c",
+    "src/core/support/file.c",
+    "src/core/support/file_posix.c",
+    "src/core/support/file_win32.c",
+    "src/core/support/histogram.c",
+    "src/core/support/host_port.c",
+    "src/core/support/log.c",
+    "src/core/support/log_android.c",
+    "src/core/support/log_linux.c",
+    "src/core/support/log_posix.c",
+    "src/core/support/log_win32.c",
+    "src/core/support/murmur_hash.c",
+    "src/core/support/slice.c",
+    "src/core/support/slice_buffer.c",
+    "src/core/support/string.c",
+    "src/core/support/string_posix.c",
+    "src/core/support/string_win32.c",
+    "src/core/support/sync.c",
+    "src/core/support/sync_posix.c",
+    "src/core/support/sync_win32.c",
+    "src/core/support/thd.c",
+    "src/core/support/thd_posix.c",
+    "src/core/support/thd_win32.c",
+    "src/core/support/time.c",
+    "src/core/support/time_posix.c",
+    "src/core/support/time_win32.c",
+  ],
+  hdrs = [
+    "include/grpc/support/alloc.h",
+    "include/grpc/support/atm.h",
+    "include/grpc/support/atm_gcc_atomic.h",
+    "include/grpc/support/atm_gcc_sync.h",
+    "include/grpc/support/atm_win32.h",
+    "include/grpc/support/cancellable_platform.h",
+    "include/grpc/support/cmdline.h",
+    "include/grpc/support/cpu.h",
+    "include/grpc/support/histogram.h",
+    "include/grpc/support/host_port.h",
+    "include/grpc/support/log.h",
+    "include/grpc/support/log_win32.h",
+    "include/grpc/support/port_platform.h",
+    "include/grpc/support/slice.h",
+    "include/grpc/support/slice_buffer.h",
+    "include/grpc/support/sync.h",
+    "include/grpc/support/sync_generic.h",
+    "include/grpc/support/sync_posix.h",
+    "include/grpc/support/sync_win32.h",
+    "include/grpc/support/thd.h",
+    "include/grpc/support/time.h",
+    "include/grpc/support/useful.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+  ],
+)
+
+
+cc_library(
+  name = "grpc",
+  srcs = [
+    "src/core/httpcli/format_request.h",
+    "src/core/httpcli/httpcli.h",
+    "src/core/httpcli/httpcli_security_context.h",
+    "src/core/httpcli/parser.h",
+    "src/core/security/auth.h",
+    "src/core/security/base64.h",
+    "src/core/security/credentials.h",
+    "src/core/security/json_token.h",
+    "src/core/security/secure_endpoint.h",
+    "src/core/security/secure_transport_setup.h",
+    "src/core/security/security_context.h",
+    "src/core/tsi/fake_transport_security.h",
+    "src/core/tsi/ssl_transport_security.h",
+    "src/core/tsi/transport_security.h",
+    "src/core/tsi/transport_security_interface.h",
+    "src/core/channel/census_filter.h",
+    "src/core/channel/channel_args.h",
+    "src/core/channel/channel_stack.h",
+    "src/core/channel/child_channel.h",
+    "src/core/channel/client_channel.h",
+    "src/core/channel/client_setup.h",
+    "src/core/channel/connected_channel.h",
+    "src/core/channel/http_client_filter.h",
+    "src/core/channel/http_filter.h",
+    "src/core/channel/http_server_filter.h",
+    "src/core/channel/metadata_buffer.h",
+    "src/core/channel/noop_filter.h",
+    "src/core/compression/algorithm.h",
+    "src/core/compression/message_compress.h",
+    "src/core/debug/trace.h",
+    "src/core/iomgr/alarm.h",
+    "src/core/iomgr/alarm_heap.h",
+    "src/core/iomgr/alarm_internal.h",
+    "src/core/iomgr/endpoint.h",
+    "src/core/iomgr/endpoint_pair.h",
+    "src/core/iomgr/fd_posix.h",
+    "src/core/iomgr/iocp_windows.h",
+    "src/core/iomgr/iomgr.h",
+    "src/core/iomgr/iomgr_internal.h",
+    "src/core/iomgr/iomgr_posix.h",
+    "src/core/iomgr/pollset.h",
+    "src/core/iomgr/pollset_kick.h",
+    "src/core/iomgr/pollset_kick_posix.h",
+    "src/core/iomgr/pollset_kick_windows.h",
+    "src/core/iomgr/pollset_posix.h",
+    "src/core/iomgr/pollset_windows.h",
+    "src/core/iomgr/resolve_address.h",
+    "src/core/iomgr/sockaddr.h",
+    "src/core/iomgr/sockaddr_posix.h",
+    "src/core/iomgr/sockaddr_utils.h",
+    "src/core/iomgr/sockaddr_win32.h",
+    "src/core/iomgr/socket_utils_posix.h",
+    "src/core/iomgr/socket_windows.h",
+    "src/core/iomgr/tcp_client.h",
+    "src/core/iomgr/tcp_posix.h",
+    "src/core/iomgr/tcp_server.h",
+    "src/core/iomgr/tcp_windows.h",
+    "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/wakeup_fd_pipe.h",
+    "src/core/iomgr/wakeup_fd_posix.h",
+    "src/core/json/json.h",
+    "src/core/json/json_common.h",
+    "src/core/json/json_reader.h",
+    "src/core/json/json_writer.h",
+    "src/core/statistics/census_interface.h",
+    "src/core/statistics/census_log.h",
+    "src/core/statistics/census_rpc_stats.h",
+    "src/core/statistics/census_tracing.h",
+    "src/core/statistics/hash_table.h",
+    "src/core/statistics/window_stats.h",
+    "src/core/surface/byte_buffer_queue.h",
+    "src/core/surface/call.h",
+    "src/core/surface/channel.h",
+    "src/core/surface/client.h",
+    "src/core/surface/completion_queue.h",
+    "src/core/surface/event_string.h",
+    "src/core/surface/init.h",
+    "src/core/surface/server.h",
+    "src/core/surface/surface_trace.h",
+    "src/core/transport/chttp2/alpn.h",
+    "src/core/transport/chttp2/bin_encoder.h",
+    "src/core/transport/chttp2/frame.h",
+    "src/core/transport/chttp2/frame_data.h",
+    "src/core/transport/chttp2/frame_goaway.h",
+    "src/core/transport/chttp2/frame_ping.h",
+    "src/core/transport/chttp2/frame_rst_stream.h",
+    "src/core/transport/chttp2/frame_settings.h",
+    "src/core/transport/chttp2/frame_window_update.h",
+    "src/core/transport/chttp2/hpack_parser.h",
+    "src/core/transport/chttp2/hpack_table.h",
+    "src/core/transport/chttp2/http2_errors.h",
+    "src/core/transport/chttp2/huffsyms.h",
+    "src/core/transport/chttp2/status_conversion.h",
+    "src/core/transport/chttp2/stream_encoder.h",
+    "src/core/transport/chttp2/stream_map.h",
+    "src/core/transport/chttp2/timeout_encoding.h",
+    "src/core/transport/chttp2/varint.h",
+    "src/core/transport/chttp2_transport.h",
+    "src/core/transport/metadata.h",
+    "src/core/transport/stream_op.h",
+    "src/core/transport/transport.h",
+    "src/core/transport/transport_impl.h",
+    "src/core/httpcli/format_request.c",
+    "src/core/httpcli/httpcli.c",
+    "src/core/httpcli/httpcli_security_context.c",
+    "src/core/httpcli/parser.c",
+    "src/core/security/auth.c",
+    "src/core/security/base64.c",
+    "src/core/security/credentials.c",
+    "src/core/security/credentials_posix.c",
+    "src/core/security/credentials_win32.c",
+    "src/core/security/factories.c",
+    "src/core/security/google_default_credentials.c",
+    "src/core/security/json_token.c",
+    "src/core/security/secure_endpoint.c",
+    "src/core/security/secure_transport_setup.c",
+    "src/core/security/security_context.c",
+    "src/core/security/server_secure_chttp2.c",
+    "src/core/surface/init_secure.c",
+    "src/core/surface/secure_channel_create.c",
+    "src/core/tsi/fake_transport_security.c",
+    "src/core/tsi/ssl_transport_security.c",
+    "src/core/tsi/transport_security.c",
+    "src/core/channel/call_op_string.c",
+    "src/core/channel/census_filter.c",
+    "src/core/channel/channel_args.c",
+    "src/core/channel/channel_stack.c",
+    "src/core/channel/child_channel.c",
+    "src/core/channel/client_channel.c",
+    "src/core/channel/client_setup.c",
+    "src/core/channel/connected_channel.c",
+    "src/core/channel/http_client_filter.c",
+    "src/core/channel/http_filter.c",
+    "src/core/channel/http_server_filter.c",
+    "src/core/channel/metadata_buffer.c",
+    "src/core/channel/noop_filter.c",
+    "src/core/compression/algorithm.c",
+    "src/core/compression/message_compress.c",
+    "src/core/debug/trace.c",
+    "src/core/iomgr/alarm.c",
+    "src/core/iomgr/alarm_heap.c",
+    "src/core/iomgr/endpoint.c",
+    "src/core/iomgr/endpoint_pair_posix.c",
+    "src/core/iomgr/fd_posix.c",
+    "src/core/iomgr/iocp_windows.c",
+    "src/core/iomgr/iomgr.c",
+    "src/core/iomgr/iomgr_posix.c",
+    "src/core/iomgr/iomgr_windows.c",
+    "src/core/iomgr/pollset_kick.c",
+    "src/core/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/iomgr/pollset_posix.c",
+    "src/core/iomgr/pollset_windows.c",
+    "src/core/iomgr/resolve_address_posix.c",
+    "src/core/iomgr/resolve_address_windows.c",
+    "src/core/iomgr/sockaddr_utils.c",
+    "src/core/iomgr/socket_utils_common_posix.c",
+    "src/core/iomgr/socket_utils_linux.c",
+    "src/core/iomgr/socket_utils_posix.c",
+    "src/core/iomgr/socket_windows.c",
+    "src/core/iomgr/tcp_client_posix.c",
+    "src/core/iomgr/tcp_client_windows.c",
+    "src/core/iomgr/tcp_posix.c",
+    "src/core/iomgr/tcp_server_posix.c",
+    "src/core/iomgr/tcp_server_windows.c",
+    "src/core/iomgr/tcp_windows.c",
+    "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/wakeup_fd_eventfd.c",
+    "src/core/iomgr/wakeup_fd_nospecial.c",
+    "src/core/iomgr/wakeup_fd_pipe.c",
+    "src/core/iomgr/wakeup_fd_posix.c",
+    "src/core/json/json.c",
+    "src/core/json/json_reader.c",
+    "src/core/json/json_string.c",
+    "src/core/json/json_writer.c",
+    "src/core/statistics/census_init.c",
+    "src/core/statistics/census_log.c",
+    "src/core/statistics/census_rpc_stats.c",
+    "src/core/statistics/census_tracing.c",
+    "src/core/statistics/hash_table.c",
+    "src/core/statistics/window_stats.c",
+    "src/core/surface/byte_buffer.c",
+    "src/core/surface/byte_buffer_queue.c",
+    "src/core/surface/byte_buffer_reader.c",
+    "src/core/surface/call.c",
+    "src/core/surface/call_details.c",
+    "src/core/surface/call_log_batch.c",
+    "src/core/surface/channel.c",
+    "src/core/surface/channel_create.c",
+    "src/core/surface/client.c",
+    "src/core/surface/completion_queue.c",
+    "src/core/surface/event_string.c",
+    "src/core/surface/init.c",
+    "src/core/surface/lame_client.c",
+    "src/core/surface/metadata_array.c",
+    "src/core/surface/server.c",
+    "src/core/surface/server_chttp2.c",
+    "src/core/surface/server_create.c",
+    "src/core/surface/surface_trace.c",
+    "src/core/transport/chttp2/alpn.c",
+    "src/core/transport/chttp2/bin_encoder.c",
+    "src/core/transport/chttp2/frame_data.c",
+    "src/core/transport/chttp2/frame_goaway.c",
+    "src/core/transport/chttp2/frame_ping.c",
+    "src/core/transport/chttp2/frame_rst_stream.c",
+    "src/core/transport/chttp2/frame_settings.c",
+    "src/core/transport/chttp2/frame_window_update.c",
+    "src/core/transport/chttp2/hpack_parser.c",
+    "src/core/transport/chttp2/hpack_table.c",
+    "src/core/transport/chttp2/huffsyms.c",
+    "src/core/transport/chttp2/status_conversion.c",
+    "src/core/transport/chttp2/stream_encoder.c",
+    "src/core/transport/chttp2/stream_map.c",
+    "src/core/transport/chttp2/timeout_encoding.c",
+    "src/core/transport/chttp2/varint.c",
+    "src/core/transport/chttp2_transport.c",
+    "src/core/transport/metadata.c",
+    "src/core/transport/stream_op.c",
+    "src/core/transport/transport.c",
+  ],
+  hdrs = [
+    "include/grpc/grpc_security.h",
+    "include/grpc/byte_buffer.h",
+    "include/grpc/byte_buffer_reader.h",
+    "include/grpc/grpc.h",
+    "include/grpc/grpc_http.h",
+    "include/grpc/status.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:libssl",
+    ":gpr",
+  ],
+)
+
+
+cc_library(
+  name = "grpc_unsecure",
+  srcs = [
+    "src/core/channel/census_filter.h",
+    "src/core/channel/channel_args.h",
+    "src/core/channel/channel_stack.h",
+    "src/core/channel/child_channel.h",
+    "src/core/channel/client_channel.h",
+    "src/core/channel/client_setup.h",
+    "src/core/channel/connected_channel.h",
+    "src/core/channel/http_client_filter.h",
+    "src/core/channel/http_filter.h",
+    "src/core/channel/http_server_filter.h",
+    "src/core/channel/metadata_buffer.h",
+    "src/core/channel/noop_filter.h",
+    "src/core/compression/algorithm.h",
+    "src/core/compression/message_compress.h",
+    "src/core/debug/trace.h",
+    "src/core/iomgr/alarm.h",
+    "src/core/iomgr/alarm_heap.h",
+    "src/core/iomgr/alarm_internal.h",
+    "src/core/iomgr/endpoint.h",
+    "src/core/iomgr/endpoint_pair.h",
+    "src/core/iomgr/fd_posix.h",
+    "src/core/iomgr/iocp_windows.h",
+    "src/core/iomgr/iomgr.h",
+    "src/core/iomgr/iomgr_internal.h",
+    "src/core/iomgr/iomgr_posix.h",
+    "src/core/iomgr/pollset.h",
+    "src/core/iomgr/pollset_kick.h",
+    "src/core/iomgr/pollset_kick_posix.h",
+    "src/core/iomgr/pollset_kick_windows.h",
+    "src/core/iomgr/pollset_posix.h",
+    "src/core/iomgr/pollset_windows.h",
+    "src/core/iomgr/resolve_address.h",
+    "src/core/iomgr/sockaddr.h",
+    "src/core/iomgr/sockaddr_posix.h",
+    "src/core/iomgr/sockaddr_utils.h",
+    "src/core/iomgr/sockaddr_win32.h",
+    "src/core/iomgr/socket_utils_posix.h",
+    "src/core/iomgr/socket_windows.h",
+    "src/core/iomgr/tcp_client.h",
+    "src/core/iomgr/tcp_posix.h",
+    "src/core/iomgr/tcp_server.h",
+    "src/core/iomgr/tcp_windows.h",
+    "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/wakeup_fd_pipe.h",
+    "src/core/iomgr/wakeup_fd_posix.h",
+    "src/core/json/json.h",
+    "src/core/json/json_common.h",
+    "src/core/json/json_reader.h",
+    "src/core/json/json_writer.h",
+    "src/core/statistics/census_interface.h",
+    "src/core/statistics/census_log.h",
+    "src/core/statistics/census_rpc_stats.h",
+    "src/core/statistics/census_tracing.h",
+    "src/core/statistics/hash_table.h",
+    "src/core/statistics/window_stats.h",
+    "src/core/surface/byte_buffer_queue.h",
+    "src/core/surface/call.h",
+    "src/core/surface/channel.h",
+    "src/core/surface/client.h",
+    "src/core/surface/completion_queue.h",
+    "src/core/surface/event_string.h",
+    "src/core/surface/init.h",
+    "src/core/surface/server.h",
+    "src/core/surface/surface_trace.h",
+    "src/core/transport/chttp2/alpn.h",
+    "src/core/transport/chttp2/bin_encoder.h",
+    "src/core/transport/chttp2/frame.h",
+    "src/core/transport/chttp2/frame_data.h",
+    "src/core/transport/chttp2/frame_goaway.h",
+    "src/core/transport/chttp2/frame_ping.h",
+    "src/core/transport/chttp2/frame_rst_stream.h",
+    "src/core/transport/chttp2/frame_settings.h",
+    "src/core/transport/chttp2/frame_window_update.h",
+    "src/core/transport/chttp2/hpack_parser.h",
+    "src/core/transport/chttp2/hpack_table.h",
+    "src/core/transport/chttp2/http2_errors.h",
+    "src/core/transport/chttp2/huffsyms.h",
+    "src/core/transport/chttp2/status_conversion.h",
+    "src/core/transport/chttp2/stream_encoder.h",
+    "src/core/transport/chttp2/stream_map.h",
+    "src/core/transport/chttp2/timeout_encoding.h",
+    "src/core/transport/chttp2/varint.h",
+    "src/core/transport/chttp2_transport.h",
+    "src/core/transport/metadata.h",
+    "src/core/transport/stream_op.h",
+    "src/core/transport/transport.h",
+    "src/core/transport/transport_impl.h",
+    "src/core/surface/init_unsecure.c",
+    "src/core/channel/call_op_string.c",
+    "src/core/channel/census_filter.c",
+    "src/core/channel/channel_args.c",
+    "src/core/channel/channel_stack.c",
+    "src/core/channel/child_channel.c",
+    "src/core/channel/client_channel.c",
+    "src/core/channel/client_setup.c",
+    "src/core/channel/connected_channel.c",
+    "src/core/channel/http_client_filter.c",
+    "src/core/channel/http_filter.c",
+    "src/core/channel/http_server_filter.c",
+    "src/core/channel/metadata_buffer.c",
+    "src/core/channel/noop_filter.c",
+    "src/core/compression/algorithm.c",
+    "src/core/compression/message_compress.c",
+    "src/core/debug/trace.c",
+    "src/core/iomgr/alarm.c",
+    "src/core/iomgr/alarm_heap.c",
+    "src/core/iomgr/endpoint.c",
+    "src/core/iomgr/endpoint_pair_posix.c",
+    "src/core/iomgr/fd_posix.c",
+    "src/core/iomgr/iocp_windows.c",
+    "src/core/iomgr/iomgr.c",
+    "src/core/iomgr/iomgr_posix.c",
+    "src/core/iomgr/iomgr_windows.c",
+    "src/core/iomgr/pollset_kick.c",
+    "src/core/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/iomgr/pollset_posix.c",
+    "src/core/iomgr/pollset_windows.c",
+    "src/core/iomgr/resolve_address_posix.c",
+    "src/core/iomgr/resolve_address_windows.c",
+    "src/core/iomgr/sockaddr_utils.c",
+    "src/core/iomgr/socket_utils_common_posix.c",
+    "src/core/iomgr/socket_utils_linux.c",
+    "src/core/iomgr/socket_utils_posix.c",
+    "src/core/iomgr/socket_windows.c",
+    "src/core/iomgr/tcp_client_posix.c",
+    "src/core/iomgr/tcp_client_windows.c",
+    "src/core/iomgr/tcp_posix.c",
+    "src/core/iomgr/tcp_server_posix.c",
+    "src/core/iomgr/tcp_server_windows.c",
+    "src/core/iomgr/tcp_windows.c",
+    "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/wakeup_fd_eventfd.c",
+    "src/core/iomgr/wakeup_fd_nospecial.c",
+    "src/core/iomgr/wakeup_fd_pipe.c",
+    "src/core/iomgr/wakeup_fd_posix.c",
+    "src/core/json/json.c",
+    "src/core/json/json_reader.c",
+    "src/core/json/json_string.c",
+    "src/core/json/json_writer.c",
+    "src/core/statistics/census_init.c",
+    "src/core/statistics/census_log.c",
+    "src/core/statistics/census_rpc_stats.c",
+    "src/core/statistics/census_tracing.c",
+    "src/core/statistics/hash_table.c",
+    "src/core/statistics/window_stats.c",
+    "src/core/surface/byte_buffer.c",
+    "src/core/surface/byte_buffer_queue.c",
+    "src/core/surface/byte_buffer_reader.c",
+    "src/core/surface/call.c",
+    "src/core/surface/call_details.c",
+    "src/core/surface/call_log_batch.c",
+    "src/core/surface/channel.c",
+    "src/core/surface/channel_create.c",
+    "src/core/surface/client.c",
+    "src/core/surface/completion_queue.c",
+    "src/core/surface/event_string.c",
+    "src/core/surface/init.c",
+    "src/core/surface/lame_client.c",
+    "src/core/surface/metadata_array.c",
+    "src/core/surface/server.c",
+    "src/core/surface/server_chttp2.c",
+    "src/core/surface/server_create.c",
+    "src/core/surface/surface_trace.c",
+    "src/core/transport/chttp2/alpn.c",
+    "src/core/transport/chttp2/bin_encoder.c",
+    "src/core/transport/chttp2/frame_data.c",
+    "src/core/transport/chttp2/frame_goaway.c",
+    "src/core/transport/chttp2/frame_ping.c",
+    "src/core/transport/chttp2/frame_rst_stream.c",
+    "src/core/transport/chttp2/frame_settings.c",
+    "src/core/transport/chttp2/frame_window_update.c",
+    "src/core/transport/chttp2/hpack_parser.c",
+    "src/core/transport/chttp2/hpack_table.c",
+    "src/core/transport/chttp2/huffsyms.c",
+    "src/core/transport/chttp2/status_conversion.c",
+    "src/core/transport/chttp2/stream_encoder.c",
+    "src/core/transport/chttp2/stream_map.c",
+    "src/core/transport/chttp2/timeout_encoding.c",
+    "src/core/transport/chttp2/varint.c",
+    "src/core/transport/chttp2_transport.c",
+    "src/core/transport/metadata.c",
+    "src/core/transport/stream_op.c",
+    "src/core/transport/transport.c",
+  ],
+  hdrs = [
+    "include/grpc/byte_buffer.h",
+    "include/grpc/byte_buffer_reader.h",
+    "include/grpc/grpc.h",
+    "include/grpc/grpc_http.h",
+    "include/grpc/status.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    ":gpr",
+  ],
+)
+
+
+cc_library(
+  name = "grpc++",
+  srcs = [
+    "src/cpp/client/secure_credentials.h",
+    "src/cpp/server/secure_server_credentials.h",
+    "src/cpp/client/channel.h",
+    "src/cpp/proto/proto_utils.h",
+    "src/cpp/server/thread_pool.h",
+    "src/cpp/util/time.h",
+    "src/cpp/client/secure_credentials.cc",
+    "src/cpp/server/secure_server_credentials.cc",
+    "src/cpp/client/channel.cc",
+    "src/cpp/client/channel_arguments.cc",
+    "src/cpp/client/client_context.cc",
+    "src/cpp/client/client_unary_call.cc",
+    "src/cpp/client/create_channel.cc",
+    "src/cpp/client/credentials.cc",
+    "src/cpp/client/generic_stub.cc",
+    "src/cpp/client/insecure_credentials.cc",
+    "src/cpp/client/internal_stub.cc",
+    "src/cpp/common/call.cc",
+    "src/cpp/common/completion_queue.cc",
+    "src/cpp/common/rpc_method.cc",
+    "src/cpp/proto/proto_utils.cc",
+    "src/cpp/server/async_generic_service.cc",
+    "src/cpp/server/insecure_server_credentials.cc",
+    "src/cpp/server/server.cc",
+    "src/cpp/server/server_builder.cc",
+    "src/cpp/server/server_context.cc",
+    "src/cpp/server/server_credentials.cc",
+    "src/cpp/server/thread_pool.cc",
+    "src/cpp/util/byte_buffer.cc",
+    "src/cpp/util/slice.cc",
+    "src/cpp/util/status.cc",
+    "src/cpp/util/time.cc",
+  ],
+  hdrs = [
+    "include/grpc++/async_generic_service.h",
+    "include/grpc++/async_unary_call.h",
+    "include/grpc++/byte_buffer.h",
+    "include/grpc++/channel_arguments.h",
+    "include/grpc++/channel_interface.h",
+    "include/grpc++/client_context.h",
+    "include/grpc++/completion_queue.h",
+    "include/grpc++/config.h",
+    "include/grpc++/create_channel.h",
+    "include/grpc++/credentials.h",
+    "include/grpc++/generic_stub.h",
+    "include/grpc++/impl/call.h",
+    "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/internal_stub.h",
+    "include/grpc++/impl/rpc_method.h",
+    "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/service_type.h",
+    "include/grpc++/server.h",
+    "include/grpc++/server_builder.h",
+    "include/grpc++/server_context.h",
+    "include/grpc++/server_credentials.h",
+    "include/grpc++/slice.h",
+    "include/grpc++/status.h",
+    "include/grpc++/status_code_enum.h",
+    "include/grpc++/stream.h",
+    "include/grpc++/thread_pool_interface.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:protobuf_clib",
+    ":gpr",
+    ":grpc",
+  ],
+)
+
+
+cc_library(
+  name = "grpc++_unsecure",
+  srcs = [
+    "src/cpp/client/channel.h",
+    "src/cpp/proto/proto_utils.h",
+    "src/cpp/server/thread_pool.h",
+    "src/cpp/util/time.h",
+    "src/cpp/client/channel.cc",
+    "src/cpp/client/channel_arguments.cc",
+    "src/cpp/client/client_context.cc",
+    "src/cpp/client/client_unary_call.cc",
+    "src/cpp/client/create_channel.cc",
+    "src/cpp/client/credentials.cc",
+    "src/cpp/client/generic_stub.cc",
+    "src/cpp/client/insecure_credentials.cc",
+    "src/cpp/client/internal_stub.cc",
+    "src/cpp/common/call.cc",
+    "src/cpp/common/completion_queue.cc",
+    "src/cpp/common/rpc_method.cc",
+    "src/cpp/proto/proto_utils.cc",
+    "src/cpp/server/async_generic_service.cc",
+    "src/cpp/server/insecure_server_credentials.cc",
+    "src/cpp/server/server.cc",
+    "src/cpp/server/server_builder.cc",
+    "src/cpp/server/server_context.cc",
+    "src/cpp/server/server_credentials.cc",
+    "src/cpp/server/thread_pool.cc",
+    "src/cpp/util/byte_buffer.cc",
+    "src/cpp/util/slice.cc",
+    "src/cpp/util/status.cc",
+    "src/cpp/util/time.cc",
+  ],
+  hdrs = [
+    "include/grpc++/async_generic_service.h",
+    "include/grpc++/async_unary_call.h",
+    "include/grpc++/byte_buffer.h",
+    "include/grpc++/channel_arguments.h",
+    "include/grpc++/channel_interface.h",
+    "include/grpc++/client_context.h",
+    "include/grpc++/completion_queue.h",
+    "include/grpc++/config.h",
+    "include/grpc++/create_channel.h",
+    "include/grpc++/credentials.h",
+    "include/grpc++/generic_stub.h",
+    "include/grpc++/impl/call.h",
+    "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/internal_stub.h",
+    "include/grpc++/impl/rpc_method.h",
+    "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/service_type.h",
+    "include/grpc++/server.h",
+    "include/grpc++/server_builder.h",
+    "include/grpc++/server_context.h",
+    "include/grpc++/server_credentials.h",
+    "include/grpc++/slice.h",
+    "include/grpc++/status.h",
+    "include/grpc++/status_code_enum.h",
+    "include/grpc++/stream.h",
+    "include/grpc++/thread_pool_interface.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:protobuf_clib",
+    ":gpr",
+    ":grpc_unsecure",
+  ],
+)
+
+
+cc_library(
+  name = "grpc_plugin_support",
+  srcs = [
+    "src/compiler/config.h",
+    "src/compiler/cpp_generator.h",
+    "src/compiler/cpp_generator_helpers.h",
+    "src/compiler/generator_helpers.h",
+    "src/compiler/objective_c_generator.h",
+    "src/compiler/objective_c_generator_helpers.h",
+    "src/compiler/python_generator.h",
+    "src/compiler/ruby_generator.h",
+    "src/compiler/ruby_generator_helpers-inl.h",
+    "src/compiler/ruby_generator_map-inl.h",
+    "src/compiler/ruby_generator_string-inl.h",
+    "src/compiler/cpp_generator.cc",
+    "src/compiler/objective_c_generator.cc",
+    "src/compiler/python_generator.cc",
+    "src/compiler/ruby_generator.cc",
+  ],
+  hdrs = [
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+  ],
+)
+
+
+cc_library(
+  name = "grpc_csharp_ext",
+  srcs = [
+    "src/csharp/ext/grpc_csharp_ext.c",
+  ],
+  hdrs = [
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    ":gpr",
+    ":grpc",
+  ],
+)
+
+
+
+cc_binary(
+  name = "grpc_cpp_plugin",
+  srcs = [
+    "src/compiler/cpp_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+cc_binary(
+  name = "grpc_objective_c_plugin",
+  srcs = [
+    "src/compiler/objective_c_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+cc_binary(
+  name = "grpc_python_plugin",
+  srcs = [
+    "src/compiler/python_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+cc_binary(
+  name = "grpc_ruby_plugin",
+  srcs = [
+    "src/compiler/ruby_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+
+
+
diff --git a/Makefile b/Makefile
index 857bde1..4ba10c3 100644
--- a/Makefile
+++ b/Makefile
@@ -94,6 +94,15 @@
 LDFLAGS_dbg =
 DEFINES_dbg = _DEBUG DEBUG
 
+VALID_CONFIG_mutrace = 1
+CC_mutrace = $(DEFAULT_CC)
+CXX_mutrace = $(DEFAULT_CXX)
+LD_mutrace = $(DEFAULT_CC)
+LDXX_mutrace = $(DEFAULT_CXX)
+CPPFLAGS_mutrace = -O0
+LDFLAGS_mutrace = -rdynamic
+DEFINES_mutrace = _DEBUG DEBUG
+
 VALID_CONFIG_valgrind = 1
 REQUIRE_CUSTOM_LIBRARIES_valgrind = 1
 CC_valgrind = $(DEFAULT_CC)
@@ -218,7 +227,6 @@
 CXXFLAGS += -std=c++11
 else
 CXXFLAGS += -std=c++0x
-DEFINES += GRPC_OLD_CXX
 endif
 CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
 LDFLAGS += -g
@@ -276,7 +284,7 @@
 Q = @
 endif
 
-VERSION = 0.5.0.0
+VERSION = 0.6.0.0
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -447,7 +455,7 @@
 
 .SECONDARY = %.pb.h %.pb.cc
 
-PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
+PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
 ifeq ($(DEP_MISSING),)
 all: static shared plugins
 dep_error:
@@ -616,10 +624,14 @@
 transport_security_test: $(BINDIR)/$(CONFIG)/transport_security_test
 async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
 channel_arguments_test: $(BINDIR)/$(CONFIG)/channel_arguments_test
+cli_call_test: $(BINDIR)/$(CONFIG)/cli_call_test
 credentials_test: $(BINDIR)/$(CONFIG)/credentials_test
+cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test
 end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
 generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
+grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
 grpc_cpp_plugin: $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
+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
 interop_client: $(BINDIR)/$(CONFIG)/interop_client
@@ -629,6 +641,7 @@
 pubsub_publisher_test: $(BINDIR)/$(CONFIG)/pubsub_publisher_test
 pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
 qps_driver: $(BINDIR)/$(CONFIG)/qps_driver
+qps_smoke_test: $(BINDIR)/$(CONFIG)/qps_smoke_test
 qps_worker: $(BINDIR)/$(CONFIG)/qps_worker
 status_test: $(BINDIR)/$(CONFIG)/status_test
 thread_pool_test: $(BINDIR)/$(CONFIG)/thread_pool_test
@@ -1069,7 +1082,7 @@
 
 buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/metadata_buffer_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test
 
-buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test
+buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_smoke_test $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test
 
 test: test_c test_cxx
 
@@ -1901,8 +1914,12 @@
 	$(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing channel_arguments_test"
 	$(Q) $(BINDIR)/$(CONFIG)/channel_arguments_test || ( echo test channel_arguments_test failed ; exit 1 )
+	$(E) "[RUN]     Testing cli_call_test"
+	$(Q) $(BINDIR)/$(CONFIG)/cli_call_test || ( echo test cli_call_test failed ; exit 1 )
 	$(E) "[RUN]     Testing credentials_test"
 	$(Q) $(BINDIR)/$(CONFIG)/credentials_test || ( echo test credentials_test failed ; exit 1 )
+	$(E) "[RUN]     Testing cxx_time_test"
+	$(Q) $(BINDIR)/$(CONFIG)/cxx_time_test || ( echo test cxx_time_test failed ; exit 1 )
 	$(E) "[RUN]     Testing end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing generic_end2end_test"
@@ -1985,92 +2002,152 @@
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/examples/pubsub/empty.pb.cc: protoc_dep_error
+$(GENDIR)/examples/pubsub/empty.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/examples/pubsub/empty.pb.cc: examples/pubsub/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/examples/pubsub/empty.grpc.pb.cc: examples/pubsub/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/examples/pubsub/label.pb.cc: protoc_dep_error
+$(GENDIR)/examples/pubsub/label.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/examples/pubsub/label.pb.cc: examples/pubsub/label.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/examples/pubsub/label.grpc.pb.cc: examples/pubsub/label.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/examples/pubsub/pubsub.pb.cc: protoc_dep_error
+$(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/examples/pubsub/pubsub.pb.cc: examples/pubsub/pubsub.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc: examples/pubsub/pubsub.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/interop/empty.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/interop/empty.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/test/cpp/interop/empty.pb.cc: test/cpp/interop/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/interop/empty.grpc.pb.cc: test/cpp/interop/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/interop/messages.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/interop/messages.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/test/cpp/interop/messages.pb.cc: test/cpp/interop/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/interop/messages.grpc.pb.cc: test/cpp/interop/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/interop/test.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/interop/test.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/test/cpp/interop/test.pb.cc: test/cpp/interop/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/interop/test.grpc.pb.cc: test/cpp/interop/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/qps/qpstest.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/test/cpp/qps/qpstest.pb.cc: test/cpp/qps/qpstest.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc: test/cpp/qps/qpstest.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/util/echo.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/util/echo.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/test/cpp/util/echo.pb.cc: test/cpp/util/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/util/echo.grpc.pb.cc: test/cpp/util/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc: test/cpp/util/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc: test/cpp/util/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/test/cpp/util/messages.pb.cc: protoc_dep_error
+$(GENDIR)/test/cpp/util/messages.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/test/cpp/util/messages.pb.cc: test/cpp/util/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/test/cpp/util/messages.grpc.pb.cc: test/cpp/util/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 
@@ -2147,10 +2224,11 @@
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(prefix)/lib/gpr.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr-imp.a $(prefix)/lib/libgpr-imp.a
 else
-ifneq ($(SYSTEM),Darwin)
 	$(E) "[INSTALL] Installing libgpr.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so.0
 	$(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so
 endif
 endif
@@ -2160,10 +2238,11 @@
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(prefix)/lib/grpc.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc-imp.a $(prefix)/lib/libgrpc-imp.a
 else
-ifneq ($(SYSTEM),Darwin)
 	$(E) "[INSTALL] Installing libgrpc.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so.0
 	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so
 endif
 endif
@@ -2173,10 +2252,11 @@
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT) $(prefix)/lib/grpc_unsecure.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure-imp.a $(prefix)/lib/libgrpc_unsecure-imp.a
 else
-ifneq ($(SYSTEM),Darwin)
 	$(E) "[INSTALL] Installing libgrpc_unsecure.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so.0
 	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so
 endif
 endif
@@ -2194,10 +2274,11 @@
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT) $(prefix)/lib/grpc++.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++-imp.a $(prefix)/lib/libgrpc++-imp.a
 else
-ifneq ($(SYSTEM),Darwin)
 	$(E) "[INSTALL] Installing libgrpc++.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so.0
 	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so
 endif
 endif
@@ -2207,10 +2288,11 @@
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/grpc++_unsecure.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure-imp.a $(prefix)/lib/libgrpc++_unsecure-imp.a
 else
-ifneq ($(SYSTEM),Darwin)
 	$(E) "[INSTALL] Installing libgrpc++_unsecure.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so.0
 	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so
 endif
 endif
@@ -2228,10 +2310,11 @@
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/grpc_csharp_ext.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext-imp.a $(prefix)/lib/libgrpc_csharp_ext-imp.a
 else
-ifneq ($(SYSTEM),Darwin)
 	$(E) "[INSTALL] Installing libgrpc_csharp_ext.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so.0
 	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so
 endif
 endif
@@ -2250,6 +2333,8 @@
 	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(prefix)/bin/grpc_cpp_plugin
 	$(Q) $(INSTALL) -d $(prefix)/bin
+	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(prefix)/bin/grpc_objective_c_plugin
+	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_python_plugin $(prefix)/bin/grpc_python_plugin
 	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin
@@ -2292,6 +2377,7 @@
     src/core/support/alloc.c \
     src/core/support/cancellable.c \
     src/core/support/cmdline.c \
+    src/core/support/cpu_iphone.c \
     src/core/support/cpu_linux.c \
     src/core/support/cpu_posix.c \
     src/core/support/cpu_windows.c \
@@ -2317,6 +2403,7 @@
     src/core/support/sync.c \
     src/core/support/sync_posix.c \
     src/core/support/sync_win32.c \
+    src/core/support/thd.c \
     src/core/support/thd_posix.c \
     src/core/support/thd_win32.c \
     src/core/support/time.c \
@@ -2331,6 +2418,7 @@
     include/grpc/support/atm_win32.h \
     include/grpc/support/cancellable_platform.h \
     include/grpc/support/cmdline.h \
+    include/grpc/support/cpu.h \
     include/grpc/support/histogram.h \
     include/grpc/support/host_port.h \
     include/grpc/support/log.h \
@@ -2369,7 +2457,7 @@
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgpr.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS)
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.0 -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS)
 	$(Q) ln -sf libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr.so.0
@@ -2384,6 +2472,7 @@
 $(OBJDIR)/$(CONFIG)/src/core/support/alloc.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/cancellable.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/cmdline.o: 
+$(OBJDIR)/$(CONFIG)/src/core/support/cpu_iphone.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/cpu_linux.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/cpu_posix.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/cpu_windows.o: 
@@ -2409,6 +2498,7 @@
 $(OBJDIR)/$(CONFIG)/src/core/support/sync.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/sync_posix.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/sync_win32.o: 
+$(OBJDIR)/$(CONFIG)/src/core/support/thd.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/thd_posix.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/thd_win32.o: 
 $(OBJDIR)/$(CONFIG)/src/core/support/time.o: 
@@ -2547,6 +2637,7 @@
     src/core/surface/byte_buffer_reader.c \
     src/core/surface/call.c \
     src/core/surface/call_details.c \
+    src/core/surface/call_log_batch.c \
     src/core/surface/channel.c \
     src/core/surface/channel_create.c \
     src/core/surface/client.c \
@@ -2585,6 +2676,7 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/grpc.h \
+    include/grpc/grpc_http.h \
     include/grpc/status.h \
 
 LIBGRPC_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_SRC))))
@@ -2692,6 +2784,7 @@
 src/core/surface/byte_buffer_reader.c: $(OPENSSL_DEP)
 src/core/surface/call.c: $(OPENSSL_DEP)
 src/core/surface/call_details.c: $(OPENSSL_DEP)
+src/core/surface/call_log_batch.c: $(OPENSSL_DEP)
 src/core/surface/channel.c: $(OPENSSL_DEP)
 src/core/surface/channel_create.c: $(OPENSSL_DEP)
 src/core/surface/client.c: $(OPENSSL_DEP)
@@ -2754,7 +2847,7 @@
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LDLIBS_SECURE) $(OPENSSL_MERGE_LIBS) -lgpr
 	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.so.0
@@ -2854,6 +2947,7 @@
 $(OBJDIR)/$(CONFIG)/src/core/surface/byte_buffer_reader.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/call.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/call_details.o: 
+$(OBJDIR)/$(CONFIG)/src/core/surface/call_log_batch.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/channel.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/channel_create.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/client.o: 
@@ -3029,6 +3123,7 @@
     src/core/surface/byte_buffer_reader.c \
     src/core/surface/call.c \
     src/core/surface/call_details.c \
+    src/core/surface/call_log_batch.c \
     src/core/surface/channel.c \
     src/core/surface/channel_create.c \
     src/core/surface/client.c \
@@ -3066,6 +3161,7 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/grpc.h \
+    include/grpc/grpc_http.h \
     include/grpc/status.h \
 
 LIBGRPC_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_UNSECURE_SRC))))
@@ -3091,7 +3187,7 @@
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) -lgpr
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_unsecure.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) -lgpr
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) -lgpr
 	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.so.0
@@ -3167,6 +3263,7 @@
 $(OBJDIR)/$(CONFIG)/src/core/surface/byte_buffer_reader.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/call.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/call_details.o: 
+$(OBJDIR)/$(CONFIG)/src/core/surface/call_log_batch.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/channel.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/channel_create.o: 
 $(OBJDIR)/$(CONFIG)/src/core/surface/client.o: 
@@ -3210,6 +3307,7 @@
     src/cpp/client/client_unary_call.cc \
     src/cpp/client/create_channel.cc \
     src/cpp/client/credentials.cc \
+    src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
     src/cpp/client/internal_stub.cc \
     src/cpp/common/call.cc \
@@ -3239,12 +3337,19 @@
     include/grpc++/config.h \
     include/grpc++/create_channel.h \
     include/grpc++/credentials.h \
+    include/grpc++/generic_stub.h \
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
     include/grpc++/impl/internal_stub.h \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
     include/grpc++/impl/service_type.h \
+    include/grpc++/impl/sync.h \
+    include/grpc++/impl/sync_cxx11.h \
+    include/grpc++/impl/sync_no_cxx11.h \
+    include/grpc++/impl/thd.h \
+    include/grpc++/impl/thd_cxx11.h \
+    include/grpc++/impl/thd_no_cxx11.h \
     include/grpc++/server.h \
     include/grpc++/server_builder.h \
     include/grpc++/server_context.h \
@@ -3297,6 +3402,7 @@
 src/cpp/client/client_unary_call.cc: $(OPENSSL_DEP)
 src/cpp/client/create_channel.cc: $(OPENSSL_DEP)
 src/cpp/client/credentials.cc: $(OPENSSL_DEP)
+src/cpp/client/generic_stub.cc: $(OPENSSL_DEP)
 src/cpp/client/insecure_credentials.cc: $(OPENSSL_DEP)
 src/cpp/client/internal_stub.cc: $(OPENSSL_DEP)
 src/cpp/common/call.cc: $(OPENSSL_DEP)
@@ -3337,7 +3443,7 @@
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc++.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc
 else
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc
 	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++.so.0
@@ -3363,6 +3469,7 @@
 $(OBJDIR)/$(CONFIG)/src/cpp/client/client_unary_call.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/create_channel.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/credentials.o: 
+$(OBJDIR)/$(CONFIG)/src/cpp/client/generic_stub.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/insecure_credentials.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/internal_stub.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/common/call.o: 
@@ -3383,9 +3490,10 @@
 
 
 LIBGRPC++_TEST_UTIL_SRC = \
-    $(GENDIR)/test/cpp/util/messages.pb.cc \
-    $(GENDIR)/test/cpp/util/echo.pb.cc \
-    $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc \
+    $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc \
+    $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc \
+    $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc \
+    test/cpp/util/cli_call.cc \
     test/cpp/util/create_test_channel.cc \
 
 
@@ -3416,6 +3524,7 @@
 test/cpp/util/messages.proto: $(OPENSSL_DEP)
 test/cpp/util/echo.proto: $(OPENSSL_DEP)
 test/cpp/util/echo_duplicate.proto: $(OPENSSL_DEP)
+test/cpp/util/cli_call.cc: $(OPENSSL_DEP)
 test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP)
 endif
 
@@ -3444,7 +3553,8 @@
 
 
 
-$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o:     $(GENDIR)/test/cpp/util/messages.pb.cc    $(GENDIR)/test/cpp/util/echo.pb.cc    $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o:     $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc    $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc    $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o:     $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc    $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc    $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc
 
 
 LIBGRPC++_UNSECURE_SRC = \
@@ -3454,6 +3564,7 @@
     src/cpp/client/client_unary_call.cc \
     src/cpp/client/create_channel.cc \
     src/cpp/client/credentials.cc \
+    src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
     src/cpp/client/internal_stub.cc \
     src/cpp/common/call.cc \
@@ -3483,12 +3594,19 @@
     include/grpc++/config.h \
     include/grpc++/create_channel.h \
     include/grpc++/credentials.h \
+    include/grpc++/generic_stub.h \
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
     include/grpc++/impl/internal_stub.h \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
     include/grpc++/impl/service_type.h \
+    include/grpc++/impl/sync.h \
+    include/grpc++/impl/sync_cxx11.h \
+    include/grpc++/impl/sync_no_cxx11.h \
+    include/grpc++/impl/thd.h \
+    include/grpc++/impl/thd_cxx11.h \
+    include/grpc++/impl/thd_no_cxx11.h \
     include/grpc++/server.h \
     include/grpc++/server_builder.h \
     include/grpc++/server_context.h \
@@ -3536,7 +3654,7 @@
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc++_unsecure.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
 else
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
 	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.so.0
@@ -3556,6 +3674,7 @@
 $(OBJDIR)/$(CONFIG)/src/cpp/client/client_unary_call.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/create_channel.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/credentials.o: 
+$(OBJDIR)/$(CONFIG)/src/cpp/client/generic_stub.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/insecure_credentials.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/client/internal_stub.o: 
 $(OBJDIR)/$(CONFIG)/src/cpp/common/call.o: 
@@ -3575,10 +3694,52 @@
 $(OBJDIR)/$(CONFIG)/src/cpp/util/time.o: 
 
 
+LIBGRPC_PLUGIN_SUPPORT_SRC = \
+    src/compiler/cpp_generator.cc \
+    src/compiler/objective_c_generator.cc \
+    src/compiler/python_generator.cc \
+    src/compiler/ruby_generator.cc \
+
+
+LIBGRPC_PLUGIN_SUPPORT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_PLUGIN_SUPPORT_SRC))))
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a: $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBGRPC_PLUGIN_SUPPORT_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(LIBGRPC_PLUGIN_SUPPORT_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
+endif
+
+
+
+
+endif
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC_PLUGIN_SUPPORT_OBJS:.o=.dep)
+endif
+
+$(OBJDIR)/$(CONFIG)/src/compiler/cpp_generator.o: 
+$(OBJDIR)/$(CONFIG)/src/compiler/objective_c_generator.o: 
+$(OBJDIR)/$(CONFIG)/src/compiler/python_generator.o: 
+$(OBJDIR)/$(CONFIG)/src/compiler/ruby_generator.o: 
+
+
 LIBPUBSUB_CLIENT_LIB_SRC = \
-    $(GENDIR)/examples/pubsub/label.pb.cc \
-    $(GENDIR)/examples/pubsub/empty.pb.cc \
-    $(GENDIR)/examples/pubsub/pubsub.pb.cc \
+    $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc \
+    $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc \
+    $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc \
     examples/pubsub/publisher.cc \
     examples/pubsub/subscriber.cc \
 
@@ -3639,13 +3800,14 @@
 
 
 
-$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher.o:     $(GENDIR)/examples/pubsub/label.pb.cc    $(GENDIR)/examples/pubsub/empty.pb.cc    $(GENDIR)/examples/pubsub/pubsub.pb.cc
-$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber.o:     $(GENDIR)/examples/pubsub/label.pb.cc    $(GENDIR)/examples/pubsub/empty.pb.cc    $(GENDIR)/examples/pubsub/pubsub.pb.cc
+$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher.o:     $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc    $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc    $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber.o:     $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc    $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc    $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc
 
 
 LIBQPS_SRC = \
-    $(GENDIR)/test/cpp/qps/qpstest.pb.cc \
+    $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc \
     test/cpp/qps/driver.cc \
+    test/cpp/qps/report.cc \
     test/cpp/qps/timer.cc \
 
 
@@ -3675,6 +3837,7 @@
 # otherwise parallel compilation will fail if a source is compiled first.
 test/cpp/qps/qpstest.proto: $(OPENSSL_DEP)
 test/cpp/qps/driver.cc: $(OPENSSL_DEP)
+test/cpp/qps/report.cc: $(OPENSSL_DEP)
 test/cpp/qps/timer.cc: $(OPENSSL_DEP)
 endif
 
@@ -3701,8 +3864,9 @@
 endif
 
 
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
 
 
 LIBGRPC_CSHARP_EXT_SRC = \
@@ -3754,7 +3918,7 @@
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) -lgpr -lgrpc
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_csharp_ext.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) -lgpr -lgrpc
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) -lgpr -lgrpc
 	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.so.0
@@ -7971,6 +8135,48 @@
 endif
 
 
+CLI_CALL_TEST_SRC = \
+    test/cpp/util/cli_call_test.cc \
+
+CLI_CALL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CLI_CALL_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/cli_call_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)/cli_call_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/cli_call_test: $(PROTOBUF_DEP) $(CLI_CALL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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) $(CLI_CALL_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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) -o $(BINDIR)/$(CONFIG)/cli_call_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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_cli_call_test: $(CLI_CALL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CLI_CALL_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 CREDENTIALS_TEST_SRC = \
     test/cpp/client/credentials_test.cc \
 
@@ -8013,6 +8219,48 @@
 endif
 
 
+CXX_TIME_TEST_SRC = \
+    test/cpp/util/time_test.cc \
+
+CXX_TIME_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CXX_TIME_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/cxx_time_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)/cxx_time_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/cxx_time_test: $(PROTOBUF_DEP) $(CXX_TIME_TEST_OBJS) $(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) $(CXX_TIME_TEST_OBJS) $(GTEST_LIB) $(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) -o $(BINDIR)/$(CONFIG)/cxx_time_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/time_test.o:  $(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_cxx_time_test: $(CXX_TIME_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CXX_TIME_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 END2END_TEST_SRC = \
     test/cpp/end2end/end2end_test.cc \
 
@@ -8097,8 +8345,49 @@
 endif
 
 
+GRPC_CLI_SRC = \
+    test/cpp/util/grpc_cli.cc \
+
+GRPC_CLI_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CLI_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/grpc_cli: 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_cli: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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_CLI_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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) -o $(BINDIR)/$(CONFIG)/grpc_cli
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_cli.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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_cli: $(GRPC_CLI_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_CLI_OBJS:.o=.dep)
+endif
+endif
+
+
 GRPC_CPP_PLUGIN_SRC = \
-    src/compiler/cpp_generator.cc \
     src/compiler/cpp_plugin.cc \
 
 GRPC_CPP_PLUGIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_CPP_PLUGIN_SRC))))
@@ -8112,15 +8401,14 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/grpc_cpp_plugin: $(PROTOBUF_DEP) $(GRPC_CPP_PLUGIN_OBJS)
+$(BINDIR)/$(CONFIG)/grpc_cpp_plugin: $(PROTOBUF_DEP) $(GRPC_CPP_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 	$(E) "[HOSTLD]  Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_CPP_PLUGIN_OBJS) $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
+	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_CPP_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_cpp_plugin
 
 endif
 
-$(OBJDIR)/$(CONFIG)/src/compiler/cpp_generator.o: 
-$(OBJDIR)/$(CONFIG)/src/compiler/cpp_plugin.o: 
+$(OBJDIR)/$(CONFIG)/src/compiler/cpp_plugin.o:  $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 
 deps_grpc_cpp_plugin: $(GRPC_CPP_PLUGIN_OBJS:.o=.dep)
 
@@ -8129,8 +8417,37 @@
 endif
 
 
+GRPC_OBJECTIVE_C_PLUGIN_SRC = \
+    src/compiler/objective_c_plugin.cc \
+
+GRPC_OBJECTIVE_C_PLUGIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_OBJECTIVE_C_PLUGIN_SRC))))
+
+
+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_objective_c_plugin: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_objective_c_plugin: $(PROTOBUF_DEP) $(GRPC_OBJECTIVE_C_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
+	$(E) "[HOSTLD]  Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_OBJECTIVE_C_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/compiler/objective_c_plugin.o:  $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
+
+deps_grpc_objective_c_plugin: $(GRPC_OBJECTIVE_C_PLUGIN_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_OBJECTIVE_C_PLUGIN_OBJS:.o=.dep)
+endif
+
+
 GRPC_PYTHON_PLUGIN_SRC = \
-    src/compiler/python_generator.cc \
     src/compiler/python_plugin.cc \
 
 GRPC_PYTHON_PLUGIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_PYTHON_PLUGIN_SRC))))
@@ -8144,15 +8461,14 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/grpc_python_plugin: $(PROTOBUF_DEP) $(GRPC_PYTHON_PLUGIN_OBJS)
+$(BINDIR)/$(CONFIG)/grpc_python_plugin: $(PROTOBUF_DEP) $(GRPC_PYTHON_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 	$(E) "[HOSTLD]  Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_PYTHON_PLUGIN_OBJS) $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_python_plugin
+	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_PYTHON_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_python_plugin
 
 endif
 
-$(OBJDIR)/$(CONFIG)/src/compiler/python_generator.o: 
-$(OBJDIR)/$(CONFIG)/src/compiler/python_plugin.o: 
+$(OBJDIR)/$(CONFIG)/src/compiler/python_plugin.o:  $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 
 deps_grpc_python_plugin: $(GRPC_PYTHON_PLUGIN_OBJS:.o=.dep)
 
@@ -8162,7 +8478,6 @@
 
 
 GRPC_RUBY_PLUGIN_SRC = \
-    src/compiler/ruby_generator.cc \
     src/compiler/ruby_plugin.cc \
 
 GRPC_RUBY_PLUGIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_RUBY_PLUGIN_SRC))))
@@ -8176,15 +8491,14 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/grpc_ruby_plugin: $(PROTOBUF_DEP) $(GRPC_RUBY_PLUGIN_OBJS)
+$(BINDIR)/$(CONFIG)/grpc_ruby_plugin: $(PROTOBUF_DEP) $(GRPC_RUBY_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 	$(E) "[HOSTLD]  Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_RUBY_PLUGIN_OBJS) $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
+	$(Q) $(HOST_LDXX) $(HOST_LDFLAGS) $(GRPC_RUBY_PLUGIN_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(HOST_LDLIBSXX) $(HOST_LDLIBS_PROTOC) $(HOST_LDLIBS) $(HOST_LDLIBS_PROTOC) -o $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
 
 endif
 
-$(OBJDIR)/$(CONFIG)/src/compiler/ruby_generator.o: 
-$(OBJDIR)/$(CONFIG)/src/compiler/ruby_plugin.o: 
+$(OBJDIR)/$(CONFIG)/src/compiler/ruby_plugin.o:  $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 
 deps_grpc_ruby_plugin: $(GRPC_RUBY_PLUGIN_OBJS:.o=.dep)
 
@@ -8194,9 +8508,9 @@
 
 
 INTEROP_CLIENT_SRC = \
-    $(GENDIR)/test/cpp/interop/empty.pb.cc \
-    $(GENDIR)/test/cpp/interop/messages.pb.cc \
-    $(GENDIR)/test/cpp/interop/test.pb.cc \
+    $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \
     test/cpp/interop/client.cc \
 
 INTEROP_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INTEROP_CLIENT_SRC))))
@@ -8242,9 +8556,9 @@
 
 
 INTEROP_SERVER_SRC = \
-    $(GENDIR)/test/cpp/interop/empty.pb.cc \
-    $(GENDIR)/test/cpp/interop/messages.pb.cc \
-    $(GENDIR)/test/cpp/interop/test.pb.cc \
+    $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \
     test/cpp/interop/server.cc \
 
 INTEROP_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INTEROP_SERVER_SRC))))
@@ -8499,6 +8813,48 @@
 endif
 
 
+QPS_SMOKE_TEST_SRC = \
+    test/cpp/qps/smoke_test.cc \
+
+QPS_SMOKE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_SMOKE_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/qps_smoke_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)/qps_smoke_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/qps_smoke_test: $(PROTOBUF_DEP) $(QPS_SMOKE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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) $(QPS_SMOKE_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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) -o $(BINDIR)/$(CONFIG)/qps_smoke_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/smoke_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.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_qps_smoke_test: $(QPS_SMOKE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(QPS_SMOKE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 QPS_WORKER_SRC = \
     test/cpp/qps/client_async.cc \
     test/cpp/qps/client_sync.cc \
diff --git a/README.md b/README.md
index fa60b83..b78745f 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,10 @@
 
 Copyright 2015 Google Inc.
 
+#Documentation
+
+You can find more detailed documentation and examples in the [grpc-common repository](http://github.com/grpc/grpc-common).
+
 #Installation
 
 See grpc/INSTALL for installation instructions for various platforms.
@@ -25,10 +29,6 @@
 Java source code is in [grpc-java] (http://github.com/grpc/grpc-java) repository. 
 Go source code is in [grpc-go] (http://github.com/grpc/grpc-go) repository.
 
-#Documentation
-
-You can find more detailed documentation and examples in the [grpc-common repository](http://github.com/grpc/grpc-common).
-
 #Current Status of libraries
 
 Libraries in different languages are in different state of development. We are seeking contributions for all of these libraries.
diff --git a/build.json b/build.json
index 999e140..0a7b81d 100644
--- a/build.json
+++ b/build.json
@@ -3,7 +3,7 @@
     "#": "The public version number of the library.",
     "version": {
       "major": 0,
-      "minor": 5,
+      "minor": 6,
       "micro": 0,
       "build": 0
     }
@@ -22,12 +22,19 @@
         "include/grpc++/config.h",
         "include/grpc++/create_channel.h",
         "include/grpc++/credentials.h",
+        "include/grpc++/generic_stub.h",
         "include/grpc++/impl/call.h",
         "include/grpc++/impl/client_unary_call.h",
         "include/grpc++/impl/internal_stub.h",
         "include/grpc++/impl/rpc_method.h",
         "include/grpc++/impl/rpc_service_method.h",
         "include/grpc++/impl/service_type.h",
+        "include/grpc++/impl/sync.h",
+        "include/grpc++/impl/sync_cxx11.h",
+        "include/grpc++/impl/sync_no_cxx11.h",
+        "include/grpc++/impl/thd.h",
+        "include/grpc++/impl/thd_cxx11.h",
+        "include/grpc++/impl/thd_no_cxx11.h",
         "include/grpc++/server.h",
         "include/grpc++/server_builder.h",
         "include/grpc++/server_context.h",
@@ -51,6 +58,7 @@
         "src/cpp/client/client_unary_call.cc",
         "src/cpp/client/create_channel.cc",
         "src/cpp/client/credentials.cc",
+        "src/cpp/client/generic_stub.cc",
         "src/cpp/client/insecure_credentials.cc",
         "src/cpp/client/internal_stub.cc",
         "src/cpp/common/call.cc",
@@ -76,6 +84,7 @@
         "include/grpc/byte_buffer.h",
         "include/grpc/byte_buffer_reader.h",
         "include/grpc/grpc.h",
+        "include/grpc/grpc_http.h",
         "include/grpc/status.h"
       ],
       "headers": [
@@ -143,6 +152,7 @@
         "src/core/surface/init.h",
         "src/core/surface/server.h",
         "src/core/surface/surface_trace.h",
+        "src/core/transport/chttp2/alpn.h",
         "src/core/transport/chttp2/bin_encoder.h",
         "src/core/transport/chttp2/frame.h",
         "src/core/transport/chttp2/frame_data.h",
@@ -230,6 +240,7 @@
         "src/core/surface/byte_buffer_reader.c",
         "src/core/surface/call.c",
         "src/core/surface/call_details.c",
+        "src/core/surface/call_log_batch.c",
         "src/core/surface/channel.c",
         "src/core/surface/channel_create.c",
         "src/core/surface/client.c",
@@ -278,6 +289,7 @@
         "include/grpc/support/atm_win32.h",
         "include/grpc/support/cancellable_platform.h",
         "include/grpc/support/cmdline.h",
+        "include/grpc/support/cpu.h",
         "include/grpc/support/histogram.h",
         "include/grpc/support/host_port.h",
         "include/grpc/support/log.h",
@@ -305,6 +317,7 @@
         "src/core/support/alloc.c",
         "src/core/support/cancellable.c",
         "src/core/support/cmdline.c",
+        "src/core/support/cpu_iphone.c",
         "src/core/support/cpu_linux.c",
         "src/core/support/cpu_posix.c",
         "src/core/support/cpu_windows.c",
@@ -330,6 +343,7 @@
         "src/core/support/sync.c",
         "src/core/support/sync_posix.c",
         "src/core/support/sync_win32.c",
+        "src/core/support/thd.c",
         "src/core/support/thd_posix.c",
         "src/core/support/thd_win32.c",
         "src/core/support/time.c",
@@ -343,6 +357,9 @@
       "name": "gpr_test_util",
       "build": "private",
       "language": "c",
+      "headers": [
+        "test/core/util/test_config.h"
+      ],
       "src": [
         "test/core/util/test_config.c"
       ],
@@ -367,6 +384,7 @@
         "src/core/security/base64.h",
         "src/core/security/credentials.h",
         "src/core/security/json_token.h",
+        "src/core/security/secure_endpoint.h",
         "src/core/security/secure_transport_setup.h",
         "src/core/security/security_context.h",
         "src/core/tsi/fake_transport_security.h",
@@ -426,6 +444,7 @@
       ],
       "deps": [
         "gpr",
+        "gpr_test_util",
         "grpc"
       ],
       "vs_project_guid": "{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}"
@@ -451,6 +470,10 @@
       "name": "grpc++",
       "build": "all",
       "language": "c++",
+      "headers": [
+        "src/cpp/client/secure_credentials.h",
+        "src/cpp/server/secure_server_credentials.h"
+      ],
       "src": [
         "src/cpp/client/secure_credentials.cc",
         "src/cpp/server/secure_server_credentials.cc"
@@ -474,6 +497,7 @@
         "test/cpp/util/messages.proto",
         "test/cpp/util/echo.proto",
         "test/cpp/util/echo_duplicate.proto",
+        "test/cpp/util/cli_call.cc",
         "test/cpp/util/create_test_channel.cc"
       ]
     },
@@ -492,6 +516,32 @@
       "secure": "no"
     },
     {
+      "name": "grpc_plugin_support",
+      "build": "protoc",
+      "language": "c++",
+      "headers": [
+        "src/compiler/config.h",
+        "src/compiler/cpp_generator.h",
+        "src/compiler/cpp_generator_helpers.h",
+        "src/compiler/generator_helpers.h",
+        "src/compiler/objective_c_generator.h",
+        "src/compiler/objective_c_generator_helpers.h",
+        "src/compiler/python_generator.h",
+        "src/compiler/ruby_generator.h",
+        "src/compiler/ruby_generator_helpers-inl.h",
+        "src/compiler/ruby_generator_map-inl.h",
+        "src/compiler/ruby_generator_string-inl.h"
+      ],
+      "src": [
+        "src/compiler/cpp_generator.cc",
+        "src/compiler/objective_c_generator.cc",
+        "src/compiler/python_generator.cc",
+        "src/compiler/ruby_generator.cc"
+      ],
+      "deps": [],
+      "secure": "no"
+    },
+    {
       "name": "pubsub_client_lib",
       "build": "private",
       "language": "c++",
@@ -514,11 +564,13 @@
       "language": "c++",
       "headers": [
         "test/cpp/qps/driver.h",
+        "test/cpp/qps/report.h",
         "test/cpp/qps/timer.h"
       ],
       "src": [
         "test/cpp/qps/qpstest.proto",
         "test/cpp/qps/driver.cc",
+        "test/cpp/qps/report.cc",
         "test/cpp/qps/timer.cc"
       ]
     },
@@ -1676,6 +1728,22 @@
       ]
     },
     {
+      "name": "cli_call_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/util/cli_call_test.cc"
+      ],
+      "deps": [
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "credentials_test",
       "build": "test",
       "language": "c++",
@@ -1689,6 +1757,21 @@
       ]
     },
     {
+      "name": "cxx_time_test",
+      "build": "test",
+      "language": "c++",
+      "src": [
+        "test/cpp/util/time_test.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "end2end_test",
       "build": "test",
       "language": "c++",
@@ -1721,32 +1804,56 @@
       ]
     },
     {
+      "name": "grpc_cli",
+      "build": "test",
+      "run": false,
+      "language": "c++",
+      "src": [
+        "test/cpp/util/grpc_cli.cc"
+      ],
+      "deps": [
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "grpc_cpp_plugin",
       "build": "protoc",
       "language": "c++",
-      "headers": [
-        "src/compiler/cpp_generator.h",
-        "src/compiler/cpp_generator_helpers.h"
-      ],
       "src": [
-        "src/compiler/cpp_generator.cc",
         "src/compiler/cpp_plugin.cc"
       ],
-      "deps": [],
+      "deps": [
+        "grpc_plugin_support"
+      ],
+      "secure": "no"
+    },
+    {
+      "name": "grpc_objective_c_plugin",
+      "build": "protoc",
+      "language": "c++",
+      "src": [
+        "src/compiler/objective_c_plugin.cc"
+      ],
+      "deps": [
+        "grpc_plugin_support"
+      ],
       "secure": "no"
     },
     {
       "name": "grpc_python_plugin",
       "build": "protoc",
       "language": "c++",
-      "headers": [
-        "src/compiler/python_generator.h"
-      ],
       "src": [
-        "src/compiler/python_generator.cc",
         "src/compiler/python_plugin.cc"
       ],
-      "deps": [],
+      "deps": [
+        "grpc_plugin_support"
+      ],
       "secure": "no"
     },
     {
@@ -1754,10 +1861,11 @@
       "build": "protoc",
       "language": "c++",
       "src": [
-        "src/compiler/ruby_generator.cc",
         "src/compiler/ruby_plugin.cc"
       ],
-      "deps": [],
+      "deps": [
+        "grpc_plugin_support"
+      ],
       "secure": "no"
     },
     {
@@ -1884,6 +1992,24 @@
       ]
     },
     {
+      "name": "qps_smoke_test",
+      "build": "test",
+      "run": false,
+      "language": "c++",
+      "src": [
+        "test/cpp/qps/smoke_test.cc"
+      ],
+      "deps": [
+        "qps",
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "qps_worker",
       "build": "test",
       "run": false,
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
new file mode 100644
index 0000000..3f5ce37
--- /dev/null
+++ b/doc/interop-test-descriptions.md
@@ -0,0 +1,685 @@
+Interoperability Test Case Descriptions
+=======================================
+
+Client and server use
+[test.proto](https://github.com/grpc/grpc/blob/master/test/cpp/interop/test.proto)
+and the [gRPC over HTTP/2 v2
+protocol](https://github.com/grpc/grpc-common/blob/master/PROTOCOL-HTTP2.md).
+
+Client
+------
+
+Clients implement test cases that test certain functionally. Each client is
+provided the test case it is expected to run as a command-line parameter. Names
+should be lowercase and without spaces.
+
+Clients should accept these arguments:
+* --server_host=HOSTNAME
+    * The server host to connect to. For example, "localhost" or "127.0.0.1"
+* --server_host_override=HOSTNAME
+    * The server host to claim to be connecting to, for use in TLS and HTTP/2
+      :authority header. If unspecified, the value of --server_host will be
+      used
+* --server_port=PORT
+    * The server port to connect to. For example, "8080"
+* --test_case=TESTCASE
+    * The name of the test case to execute. For example, "empty_unary"
+* --use_tls=BOOLEAN
+    * Whether to use a plaintext or encrypted connection
+* --use_test_ca=BOOLEAN
+    * Whether to replace platform root CAs with
+      [ca.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/ca.pem)
+      as the CA root
+
+Clients must support TLS with ALPN. Clients must not disable certificate
+checking.
+
+### empty_unary
+
+This test verifies that implementations support zero-size messages. Ideally,
+client implementations would verify that the request and response were zero
+bytes serialized, but this is generally prohibitive to perform, so is not
+required.
+
+Server features:
+* [EmptyCall][]
+
+Procedure:
+ 1. Client calls EmptyCall with the default Empty message
+
+Asserts:
+* call was successful
+* response is non-null
+
+*It may be possible to use UnaryCall instead of EmptyCall, but it is harder to
+ensure that the proto serialized to zero bytes.*
+
+### large_unary
+
+This test verifies unary calls succeed in sending messages, and touches on flow
+control (even if compression is enabled on the channel).
+
+Server features:
+* [UnaryCall][]
+* [Compressable Payload][]
+
+Procedure:
+ 1. Client calls UnaryCall with:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+Asserts:
+* call was successful
+* response payload type is COMPRESSABLE
+* response payload body is 314159 bytes in size
+* clients are free to assert that the response payload body contents are zero
+  and comparing the entire response message against a golden response
+
+### client_streaming
+
+This test verifies that client-only streaming succeeds.
+
+Server features:
+* [StreamingInputCall][]
+* [Compressable Payload][]
+
+Procedure:
+ 1. Client calls StreamingInputCall
+ 2. Client sends:
+
+    ```
+    {
+      payload:{
+        body: 27182 bytes of zeros
+      }
+    }
+    ```
+ 3. Client then sends:
+
+    ```
+    {
+      payload:{
+        body: 8 bytes of zeros
+      }
+    }
+    ```
+ 4. Client then sends:
+
+    ```
+    {
+      payload:{
+        body: 1828 bytes of zeros
+      }
+    }
+    ```
+ 5. Client then sends:
+
+    ```
+    {
+      payload:{
+        body: 45904 bytes of zeros
+      }
+    }
+    ```
+ 6. Client halfCloses
+
+Asserts:
+* call was successful
+* response aggregated_payload_size is 74922
+
+### server_streaming
+
+This test verifies that server-only streaming succeeds.
+
+Server features:
+* [StreamingOutputCall][]
+* [Compressable Payload][]
+
+Procedure:
+ 1. Client calls StreamingOutputCall with:
+
+    ```
+    {
+      response_type:COMPRESSABLE
+      response_parameters:{
+        size: 31415
+      }
+      response_parameters:{
+        size: 9
+      }
+      response_parameters:{
+        size: 2653
+      }
+      response_parameters:{
+        size: 58979
+      }
+    }
+    ```
+
+Asserts:
+* call was successful
+* exactly four responses
+* response payloads are COMPRESSABLE
+* response payload bodies are sized (in order): 31415, 9, 2653, 58979
+* clients are free to assert that the response payload body contents are zero
+  and comparing the entire response messages against golden responses
+
+### ping_pong
+
+This test verifies that full duplex bidi is supported.
+
+Server features:
+* [FullDuplexCall][]
+* [Compressable Payload][]
+
+Procedure:
+ 1. Client calls FullDuplexCall with:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_parameters:{
+        size: 31415
+      }
+      payload:{
+        body: 27182 bytes of zeros
+      }
+    }
+    ```
+ 2. After getting a reply, it sends:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_parameters:{
+        size: 9
+      }
+      payload:{
+        body: 8 bytes of zeros
+      }
+    }
+    ```
+ 3. After getting a reply, it sends:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_parameters:{
+        size: 2653
+      }
+      payload:{
+        body: 1828 bytes of zeros
+      }
+    }
+    ```
+ 4. After getting a reply, it sends:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_parameters:{
+        size: 58979
+      }
+      payload:{
+        body: 45904 bytes of zeros
+      }
+    }
+    ```
+
+Asserts:
+* call was successful
+* exactly four responses
+* response payloads are COMPRESSABLE
+* response payload bodies are sized (in order): 31415, 9, 2653, 58979
+* clients are free to assert that the response payload body contents are zero
+  and comparing the entire response messages against golden responses
+
+### empty_stream
+
+This test verifies that streams support having zero-messages in both
+directions.
+
+Server features:
+* [FullDuplexCall][]
+
+Procedure:
+ 1. Client calls FullDuplexCall and then half-closes
+
+Asserts:
+* call was successful
+* exactly zero responses
+
+### compute_engine_creds
+
+Status: Not yet implementable
+
+This test is only for cloud-to-prod path.
+
+This test verifies unary calls succeed in sending messages while using Service
+Credentials from GCE metadata server. The client instance needs to be created
+with desired oauth scope.
+
+Server features:
+* [UnaryCall][]
+* [Compressable Payload][]
+* SimpeResponse.username
+* SimpleResponse.oauth_scope
+
+Procedure:
+ 1. Client sets flags default_service_account with GCE service account name and
+    oauth_scope with the oauth scope to use.
+ 2. Client configures channel to use GCECredentials
+ 3. Client calls UnaryCall on the channel with:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+      fill_username: true
+      fill_oauth_scope: true
+    }
+    ```
+
+Asserts:
+* call was successful
+* received SimpleResponse.username equals FLAGS_default_service_account
+* received SimpleResponse.oauth_scope is in FLAGS_oauth_scope
+* response payload body is 314159 bytes in size
+* clients are free to assert that the response payload body contents are zero
+  and comparing the entire response message against a golden response
+
+### service_account_creds
+
+Status: Not yet implementable
+
+This test is only for cloud-to-prod path.
+
+This test verifies unary calls succeed in sending messages while using JWT
+signing keys (redeemed for OAuth2 access tokens by the auth implementation)
+
+Server features:
+* [UnaryCall][]
+* [Compressable Payload][]
+* SimpleResponse.username
+* SimpleResponse.oauth_scope
+
+Procedure:
+ 1. Client sets flags service_account_key_file with the path to json key file,
+    oauth_scope to the oauth scope.
+ 2. Client configures the channel to use ServiceAccountCredentials.
+ 3. Client calls UnaryCall with:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+      fill_username: true
+      fill_oauth_scope: true
+    }
+    ```
+
+Asserts:
+* call was successful
+* received SimpleResponse.username is in the json key file read from
+  FLAGS_service_account_key_file
+* received SimpleResponse.oauth_scope is in FLAGS_oauth_scope
+* response payload body is 314159 bytes in size
+* clients are free to assert that the response payload body contents are zero
+  and comparing the entire response message against a golden response
+
+### jwt_token_creds
+
+Status: Not yet implementable
+
+This test is only for cloud-to-prod path.
+
+This test verifies unary calls succeed in sending messages while using JWT
+token (created by the project's key file)
+
+Server features:
+* [UnaryCall][]
+* [Compressable Payload][]
+* SimpleResponse.username
+* SimpleResponse.oauth_scope
+
+Procedure:
+ 1. Client sets flags service_account_key_file with the path to json key file
+ 2. Client configures the channel to use JWTTokenCredentials.
+ 3. Client calls UnaryCall with:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+      fill_username: true
+    }
+    ```
+
+Asserts:
+* call was successful
+* received SimpleResponse.username is in the json key file read from
+  FLAGS_service_account_key_file
+* response payload body is 314159 bytes in size
+* clients are free to assert that the response payload body contents are zero
+  and comparing the entire response message against a golden response
+
+### Metadata (TODO: fix name)
+
+Status: Not yet implementable
+
+This test verifies that custom metadata in either binary or ascii format can be
+sent in header and trailer.
+
+Server features:
+* [UnaryCall][]
+* [Compressable Payload][]
+* Ability to receive custom metadata from client in header and send custom data
+  back to client in both header and trailer. (TODO: this is not defined)
+
+Procedure:
+ 1. While sending custom metadata (ascii + binary) in the header, client calls UnaryCall with:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+Asserts:
+* call was successful
+* custom metadata is echoed back in the response header.
+* custom metadata is echoed back in the response trailer.
+
+### status_code_and_message
+
+Status: Not yet implementable
+
+This test verifies unary calls succeed in sending messages, and propagates back
+status code and message sent along with the messages.
+
+Server features:
+* [UnaryCall][]
+
+Procedure:
+ 1. Client calls UnaryCall with:
+
+    ```
+    {
+      response_status:{
+        code: 2
+        message: "test status message"
+      }
+    }
+    ```
+
+Asserts:
+* received status code is the same with sent code
+* received status message is the same with sent message
+
+### unimplemented_method
+
+Status: Not yet implementable
+
+This test verifies calling unimplemented RPC method returns unimplemented
+status.
+
+Procedure:
+* Client calls UnimplementedCall with:
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+Asserts:
+* received status code is 12 (UNIMPLEMENTED)
+* received status message is empty or null/unset
+
+### cancel_after_begin
+
+This test verifies that a request can be cancelled after metadata has been sent
+but before payloads are sent.
+
+Server features:
+* [StreamingInputCall][]
+
+Procedure:
+ 1. Client starts StreamingInputCall
+ 2. Client immediately cancels request
+
+Asserts:
+* Call completed with status CANCELLED
+
+### cancel_after_first_response
+
+This test verifies that a request can be cancelled after receiving a message
+from the server.
+
+Server features:
+* [FullDuplexCall][]
+* [Compressable Payload][]
+
+Procedure:
+ 1. Client starts FullDuplexCall with
+
+    ```
+    {
+      response_type: COMPRESSABLE
+      response_parameters:{
+        size: 31415
+      }
+      payload:{
+        body: 27182 bytes of zeros
+      }
+    }
+    ```
+ 2. After receiving a response, client cancels request
+
+Asserts:
+* Call completed with status CANCELLED
+
+### concurrent_large_unary
+
+Status: TODO
+
+Client performs 1000 large_unary tests in parallel on the same channel.
+
+### Flow control. Pushback at client for large messages (TODO: fix name)
+
+Status: TODO
+
+This test verifies that a client sending faster than a server can drain sees
+pushback (i.e., attempts to send succeed only after appropriate delays).
+
+### TODO Tests
+
+High priority:
+
+Propagation of status code and message (yangg)
+
+Cancel after sent headers (ctiller - done)
+
+Cancel after received first message (ctiller - done)
+
+Timeout after expire (zhaoq)
+
+Zero-message streams (ejona)
+
+Multiple thousand simultaneous calls on same Channel (ctiller - done)
+
+OAuth2 tokens + Service Credentials from GCE metadata server (GCE->prod only)
+(abhishek)
+
+OAuth2 tokens + JWT signing key (GCE->prod only) (abhishek)
+
+Metadata: client headers, server headers + trailers, binary+ascii (chenw)
+
+Normal priority:
+
+Cancel before start (ctiller)
+
+Cancel after sent first message (ctiller)
+
+Cancel after received headers (ctiller)
+
+Timeout but completed before expire (zhaoq)
+
+Multiple thousand simultaneous calls timeout on same Channel (ctiller)
+
+Lower priority:
+
+Flow control. Pushback at client for large messages (abhishek)
+
+Flow control. Pushback at server for large messages (abhishek)
+
+Going over max concurrent streams doesn't fail (client controls itself)
+(abhishek)
+
+RPC method not implemented (yangg)
+
+Multiple thousand simultaneous calls on different Channels (ctiller)
+
+Failed TLS hostname verification (ejona?)
+
+To priorize:
+
+Start streaming RPC but don't send any requests, server responds
+
+### Postponed Tests
+
+Resilience to buggy servers: These tests would verify that a client application
+isn't affected negatively by the responses put on the wire by a buggy server
+(e.g. the client library won't make the application crash).
+
+Reconnect after transport failure
+
+Reconnect backoff
+
+Fuzz testing
+
+
+Server
+------
+
+Servers implement various named features for clients to test with. Server
+features are orthogonal. If a server implements a feature, it is always
+available for clients. Names are simple descriptions for developer
+communication and tracking.
+
+Servers should accept these arguments:
+
+* --port=PORT
+
+    * The port to listen on. For example, "8080"
+
+* --use_tls=BOOLEAN
+
+    * Whether to use a plaintext or encrypted connection
+
+Servers must support TLS with ALPN. They should use
+[server1.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/server1.pem)
+for their certificate.
+
+### EmptyCall
+[EmptyCall]: #emptycall
+
+Server implements EmptyCall which immediately returns the empty message.
+
+### UnaryCall
+[UnaryCall]: #unarycall
+
+Server implements UnaryCall which immediately returns a SimpleResponse with a
+payload body of size SimpleRequest.response_size bytes and type as appropriate
+for the SimpleRequest.response_type. If the server does not support the
+response_type, then it should fail the RPC with INVALID_ARGUMENT.
+
+If the request sets fill_username, the server should return the client username
+it sees in field SimpleResponse.username. If the request sets fill_oauth_scope,
+the server should return the oauth scope of the rpc in the form of "xapi_zoo"
+in field SimpleResponse.oauth_scope.
+
+### StreamingInputCall
+[StreamingInputCall]: #streaminginputcall
+
+Server implements StreamingInputCall which upon half close immediately returns
+a StreamingInputCallResponse where aggregated_payload_size is the sum of all
+request payload bodies received.
+
+### StreamingOutputCall
+[StreamingOutputCall]: #streamingoutputcall
+
+Server implements StreamingOutputCall by replying, in order, with one
+StreamingOutputCallResponses for each ResponseParameters in
+StreamingOutputCallRequest. Each StreamingOutputCallResponses should have a
+payload body of size ResponseParameters.size bytes, as specified by its
+respective ResponseParameters. After sending all responses, it closes with OK.
+
+### FullDuplexCall
+[FullDuplexCall]: #fullduplexcall
+
+Server implements FullDuplexCall by replying, in order, with one
+StreamingOutputCallResponses for each ResponseParameters in each
+StreamingOutputCallRequest. Each StreamingOutputCallResponses should have a
+payload body of size ResponseParameters.size bytes, as specified by its
+respective ResponseParameters. After receiving half close and sending all
+responses, it closes with OK.
+
+### Compressable Payload
+[Compressable Payload]: #compressable-payload
+
+When the client requests COMPRESSABLE payload, the response includes a payload
+of the size requested containing all zeros and the payload type is
+COMPRESSABLE.
+
+### Observe ResponseParameters.interval_us
+[Observe ResponseParameters.interval_us]: #observe-responseparametersinterval_us
+
+In StreamingOutputCall and FullDuplexCall, server delays sending a
+StreamingOutputCallResponse by the ResponseParameters's interval_us for that
+particular response, relative to the last response sent. That is, interval_us
+acts like a sleep *before* sending the response and accumulates from one
+response to the next.
+
+Interaction with flow control is unspecified.
+
+### Echo Auth Information
+
+Status: Pending
+
+If a SimpleRequest has fill_username=true and that request was successfully
+authenticated, then the SimpleResponse should have username filled with the
+canonical form of the authenticated source. The canonical form is dependent on
+the authentication method, but is likely to be a base 10 integer identifier or
+an email address.
+
+Discussion:
+
+Ideally, this would be communicated via metadata and not in the
+request/response, but we want to use this test in code paths that don't yet
+fully communicate metadata.
diff --git a/examples/pubsub/main.cc b/examples/pubsub/main.cc
index 6f7737e..cc5076f 100644
--- a/examples/pubsub/main.cc
+++ b/examples/pubsub/main.cc
@@ -51,14 +51,14 @@
 #include "examples/pubsub/subscriber.h"
 
 DEFINE_int32(server_port, 443, "Server port.");
-DEFINE_string(server_host,
-              "pubsub-staging.googleapis.com", "Server host to connect to");
+DEFINE_string(server_host, "pubsub-staging.googleapis.com",
+              "Server host to connect to");
 DEFINE_string(project_id, "", "GCE project id such as stoked-keyword-656");
 
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
-namespace google { }
-namespace gflags { }
+namespace google {}
+namespace gflags {}
 using namespace google;
 using namespace gflags;
 
@@ -92,32 +92,32 @@
   grpc::string topic = ss.str();
 
   ss.str("");
-  ss << FLAGS_project_id << "/"  << kSubscriptionName;
+  ss << FLAGS_project_id << "/" << kSubscriptionName;
   grpc::string subscription_name = ss.str();
 
   // Clean up test topic and subcription if they exist before.
   grpc::string subscription_topic;
-  if (subscriber.GetSubscription(
-      subscription_name, &subscription_topic).IsOk()) {
+  if (subscriber.GetSubscription(subscription_name, &subscription_topic)
+          .IsOk()) {
     subscriber.DeleteSubscription(subscription_name);
   }
 
   if (publisher.GetTopic(topic).IsOk()) publisher.DeleteTopic(topic);
 
   grpc::Status s = publisher.CreateTopic(topic);
-  gpr_log(GPR_INFO, "Create topic returns code %d, %s",
-          s.code(), s.details().c_str());
+  gpr_log(GPR_INFO, "Create topic returns code %d, %s", s.code(),
+          s.details().c_str());
   GPR_ASSERT(s.IsOk());
 
   s = publisher.GetTopic(topic);
-  gpr_log(GPR_INFO, "Get topic returns code %d, %s",
-          s.code(), s.details().c_str());
+  gpr_log(GPR_INFO, "Get topic returns code %d, %s", s.code(),
+          s.details().c_str());
   GPR_ASSERT(s.IsOk());
 
   std::vector<grpc::string> topics;
   s = publisher.ListTopics(FLAGS_project_id, &topics);
-  gpr_log(GPR_INFO, "List topic returns code %d, %s",
-          s.code(), s.details().c_str());
+  gpr_log(GPR_INFO, "List topic returns code %d, %s", s.code(),
+          s.details().c_str());
   bool topic_found = false;
   for (unsigned int i = 0; i < topics.size(); i++) {
     if (topics[i] == topic) topic_found = true;
@@ -127,27 +127,27 @@
   GPR_ASSERT(topic_found);
 
   s = subscriber.CreateSubscription(topic, subscription_name);
-  gpr_log(GPR_INFO, "create subscrption returns code %d, %s",
-          s.code(), s.details().c_str());
+  gpr_log(GPR_INFO, "create subscrption returns code %d, %s", s.code(),
+          s.details().c_str());
   GPR_ASSERT(s.IsOk());
 
   s = publisher.Publish(topic, kMessageData);
-  gpr_log(GPR_INFO, "Publish %s returns code %d, %s",
-          kMessageData, s.code(), s.details().c_str());
+  gpr_log(GPR_INFO, "Publish %s returns code %d, %s", kMessageData, s.code(),
+          s.details().c_str());
   GPR_ASSERT(s.IsOk());
 
   grpc::string data;
   s = subscriber.Pull(subscription_name, &data);
   gpr_log(GPR_INFO, "Pull %s", data.c_str());
 
-  s =  subscriber.DeleteSubscription(subscription_name);
-  gpr_log(GPR_INFO, "Delete subscription returns code %d, %s",
-          s.code(), s.details().c_str());
+  s = subscriber.DeleteSubscription(subscription_name);
+  gpr_log(GPR_INFO, "Delete subscription returns code %d, %s", s.code(),
+          s.details().c_str());
   GPR_ASSERT(s.IsOk());
 
   s = publisher.DeleteTopic(topic);
-  gpr_log(GPR_INFO, "Delete topic returns code %d, %s",
-          s.code(), s.details().c_str());
+  gpr_log(GPR_INFO, "Delete topic returns code %d, %s", s.code(),
+          s.details().c_str());
   GPR_ASSERT(s.IsOk());
 
   subscriber.Shutdown();
diff --git a/examples/pubsub/publisher.cc b/examples/pubsub/publisher.cc
index 308f9a7..458050a 100644
--- a/examples/pubsub/publisher.cc
+++ b/examples/pubsub/publisher.cc
@@ -51,12 +51,9 @@
 namespace pubsub {
 
 Publisher::Publisher(std::shared_ptr<ChannelInterface> channel)
-    : stub_(PublisherService::NewStub(channel)) {
-}
+    : stub_(PublisherService::NewStub(channel)) {}
 
-void Publisher::Shutdown() {
-  stub_.reset();
-}
+void Publisher::Shutdown() { stub_.reset(); }
 
 Status Publisher::CreateTopic(const grpc::string& topic) {
   Topic request;
diff --git a/examples/pubsub/publisher.h b/examples/pubsub/publisher.h
index c90406f..33bcf98 100644
--- a/examples/pubsub/publisher.h
+++ b/examples/pubsub/publisher.h
@@ -37,7 +37,7 @@
 #include <grpc++/channel_interface.h>
 #include <grpc++/status.h>
 
-#include "examples/pubsub/pubsub.pb.h"
+#include "examples/pubsub/pubsub.grpc.pb.h"
 
 namespace grpc {
 namespace examples {
diff --git a/examples/pubsub/publisher_test.cc b/examples/pubsub/publisher_test.cc
index 62442c7..ac49212 100644
--- a/examples/pubsub/publisher_test.cc
+++ b/examples/pubsub/publisher_test.cc
@@ -31,8 +31,6 @@
  *
  */
 
-#include <google/protobuf/stubs/common.h>
-
 #include <grpc++/channel_arguments.h>
 #include <grpc++/channel_interface.h>
 #include <grpc++/client_context.h>
@@ -84,20 +82,19 @@
   Status ListTopics(
       ServerContext* context, const ::tech::pubsub::ListTopicsRequest* request,
       ::tech::pubsub::ListTopicsResponse* response) GRPC_OVERRIDE {
-   std::ostringstream ss;
-   ss << "cloud.googleapis.com/project in (/projects/" << kProjectId << ")";
-   EXPECT_EQ(request->query(), ss.str());
-   response->add_topic()->set_name(kTopic);
-   return Status::OK;
- }
+    std::ostringstream ss;
+    ss << "cloud.googleapis.com/project in (/projects/" << kProjectId << ")";
+    EXPECT_EQ(request->query(), ss.str());
+    response->add_topic()->set_name(kTopic);
+    return Status::OK;
+  }
 
- Status DeleteTopic(ServerContext* context,
-                    const ::tech::pubsub::DeleteTopicRequest* request,
-                    ::proto2::Empty* response) GRPC_OVERRIDE {
+  Status DeleteTopic(ServerContext* context,
+                     const ::tech::pubsub::DeleteTopicRequest* request,
+                     ::proto2::Empty* response) GRPC_OVERRIDE {
     EXPECT_EQ(request->topic(), kTopic);
     return Status::OK;
- }
-
+  }
 };
 
 class PublisherTest : public ::testing::Test {
@@ -107,11 +104,13 @@
     int port = grpc_pick_unused_port_or_die();
     server_address_ << "localhost:" << port;
     ServerBuilder builder;
-    builder.AddListeningPort(server_address_.str(), grpc::InsecureServerCredentials());
+    builder.AddListeningPort(server_address_.str(),
+                             grpc::InsecureServerCredentials());
     builder.RegisterService(&service_);
     server_ = builder.BuildAndStart();
 
-    channel_ = CreateChannel(server_address_.str(), grpc::InsecureCredentials(), ChannelArguments());
+    channel_ = CreateChannel(server_address_.str(), grpc::InsecureCredentials(),
+                             ChannelArguments());
 
     publisher_.reset(new grpc::examples::pubsub::Publisher(channel_));
   }
diff --git a/examples/pubsub/subscriber.cc b/examples/pubsub/subscriber.cc
index 29f6635..d9e0292 100644
--- a/examples/pubsub/subscriber.cc
+++ b/examples/pubsub/subscriber.cc
@@ -49,12 +49,9 @@
 namespace pubsub {
 
 Subscriber::Subscriber(std::shared_ptr<ChannelInterface> channel)
-    : stub_(SubscriberService::NewStub(channel)) {
-}
+    : stub_(SubscriberService::NewStub(channel)) {}
 
-void Subscriber::Shutdown() {
-  stub_.reset();
-}
+void Subscriber::Shutdown() { stub_.reset(); }
 
 Status Subscriber::CreateSubscription(const grpc::string& topic,
                                       const grpc::string& name) {
diff --git a/examples/pubsub/subscriber.h b/examples/pubsub/subscriber.h
index c587c01..40ab454 100644
--- a/examples/pubsub/subscriber.h
+++ b/examples/pubsub/subscriber.h
@@ -37,7 +37,7 @@
 #include <grpc++/channel_interface.h>
 #include <grpc++/status.h>
 
-#include "examples/pubsub/pubsub.pb.h"
+#include "examples/pubsub/pubsub.grpc.pb.h"
 
 namespace grpc {
 namespace examples {
diff --git a/examples/pubsub/subscriber_test.cc b/examples/pubsub/subscriber_test.cc
index b8dd1f9..9ab60ed 100644
--- a/examples/pubsub/subscriber_test.cc
+++ b/examples/pubsub/subscriber_test.cc
@@ -31,8 +31,6 @@
  *
  */
 
-#include <google/protobuf/stubs/common.h>
-
 #include <grpc++/channel_arguments.h>
 #include <grpc++/channel_interface.h>
 #include <grpc++/client_context.h>
@@ -95,7 +93,6 @@
                      proto2::Empty* response) GRPC_OVERRIDE {
     return Status::OK;
   }
-
 };
 
 class SubscriberTest : public ::testing::Test {
@@ -105,11 +102,13 @@
     int port = grpc_pick_unused_port_or_die();
     server_address_ << "localhost:" << port;
     ServerBuilder builder;
-    builder.AddListeningPort(server_address_.str(), grpc::InsecureServerCredentials());
+    builder.AddListeningPort(server_address_.str(),
+                             grpc::InsecureServerCredentials());
     builder.RegisterService(&service_);
     server_ = builder.BuildAndStart();
 
-    channel_ = CreateChannel(server_address_.str(), grpc::InsecureCredentials(), ChannelArguments());
+    channel_ = CreateChannel(server_address_.str(), grpc::InsecureCredentials(),
+                             ChannelArguments());
 
     subscriber_.reset(new grpc::examples::pubsub::Subscriber(channel_));
   }
@@ -129,17 +128,15 @@
 };
 
 TEST_F(SubscriberTest, TestSubscriber) {
-  EXPECT_TRUE(subscriber_->CreateSubscription(kTopic,
-                                              kSubscriptionName).IsOk());
+  EXPECT_TRUE(
+      subscriber_->CreateSubscription(kTopic, kSubscriptionName).IsOk());
 
   grpc::string topic;
-  EXPECT_TRUE(subscriber_->GetSubscription(kSubscriptionName,
-                                           &topic).IsOk());
+  EXPECT_TRUE(subscriber_->GetSubscription(kSubscriptionName, &topic).IsOk());
   EXPECT_EQ(topic, kTopic);
 
   grpc::string data;
-  EXPECT_TRUE(subscriber_->Pull(kSubscriptionName,
-                                &data).IsOk());
+  EXPECT_TRUE(subscriber_->Pull(kSubscriptionName, &data).IsOk());
 
   EXPECT_TRUE(subscriber_->DeleteSubscription(kSubscriptionName).IsOk());
 }
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
index f4619a1..e6a8c6f 100644
--- a/include/grpc++/completion_queue.h
+++ b/include/grpc++/completion_queue.h
@@ -36,6 +36,7 @@
 
 #include <chrono>
 #include <grpc++/impl/client_unary_call.h>
+#include <grpc/support/time.h>
 
 struct grpc_completion_queue;
 
@@ -88,9 +89,7 @@
   // Returns false if the queue is ready for destruction, true if event
 
   bool Next(void** tag, bool* ok) {
-    return (
-        AsyncNext(tag, ok, (std::chrono::system_clock::time_point::max)()) !=
-        SHUTDOWN);
+    return (AsyncNextInternal(tag, ok, gpr_inf_future) != SHUTDOWN);
   }
 
   // Shutdown has to be called, and the CompletionQueue can only be
@@ -122,6 +121,8 @@
                                   const grpc::protobuf::Message& request,
                                   grpc::protobuf::Message* result);
 
+  NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
+
   // Wraps grpc_completion_queue_pluck.
   // Cannot be mixed with calls to Next().
   bool Pluck(CompletionQueueTag* tag);
diff --git a/include/grpc++/config.h b/include/grpc++/config.h
index 35bf507..0f3d692 100644
--- a/include/grpc++/config.h
+++ b/include/grpc++/config.h
@@ -34,11 +34,46 @@
 #ifndef GRPCXX_CONFIG_H
 #define GRPCXX_CONFIG_H
 
-#ifdef GRPC_OLD_CXX
+#if !defined(GRPC_NO_AUTODETECT_PLATFORM)
+
+#ifdef _MSC_VER
+// Visual Studio 2010 is 1600.
+#if _MSC_VER < 1600
+#error "gRPC is only supported with Visual Studio starting at 2010"
+// Visual Studio 2013 is 1800.
+#elif _MSC_VER < 1800
+#define GRPC_CXX0X_NO_FINAL 1
+#define GRPC_CXX0X_NO_OVERRIDE 1
+#define GRPC_CXX0X_NO_CHRONO 1
+#define GRPC_CXX0X_NO_THREAD 1
+#endif  
+#endif  // Visual Studio
+
+#ifndef __clang__
+#ifdef __GNUC__
+// nullptr was added in gcc 4.6
+#if (__GNUC__ * 100 + __GNUC_MINOR__ < 406)
+#define GRPC_CXX0X_NO_NULLPTR 1
+#endif
+// final and override were added in gcc 4.7
+#if (__GNUC__ * 100 + __GNUC_MINOR__ < 407)
+#define GRPC_CXX0X_NO_FINAL 1
+#define GRPC_CXX0X_NO_OVERRIDE 1
+#endif
+#endif
+#endif
+
+#endif
+
+#ifdef GRPC_CXX0X_NO_FINAL
 #define GRPC_FINAL
-#define GRPC_OVERRIDE
 #else
 #define GRPC_FINAL final
+#endif
+
+#ifdef GRPC_CXX0X_NO_OVERRIDE
+#define GRPC_OVERRIDE
+#else
 #define GRPC_OVERRIDE override
 #endif
 
@@ -65,6 +100,20 @@
   ::google::protobuf::io::ZeroCopyInputStream
 #endif
 
+#ifdef GRPC_CXX0X_NO_NULLPTR
+#include <memory>
+const class {
+public:
+  template <class T> operator T*() const {return static_cast<T *>(0);}
+  template <class T> operator std::unique_ptr<T>() const {
+    return std::unique_ptr<T>(static_cast<T *>(0));
+  }
+  operator bool() const {return false;}
+private:
+  void operator&() const = delete;
+} nullptr = {};
+#endif
+
 namespace grpc {
 
 typedef GRPC_CUSTOM_STRING string;
diff --git a/include/grpc++/generic_stub.h b/include/grpc++/generic_stub.h
index d4c8380..c34e1fc 100644
--- a/include/grpc++/generic_stub.h
+++ b/include/grpc++/generic_stub.h
@@ -39,6 +39,7 @@
 
 namespace grpc {
 
+class CompletionQueue;
 typedef ClientAsyncReaderWriter<ByteBuffer, ByteBuffer>
     GenericClientAsyncReaderWriter;
 
@@ -51,7 +52,8 @@
 
   // begin a call to a named method
   std::unique_ptr<GenericClientAsyncReaderWriter> Call(
-      ClientContext* context, const grpc::string& method);
+      ClientContext* context, const grpc::string& method,
+      CompletionQueue* cq, void* tag);
 
  private:
   std::shared_ptr<ChannelInterface> channel_;
diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
index e117ac6..b14c41d 100644
--- a/include/grpc++/impl/call.h
+++ b/include/grpc++/impl/call.h
@@ -109,7 +109,9 @@
   char* status_details_;
   size_t status_details_capacity_;
   // Server send status
-  const Status* send_status_;
+  bool send_status_available_;
+  grpc_status_code send_status_code_;
+  grpc::string send_status_details_;
   size_t trailing_metadata_count_;
   grpc_metadata* trailing_metadata_;
   int cancelled_buf_;
diff --git a/src/php/ext/grpc/event.h b/include/grpc++/impl/sync.h
old mode 100755
new mode 100644
similarity index 79%
copy from src/php/ext/grpc/event.h
copy to include/grpc++/impl/sync.h
index ef5846a..2f41d2b
--- a/src/php/ext/grpc/event.h
+++ b/include/grpc++/impl/sync.h
@@ -31,21 +31,15 @@
  *
  */
 
-#ifndef NET_GRPC_PHP_GRPC_EVENT_H_
-#define NET_GRPC_PHP_GRPC_EVENT_H_
+#ifndef GRPCXX_IMPL_SYNC_H
+#define GRPCXX_IMPL_SYNC_H
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <grpc++/config.h>
+
+#ifdef GRPC_CXX0X_NO_THREAD
+#include <grpc++/impl/sync_no_cxx11.h>
+#else
+#include <grpc++/impl/sync_cxx11.h>
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
-
-#include "grpc/grpc.h"
-
-/* Create a new Event object that wraps an existing grpc_event struct */
-zval *grpc_php_convert_event(grpc_event *event);
-
-#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */
+#endif  // GRPCXX_IMPL_SYNC_H
diff --git a/src/php/lib/autoload.php b/include/grpc++/impl/sync_cxx11.h
old mode 100755
new mode 100644
similarity index 79%
copy from src/php/lib/autoload.php
copy to include/grpc++/impl/sync_cxx11.h
index 42eb33d..4e6f1da
--- a/src/php/lib/autoload.php
+++ b/include/grpc++/impl/sync_cxx11.h
@@ -1,4 +1,3 @@
-<?php
 /*
  *
  * Copyright 2015, Google Inc.
@@ -31,23 +30,20 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-function grpcAutoloader($class) {
-  $prefix = 'Grpc\\';
 
-  $base_dir = __DIR__ . '/Grpc/';
+#ifndef GRPCXX_IMPL_SYNC_CXX11_H
+#define GRPCXX_IMPL_SYNC_CXX11_H
 
-  $len = strlen($prefix);
-  if (strncmp($prefix, $class, $len) !== 0) {
-    return;
-  }
+#include <condition_variable>
+#include <mutex>
 
-  $relative_class = substr($class, $len);
+namespace grpc {
 
-  $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
+using std::condition_variable;
+using std::mutex;
+using std::lock_guard;
+using std::unique_lock;
 
-  if (file_exists($file)) {
-    include $file;
-  }
-}
+}  // namespace grpc
 
-spl_autoload_register('grpcAutoloader');
+#endif  // GRPCXX_IMPL_SYNC_CXX11_H
diff --git a/include/grpc++/impl/sync_no_cxx11.h b/include/grpc++/impl/sync_no_cxx11.h
new file mode 100644
index 0000000..5636373
--- /dev/null
+++ b/include/grpc++/impl/sync_no_cxx11.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_SYNC_NO_CXX11_H
+#define GRPCXX_IMPL_SYNC_NO_CXX11_H
+
+#include <grpc/support/sync.h>
+
+namespace grpc {
+
+template<class mutex>
+class lock_guard;
+class condition_variable;
+
+class mutex {
+ public:
+  mutex() { gpr_mu_init(&mu_); }
+  ~mutex() { gpr_mu_destroy(&mu_); }
+ private:
+  ::gpr_mu mu_;
+  template <class mutex>
+  friend class lock_guard;
+  friend class condition_variable;
+};
+
+template <class mutex>
+class lock_guard {
+ public:
+  lock_guard(mutex &mu) : mu_(mu), locked(true) { gpr_mu_lock(&mu.mu_); }
+  ~lock_guard() { unlock_internal(); }
+ protected:
+  void lock_internal() {
+    if (!locked) gpr_mu_lock(&mu_.mu_);
+    locked = true;
+  }
+  void unlock_internal() {
+    if (locked) gpr_mu_unlock(&mu_.mu_);
+    locked = false;
+  }
+ private:
+  mutex &mu_;
+  bool locked;
+  friend class condition_variable;
+};
+
+template <class mutex>
+class unique_lock : public lock_guard<mutex> {
+ public:
+  unique_lock(mutex &mu) : lock_guard(mu) { }
+  void lock() { lock_internal(); }
+  void unlock() { unlock_internal(); }
+};
+
+class condition_variable {
+ public:
+  condition_variable() { gpr_cv_init(&cv_); }
+  ~condition_variable() { gpr_cv_destroy(&cv_); }
+  void wait(lock_guard<mutex> &mu) {
+    mu.locked = false;
+    gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future);
+    mu.locked = true;
+  }
+  void notify_one() { gpr_cv_signal(&cv_); }
+  void notify_all() { gpr_cv_broadcast(&cv_); }
+ private:
+  gpr_cv cv_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_SYNC_NO_CXX11_H
diff --git a/src/php/ext/grpc/event.h b/include/grpc++/impl/thd.h
old mode 100755
new mode 100644
similarity index 79%
rename from src/php/ext/grpc/event.h
rename to include/grpc++/impl/thd.h
index ef5846a..4c4578a
--- a/src/php/ext/grpc/event.h
+++ b/include/grpc++/impl/thd.h
@@ -31,21 +31,15 @@
  *
  */
 
-#ifndef NET_GRPC_PHP_GRPC_EVENT_H_
-#define NET_GRPC_PHP_GRPC_EVENT_H_
+#ifndef GRPCXX_IMPL_THD_H
+#define GRPCXX_IMPL_THD_H
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <grpc++/config.h>
+
+#ifdef GRPC_CXX0X_NO_THREAD
+#include <grpc++/impl/thd_no_cxx11.h>
+#else
+#include <grpc++/impl/thd_cxx11.h>
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
-
-#include "grpc/grpc.h"
-
-/* Create a new Event object that wraps an existing grpc_event struct */
-zval *grpc_php_convert_event(grpc_event *event);
-
-#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */
+#endif  // GRPCXX_IMPL_THD_H
diff --git a/src/php/lib/autoload.php b/include/grpc++/impl/thd_cxx11.h
old mode 100755
new mode 100644
similarity index 79%
rename from src/php/lib/autoload.php
rename to include/grpc++/impl/thd_cxx11.h
index 42eb33d..2055b1d
--- a/src/php/lib/autoload.php
+++ b/include/grpc++/impl/thd_cxx11.h
@@ -1,4 +1,3 @@
-<?php
 /*
  *
  * Copyright 2015, Google Inc.
@@ -31,23 +30,16 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-function grpcAutoloader($class) {
-  $prefix = 'Grpc\\';
 
-  $base_dir = __DIR__ . '/Grpc/';
+#ifndef GRPCXX_IMPL_THD_CXX11_H
+#define GRPCXX_IMPL_THD_CXX11_H
 
-  $len = strlen($prefix);
-  if (strncmp($prefix, $class, $len) !== 0) {
-    return;
-  }
+#include <thread>
 
-  $relative_class = substr($class, $len);
+namespace grpc {
 
-  $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
+using std::thread;
 
-  if (file_exists($file)) {
-    include $file;
-  }
-}
+}  // namespace grpc
 
-spl_autoload_register('grpcAutoloader');
+#endif  // GRPCXX_IMPL_THD_CXX11_H
diff --git a/include/grpc++/impl/thd_no_cxx11.h b/include/grpc++/impl/thd_no_cxx11.h
new file mode 100644
index 0000000..a01b931
--- /dev/null
+++ b/include/grpc++/impl/thd_no_cxx11.h
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_THD_NO_CXX11_H
+#define GRPCXX_IMPL_THD_NO_CXX11_H
+
+#include <grpc/support/thd.h>
+
+namespace grpc {
+
+class thread {
+ public:
+  template<class T> thread(void (T::*fptr)(), T *obj) {
+    func_ = new thread_function<T>(fptr, obj);
+    joined_ = false;
+    start();
+  }
+  ~thread() {
+    if (!joined_) std::terminate();
+    delete func_;
+  }
+  void join() {
+    gpr_thd_join(thd_);
+    joined_ = true;
+  }
+ private:
+  void start() {
+    gpr_thd_options options = gpr_thd_options_default();
+    gpr_thd_options_set_joinable(&options);
+    gpr_thd_new(&thd_, thread_func, (void *) func_, &options);
+  }
+  static void thread_func(void *arg) {
+    thread_function_base *func = (thread_function_base *) arg;
+    func->call();
+  }
+  class thread_function_base {
+   public:
+    virtual ~thread_function_base() { }
+    virtual void call() = 0;
+  };
+  template<class T>
+  class thread_function : public thread_function_base {
+   public:
+    thread_function(void (T::*fptr)(), T *obj)
+      : fptr_(fptr)
+      , obj_(obj) { }
+    virtual void call() { (obj_->*fptr_)(); }
+   private:
+    void (T::*fptr_)();
+    T *obj_;
+  };
+  thread_function_base *func_;
+  gpr_thd_id thd_;
+  bool joined_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_THD_NO_CXX11_H
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index bddb4f6..eb50611 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -34,15 +34,14 @@
 #ifndef GRPCXX_SERVER_H
 #define GRPCXX_SERVER_H
 
-#include <condition_variable>
 #include <list>
 #include <memory>
-#include <mutex>
 
 #include <grpc++/completion_queue.h>
 #include <grpc++/config.h>
 #include <grpc++/impl/call.h>
 #include <grpc++/impl/service_type.h>
+#include <grpc++/impl/sync.h>
 #include <grpc++/status.h>
 
 struct grpc_server;
@@ -110,12 +109,12 @@
   CompletionQueue cq_;
 
   // Sever status
-  std::mutex mu_;
+  grpc::mutex mu_;
   bool started_;
   bool shutdown_;
   // The number of threads which are running callbacks.
   int num_running_cb_;
-  std::condition_variable callback_cv_;
+  grpc::condition_variable callback_cv_;
 
   std::list<SyncRequest> sync_methods_;
 
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index 53f6cd0..034de5b 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -223,7 +223,7 @@
 #endif
 
 #if defined(GPR_POSIX_SOCKET) + defined(GPR_WIN32) != 1
-#error Must define exactly one of GPR_POSIX_POLLSET, GPR_WIN32
+#error Must define exactly one of GPR_POSIX_SOCKET, GPR_WIN32
 #endif
 
 typedef int16_t gpr_int16;
diff --git a/include/grpc/support/thd.h b/include/grpc/support/thd.h
index 64d5bed..8126992 100644
--- a/include/grpc/support/thd.h
+++ b/include/grpc/support/thd.h
@@ -52,9 +52,8 @@
 
 /* Thread creation options. */
 typedef struct {
-  int flags; /* Flags below can be set here.  Default value 0.  */
+  int flags; /* Opaque field. Get and set with accessors below. */
 } gpr_thd_options;
-/* No flags are currently defined. */
 
 /* Create a new thread running (*thd_body)(arg) and place its thread identifier
    in *t, and return true.  If there are insufficient resources, return false.
@@ -66,9 +65,25 @@
 /* Return a gpr_thd_options struct with all fields set to defaults. */
 gpr_thd_options gpr_thd_options_default(void);
 
+/* Set the thread to become detached on startup - this is the default. */
+void gpr_thd_options_set_detached(gpr_thd_options *options);
+
+/* Set the thread to become joinable - mutually exclusive with detached. */
+void gpr_thd_options_set_joinable(gpr_thd_options *options);
+
+/* Returns non-zero if the option detached is set. */
+int gpr_thd_options_is_detached(const gpr_thd_options *options);
+
+/* Returns non-zero if the option joinable is set. */
+int gpr_thd_options_is_joinable(const gpr_thd_options *options);
+
 /* Returns the identifier of the current thread. */
 gpr_thd_id gpr_thd_currentid(void);
 
+/* Blocks until the specified thread properly terminates.
+   Calling this on a detached thread has unpredictable results. */
+void gpr_thd_join(gpr_thd_id t);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index d500462..c78f033 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -109,9 +109,49 @@
   }
   return false;
 }
+
+grpc::string FilenameIdentifier(const grpc::string& filename) {
+  grpc::string result;
+  for (unsigned i = 0; i < filename.size(); i++) {
+    char c = filename[i];
+    if (isalnum(c)) {
+      result.push_back(c);
+    } else {
+      static char hex[] = "0123456789abcdef";
+      result.push_back('_');
+      result.push_back(hex[(c >> 4) & 0xf]);
+      result.push_back(hex[c & 0xf]);
+    }
+  }
+  return result;
+}
 }  // namespace
 
-grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file) {
+grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params) {
+  grpc::string output;
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  grpc::protobuf::io::Printer printer(&output_stream, '$');
+  std::map<grpc::string, grpc::string> vars;
+
+  vars["filename"] = file->name();
+  vars["filename_identifier"] = FilenameIdentifier(file->name());
+  vars["filename_base"] = grpc_generator::StripProto(file->name());
+
+  printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+  printer.Print(vars, "// If you make any local change, they will be lost.\n");
+  printer.Print(vars, "// source: $filename$\n");
+  printer.Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
+  printer.Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
+  printer.Print(vars, "\n");
+  printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
+  printer.Print(vars, "\n");
+
+  return output;
+}
+
+grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params) {
   grpc::string temp =
       "#include <grpc++/impl/internal_stub.h>\n"
       "#include <grpc++/impl/service_type.h>\n"
@@ -155,17 +195,21 @@
         "class ServerAsyncReaderWriter;\n");
   }
   temp.append("}  // namespace grpc\n");
-  return temp;
-}
 
-grpc::string GetSourceIncludes() {
-  return "#include <grpc++/async_unary_call.h>\n"
-         "#include <grpc++/channel_interface.h>\n"
-         "#include <grpc++/impl/client_unary_call.h>\n"
-         "#include <grpc++/impl/rpc_method.h>\n"
-         "#include <grpc++/impl/rpc_service_method.h>\n"
-         "#include <grpc++/impl/service_type.h>\n"
-         "#include <grpc++/stream.h>\n";
+  temp.append("\n");
+
+  std::vector<grpc::string> parts =
+    grpc_generator::tokenize(file->package(), ".");
+
+  for (auto part = parts.begin(); part != parts.end(); part++) {
+    temp.append("namespace ");
+    temp.append(*part);
+    temp.append(" {\n");
+  }
+
+  temp.append("\n");
+
+  return temp;
 }
 
 void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
@@ -353,16 +397,99 @@
   printer->Print("};\n");
 }
 
-grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file) {
+grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params) {
   grpc::string output;
   grpc::protobuf::io::StringOutputStream output_stream(&output);
   grpc::protobuf::io::Printer printer(&output_stream, '$');
   std::map<grpc::string, grpc::string> vars;
 
+  if (!params.services_namespace.empty()) {
+    vars["services_namespace"] = params.services_namespace;
+    printer.Print(vars, "\nnamespace $services_namespace$ {\n\n");
+  }
+
   for (int i = 0; i < file->service_count(); ++i) {
     PrintHeaderService(&printer, file->service(i), &vars);
     printer.Print("\n");
   }
+
+  if (!params.services_namespace.empty()) {
+    printer.Print(vars, "}  // namespace $services_namespace$\n\n");
+  }
+
+  return output;
+}
+
+grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params) {
+  grpc::string output;
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  grpc::protobuf::io::Printer printer(&output_stream, '$');
+  std::map<grpc::string, grpc::string> vars;
+
+  vars["filename"] = file->name();
+  vars["filename_identifier"] = FilenameIdentifier(file->name());
+
+  std::vector<grpc::string> parts =
+    grpc_generator::tokenize(file->package(), ".");
+
+  for (auto part = parts.rbegin(); part != parts.rend(); part++) {
+    vars["part"] = *part;
+    printer.Print(vars, "}  // namespace $part$\n");
+  }
+
+  printer.Print(vars, "\n\n");
+  printer.Print(vars, "#endif  // GRPC_$filename_identifier$__INCLUDED\n");
+
+  return output;
+}
+
+grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params) {
+  grpc::string output;
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  grpc::protobuf::io::Printer printer(&output_stream, '$');
+  std::map<grpc::string, grpc::string> vars;
+
+  vars["filename"] = file->name();
+  vars["filename_base"] = grpc_generator::StripProto(file->name());
+
+  printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+  printer.Print(vars, "// If you make any local change, they will be lost.\n");
+  printer.Print(vars, "// source: $filename$\n\n");
+  printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
+  printer.Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n");
+  printer.Print(vars, "\n");
+
+  return output;
+}
+
+grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &param) {
+  grpc::string output;
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  grpc::protobuf::io::Printer printer(&output_stream, '$');
+  std::map<grpc::string, grpc::string> vars;
+
+  printer.Print(vars, "#include <grpc++/async_unary_call.h>\n");
+  printer.Print(vars, "#include <grpc++/channel_interface.h>\n");
+  printer.Print(vars, "#include <grpc++/impl/client_unary_call.h>\n");
+  printer.Print(vars, "#include <grpc++/impl/rpc_method.h>\n");
+  printer.Print(vars, "#include <grpc++/impl/rpc_service_method.h>\n");
+  printer.Print(vars, "#include <grpc++/impl/service_type.h>\n");
+  printer.Print(vars, "#include <grpc++/stream.h>\n");
+
+  std::vector<grpc::string> parts =
+    grpc_generator::tokenize(file->package(), ".");
+
+  for (auto part = parts.begin(); part != parts.end(); part++) {
+    vars["part"] = *part;
+    printer.Print(vars, "namespace $part$ {\n");
+  }
+
+  printer.Print(vars, "\n");
+
   return output;
 }
 
@@ -376,18 +503,18 @@
       grpc_cpp_generator::ClassName(method->output_type(), true);
   if (NoStreaming(method)) {
     printer->Print(*vars,
-                   "::grpc::Status $Service$::Stub::$Method$("
+                   "::grpc::Status $ns$$Service$::Stub::$Method$("
                    "::grpc::ClientContext* context, "
                    "const $Request$& request, $Response$* response) {\n");
     printer->Print(*vars,
                    "  return ::grpc::BlockingUnaryCall(channel(),"
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$]), "
                    "context, request, response);\n"
                    "}\n\n");
     printer->Print(
         *vars,
         "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
-        "$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
+        "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
         "const $Request$& request, "
         "::grpc::CompletionQueue* cq, void* tag) {\n");
     printer->Print(*vars,
@@ -395,32 +522,32 @@
                    "::grpc::ClientAsyncResponseReader< $Response$>>(new "
                    "::grpc::ClientAsyncResponseReader< $Response$>("
                    "channel(), cq, "
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$]), "
                    "context, request, tag));\n"
                    "}\n\n");
   } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
                    "std::unique_ptr< ::grpc::ClientWriter< $Request$>> "
-                   "$Service$::Stub::$Method$("
+                   "$ns$$Service$::Stub::$Method$("
                    "::grpc::ClientContext* context, $Response$* response) {\n");
     printer->Print(*vars,
                    "  return std::unique_ptr< ::grpc::ClientWriter< "
                    "$Request$>>(new ::grpc::ClientWriter< $Request$>("
                    "channel(),"
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
                    "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
                    "context, response));\n"
                    "}\n\n");
     printer->Print(*vars,
                    "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>> "
-                   "$Service$::Stub::Async$Method$("
+                   "$ns$$Service$::Stub::Async$Method$("
                    "::grpc::ClientContext* context, $Response$* response, "
                    "::grpc::CompletionQueue* cq, void* tag) {\n");
     printer->Print(*vars,
                    "  return std::unique_ptr< ::grpc::ClientAsyncWriter< "
                    "$Request$>>(new ::grpc::ClientAsyncWriter< $Request$>("
                    "channel(), cq, "
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
                    "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
                    "context, response, tag));\n"
                    "}\n\n");
@@ -428,26 +555,26 @@
     printer->Print(
         *vars,
         "std::unique_ptr< ::grpc::ClientReader< $Response$>> "
-        "$Service$::Stub::$Method$("
+        "$ns$$Service$::Stub::$Method$("
         "::grpc::ClientContext* context, const $Request$& request) {\n");
     printer->Print(*vars,
                    "  return std::unique_ptr< ::grpc::ClientReader< "
                    "$Response$>>(new ::grpc::ClientReader< $Response$>("
                    "channel(),"
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
                    "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
                    "context, request));\n"
                    "}\n\n");
     printer->Print(*vars,
                    "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
-                   "$Service$::Stub::Async$Method$("
+                   "$ns$$Service$::Stub::Async$Method$("
                    "::grpc::ClientContext* context, const $Request$& request, "
                    "::grpc::CompletionQueue* cq, void* tag) {\n");
     printer->Print(*vars,
                    "  return std::unique_ptr< ::grpc::ClientAsyncReader< "
                    "$Response$>>(new ::grpc::ClientAsyncReader< $Response$>("
                    "channel(), cq, "
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
                    "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
                    "context, request, tag));\n"
                    "}\n\n");
@@ -455,27 +582,27 @@
     printer->Print(
         *vars,
         "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>> "
-        "$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
+        "$ns$$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
     printer->Print(*vars,
                    "  return std::unique_ptr< ::grpc::ClientReaderWriter< "
                    "$Request$, $Response$>>(new ::grpc::ClientReaderWriter< "
                    "$Request$, $Response$>("
                    "channel(),"
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
                    "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
                    "context));\n"
                    "}\n\n");
     printer->Print(*vars,
                    "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
                    "$Request$, $Response$>> "
-                   "$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
+                   "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
                    "::grpc::CompletionQueue* cq, void* tag) {\n");
     printer->Print(*vars,
                    "  return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
                    "$Request$, $Response$>>(new "
                    "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
                    "channel(), cq, "
-                   "::grpc::RpcMethod($Service$_method_names[$Idx$], "
+                   "::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], "
                    "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
                    "context, tag));\n"
                    "}\n\n");
@@ -492,7 +619,7 @@
       grpc_cpp_generator::ClassName(method->output_type(), true);
   if (NoStreaming(method)) {
     printer->Print(*vars,
-                   "::grpc::Status $Service$::Service::$Method$("
+                   "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
                    "const $Request$* request, $Response$* response) {\n");
     printer->Print(
@@ -501,7 +628,7 @@
     printer->Print("}\n\n");
   } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
-                   "::grpc::Status $Service$::Service::$Method$("
+                   "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
                    "::grpc::ServerReader< $Request$>* reader, "
                    "$Response$* response) {\n");
@@ -511,7 +638,7 @@
     printer->Print("}\n\n");
   } else if (ServerOnlyStreaming(method)) {
     printer->Print(*vars,
-                   "::grpc::Status $Service$::Service::$Method$("
+                   "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
                    "const $Request$* request, "
                    "::grpc::ServerWriter< $Response$>* writer) {\n");
@@ -521,7 +648,7 @@
     printer->Print("}\n\n");
   } else if (BidiStreaming(method)) {
     printer->Print(*vars,
-                   "::grpc::Status $Service$::Service::$Method$("
+                   "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
                    "::grpc::ServerReaderWriter< $Response$, $Request$>* "
                    "stream) {\n");
@@ -543,7 +670,7 @@
       grpc_cpp_generator::ClassName(method->output_type(), true);
   if (NoStreaming(method)) {
     printer->Print(*vars,
-                   "void $Service$::AsyncService::Request$Method$("
+                   "void $ns$$Service$::AsyncService::Request$Method$("
                    "::grpc::ServerContext* context, "
                    "$Request$* request, "
                    "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
@@ -554,7 +681,7 @@
     printer->Print("}\n\n");
   } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
-                   "void $Service$::AsyncService::Request$Method$("
+                   "void $ns$$Service$::AsyncService::Request$Method$("
                    "::grpc::ServerContext* context, "
                    "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
                    "::grpc::CompletionQueue* cq, void* tag) {\n");
@@ -564,7 +691,7 @@
     printer->Print("}\n\n");
   } else if (ServerOnlyStreaming(method)) {
     printer->Print(*vars,
-                   "void $Service$::AsyncService::Request$Method$("
+                   "void $ns$$Service$::AsyncService::Request$Method$("
                    "::grpc::ServerContext* context, "
                    "$Request$* request, "
                    "::grpc::ServerAsyncWriter< $Response$>* writer, "
@@ -576,7 +703,7 @@
   } else if (BidiStreaming(method)) {
     printer->Print(
         *vars,
-        "void $Service$::AsyncService::Request$Method$("
+        "void $ns$$Service$::AsyncService::Request$Method$("
         "::grpc::ServerContext* context, "
         "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
         "::grpc::CompletionQueue* cq, void *tag) {\n");
@@ -592,7 +719,7 @@
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
-  printer->Print(*vars, "static const char* $Service$_method_names[] = {\n");
+  printer->Print(*vars, "static const char* $prefix$$Service$_method_names[] = {\n");
   for (int i = 0; i < service->method_count(); ++i) {
     (*vars)["Method"] = service->method(i)->name();
     printer->Print(*vars, "  \"/$Package$$Service$/$Method$\",\n");
@@ -601,9 +728,9 @@
 
   printer->Print(
       *vars,
-      "std::unique_ptr< $Service$::Stub> $Service$::NewStub("
+      "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
       "const std::shared_ptr< ::grpc::ChannelInterface>& channel) {\n"
-      "  std::unique_ptr< $Service$::Stub> stub(new $Service$::Stub());\n"
+      "  std::unique_ptr< $ns$$Service$::Stub> stub(new $ns$$Service$::Stub());\n"
       "  stub->set_channel(channel);\n"
       "  return stub;\n"
       "}\n\n");
@@ -615,12 +742,12 @@
   (*vars)["MethodCount"] = as_string(service->method_count());
   printer->Print(
       *vars,
-      "$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : "
-      "::grpc::AsynchronousService(cq, $Service$_method_names, $MethodCount$) "
+      "$ns$$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : "
+      "::grpc::AsynchronousService(cq, $prefix$$Service$_method_names, $MethodCount$) "
       "{}\n\n");
 
   printer->Print(*vars,
-                 "$Service$::Service::~Service() {\n"
+                 "$ns$$Service$::Service::~Service() {\n"
                  "  delete service_;\n"
                  "}\n\n");
   for (int i = 0; i < service->method_count(); ++i) {
@@ -629,7 +756,7 @@
     PrintSourceServerAsyncMethod(printer, service->method(i), vars);
   }
   printer->Print(*vars,
-                 "::grpc::RpcService* $Service$::Service::service() {\n");
+                 "::grpc::RpcService* $ns$$Service$::Service::service() {\n");
   printer->Indent();
   printer->Print(
       "if (service_ != nullptr) {\n"
@@ -648,52 +775,52 @@
       printer->Print(
           *vars,
           "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
-          "    $Service$_method_names[$Idx$],\n"
+          "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::NORMAL_RPC,\n"
-          "    new ::grpc::RpcMethodHandler< $Service$::Service, $Request$, "
+          "    new ::grpc::RpcMethodHandler< $ns$$Service$::Service, $Request$, "
           "$Response$>(\n"
-          "        std::function< ::grpc::Status($Service$::Service*, "
+          "        std::function< ::grpc::Status($ns$$Service$::Service*, "
           "::grpc::ServerContext*, const $Request$*, $Response$*)>("
-          "&$Service$::Service::$Method$), this),\n"
+          "&$ns$$Service$::Service::$Method$), this),\n"
           "    new $Request$, new $Response$));\n");
     } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
-          "    $Service$_method_names[$Idx$],\n"
+          "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::CLIENT_STREAMING,\n"
           "    new ::grpc::ClientStreamingHandler< "
-          "$Service$::Service, $Request$, $Response$>(\n"
-          "        std::function< ::grpc::Status($Service$::Service*, "
+          "$ns$$Service$::Service, $Request$, $Response$>(\n"
+          "        std::function< ::grpc::Status($ns$$Service$::Service*, "
           "::grpc::ServerContext*, "
           "::grpc::ServerReader< $Request$>*, $Response$*)>("
-          "&$Service$::Service::$Method$), this),\n"
+          "&$ns$$Service$::Service::$Method$), this),\n"
           "    new $Request$, new $Response$));\n");
     } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
-          "    $Service$_method_names[$Idx$],\n"
+          "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::SERVER_STREAMING,\n"
           "    new ::grpc::ServerStreamingHandler< "
-          "$Service$::Service, $Request$, $Response$>(\n"
-          "        std::function< ::grpc::Status($Service$::Service*, "
+          "$ns$$Service$::Service, $Request$, $Response$>(\n"
+          "        std::function< ::grpc::Status($ns$$Service$::Service*, "
           "::grpc::ServerContext*, "
           "const $Request$*, ::grpc::ServerWriter< $Response$>*)>("
-          "&$Service$::Service::$Method$), this),\n"
+          "&$ns$$Service$::Service::$Method$), this),\n"
           "    new $Request$, new $Response$));\n");
     } else if (BidiStreaming(method)) {
       printer->Print(
           *vars,
           "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
-          "    $Service$_method_names[$Idx$],\n"
+          "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::BIDI_STREAMING,\n"
           "    new ::grpc::BidiStreamingHandler< "
-          "$Service$::Service, $Request$, $Response$>(\n"
-          "        std::function< ::grpc::Status($Service$::Service*, "
+          "$ns$$Service$::Service, $Request$, $Response$>(\n"
+          "        std::function< ::grpc::Status($ns$$Service$::Service*, "
           "::grpc::ServerContext*, "
           "::grpc::ServerReaderWriter< $Response$, $Request$>*)>("
-          "&$Service$::Service::$Method$), this),\n"
+          "&$ns$$Service$::Service::$Method$), this),\n"
           "    new $Request$, new $Response$));\n");
     }
   }
@@ -702,7 +829,8 @@
   printer->Print("}\n\n");
 }
 
-grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file) {
+grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params) {
   grpc::string output;
   grpc::protobuf::io::StringOutputStream output_stream(&output);
   grpc::protobuf::io::Printer printer(&output_stream, '$');
@@ -713,6 +841,13 @@
   if (!file->package().empty()) {
     vars["Package"].append(".");
   }
+  if (!params.services_namespace.empty()) {
+    vars["ns"] = params.services_namespace + "::";
+    vars["prefix"] = params.services_namespace;
+  } else {
+    vars["ns"] = "";
+    vars["prefix"] = "";
+  }
 
   for (int i = 0; i < file->service_count(); ++i) {
     PrintSourceService(&printer, file->service(i), &vars);
@@ -721,4 +856,22 @@
   return output;
 }
 
+grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params) {
+  grpc::string temp;
+
+  std::vector<grpc::string> parts =
+    grpc_generator::tokenize(file->package(), ".");
+
+  for (auto part = parts.begin(); part != parts.end(); part++) {
+    temp.append("}  // namespace ");
+    temp.append(*part);
+    temp.append("\n");
+  }
+
+  temp.append("\n");
+
+  return temp;
+}
+
 }  // namespace grpc_cpp_generator
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 2ecdb5c..70c2e98 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -38,17 +38,43 @@
 
 namespace grpc_cpp_generator {
 
+// Contains all the parameters that are parsed from the command line.
+struct Parameters {
+  // Puts the service into a namespace
+  grpc::string services_namespace;
+};
+
+// Return the prologue of the generated header file.
+grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
+
 // Return the includes needed for generated header file.
-grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
 
 // Return the includes needed for generated source file.
-grpc::string GetSourceIncludes();
+grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
+
+// Return the epilogue of the generated header file.
+grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
+
+// Return the prologue of the generated source file.
+grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
 
 // Return the services for generated header file.
-grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
 
 // Return the services for generated source file.
-grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
+
+// Return the epilogue of the generated source file.
+grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file,
+                               const Parameters &params);
 
 }  // namespace grpc_cpp_generator
 
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index 5b83aa8..88c7049 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -58,18 +58,48 @@
       return false;
     }
 
+    grpc_cpp_generator::Parameters generator_parameters;
+
+    if (!parameter.empty()) {
+      std::vector<grpc::string> parameters_list =
+        grpc_generator::tokenize(parameter, ",");
+      for (auto parameter_string = parameters_list.begin();
+           parameter_string != parameters_list.end();
+           parameter_string++) {
+        std::vector<grpc::string> param =
+          grpc_generator::tokenize(*parameter_string, "=");
+        if (param[0] == "services_namespace") {
+          generator_parameters.services_namespace = param[1];
+        } else {
+          *error = grpc::string("Unknown parameter: ") + *parameter_string;
+          return false;
+        }
+      }
+    }
+
     grpc::string file_name = grpc_generator::StripProto(file->name());
 
-    // Generate .pb.h
-    Insert(context, file_name + ".pb.h", "includes",
-           grpc_cpp_generator::GetHeaderIncludes(file));
-    Insert(context, file_name + ".pb.h", "namespace_scope",
-           grpc_cpp_generator::GetHeaderServices(file));
-    // Generate .pb.cc
-    Insert(context, file_name + ".pb.cc", "includes",
-           grpc_cpp_generator::GetSourceIncludes());
-    Insert(context, file_name + ".pb.cc", "namespace_scope",
-           grpc_cpp_generator::GetSourceServices(file));
+    grpc::string header_code =
+        grpc_cpp_generator::GetHeaderPrologue(file, generator_parameters) +
+        grpc_cpp_generator::GetHeaderIncludes(file, generator_parameters) +
+        grpc_cpp_generator::GetHeaderServices(file, generator_parameters) +
+        grpc_cpp_generator::GetHeaderEpilogue(file, generator_parameters);
+    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
+        context->Open(file_name + ".grpc.pb.h"));
+    grpc::protobuf::io::CodedOutputStream header_coded_out(
+        header_output.get());
+    header_coded_out.WriteRaw(header_code.data(), header_code.size());
+
+    grpc::string source_code =
+        grpc_cpp_generator::GetSourcePrologue(file, generator_parameters) +
+        grpc_cpp_generator::GetSourceIncludes(file, generator_parameters) +
+        grpc_cpp_generator::GetSourceServices(file, generator_parameters) +
+        grpc_cpp_generator::GetSourceEpilogue(file, generator_parameters);
+    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
+        context->Open(file_name + ".grpc.pb.cc"));
+    grpc::protobuf::io::CodedOutputStream source_coded_out(
+        source_output.get());
+    source_coded_out.WriteRaw(source_code.data(), source_code.size());
 
     return true;
   }
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 1e6727d..374e137 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -75,6 +75,47 @@
   return str;
 }
 
+inline std::vector<grpc::string> tokenize(const grpc::string &input,
+                                          const grpc::string &delimiters) {
+  std::vector<grpc::string> tokens;
+  size_t pos, last_pos = 0;
+
+  for (;;) {
+    bool done = false;
+    pos = input.find_first_of(delimiters, last_pos);
+    if (pos == grpc::string::npos) {
+      done = true;
+      pos = input.length();
+    }
+
+    tokens.push_back(input.substr(last_pos, pos - last_pos));
+    if (done) return tokens;
+
+    last_pos = pos + 1;
+  }
+}
+
+inline grpc::string CapitalizeFirstLetter(grpc::string s) {
+  if (s.empty()) {
+    return s;
+  }
+  s[0] = ::toupper(s[0]);
+  return s;
+}
+
+inline grpc::string LowerUnderscoreToUpperCamel(grpc::string str) {
+  std::vector<grpc::string> tokens = tokenize(str, "_");
+  grpc::string result = "";
+  for (unsigned int i = 0; i < tokens.size(); i++) {
+    result += CapitalizeFirstLetter(tokens[i]);
+  }
+  return result;
+}
+
+inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) {
+  return LowerUnderscoreToUpperCamel(StripProto(file->name()));
+}
+
 }  // namespace grpc_generator
 
 #endif  // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
new file mode 100644
index 0000000..c68c9c3
--- /dev/null
+++ b/src/compiler/objective_c_generator.cc
@@ -0,0 +1,236 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <map>
+
+#include "src/compiler/objective_c_generator.h"
+#include "src/compiler/objective_c_generator_helpers.h"
+
+#include "src/compiler/config.h"
+
+#include <sstream>
+
+namespace grpc_objective_c_generator {
+namespace {
+
+void PrintSimpleBlockSignature(grpc::protobuf::io::Printer *printer,
+                               const grpc::protobuf::MethodDescriptor *method,
+                               std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["method_name"] = method->name();
+  (*vars)["request_type"] = PrefixedName(method->input_type()->name());
+  (*vars)["response_type"] = PrefixedName(method->output_type()->name());
+
+  if (method->server_streaming()) {
+    printer->Print("// When the response stream finishes, the handler is "
+                   "called with nil for both arguments.\n\n");
+  } else {
+    printer->Print("// The handler is only called once.\n\n");
+  }
+  printer->Print(*vars, "- (id<GRXLiveSource>)$method_name$WithRequest:"
+                 "($request_type$)request completionHandler:(void(^)"
+                 "($response_type$ *, NSError *))handler");
+}
+
+void PrintSimpleDelegateSignature(grpc::protobuf::io::Printer *printer,
+                                  const grpc::protobuf::MethodDescriptor *method,
+                                  std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["method_name"] = method->name();
+  (*vars)["request_type"] = PrefixedName(method->input_type()->name());
+
+  printer->Print(*vars, "- (id<GRXLiveSource>)$method_name$WithRequest:"
+                 "($request_type$)request delegate:(id<GRXSink>)delegate");
+}
+
+void PrintAdvancedSignature(grpc::protobuf::io::Printer *printer,
+                            const grpc::protobuf::MethodDescriptor *method,
+                            std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["method_name"] = method->name();
+  printer->Print(*vars, "- (GRXSource *)$method_name$WithRequest:"
+                 "(id<GRXSource>)request");
+}
+
+void PrintSourceMethodSimpleBlock(grpc::protobuf::io::Printer *printer,
+                                  const grpc::protobuf::MethodDescriptor *method,
+                                  std::map<grpc::string, grpc::string> *vars) {
+  PrintSimpleBlockSignature(printer, method, vars);
+
+  (*vars)["method_name"] = method->name();
+  printer->Print(" {\n");
+  printer->Indent();
+  printer->Print(*vars, "return [[self $method_name$WithRequest:request] "
+                 "connectHandler:^(id value, NSError *error) {\n");
+  printer->Indent();
+  printer->Print("handler(value, error);\n");
+  printer->Outdent();
+  printer->Print("}];\n");
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void PrintSourceMethodSimpleDelegate(grpc::protobuf::io::Printer *printer,
+                                     const grpc::protobuf::MethodDescriptor *method,
+                                     std::map<grpc::string, grpc::string> *vars) {
+  PrintSimpleDelegateSignature(printer, method, vars);
+
+  (*vars)["method_name"] = method->name();
+  printer->Print(" {\n");
+  printer->Indent();
+  printer->Print(*vars, "return [[self $method_name$WithRequest:request]"
+                 "connectToSink:delegate];\n");
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void PrintSourceMethodAdvanced(grpc::protobuf::io::Printer *printer,
+                               const grpc::protobuf::MethodDescriptor *method,
+                               std::map<grpc::string, grpc::string> *vars) {
+  PrintAdvancedSignature(printer, method, vars);
+
+  (*vars)["method_name"] = method->name();
+  printer->Print(" {\n");
+  printer->Indent();
+  printer->Print(*vars, "return [self $method_name$WithRequest:request "
+                 "client:[self newClient]];\n");
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+void PrintSourceMethodHandler(grpc::protobuf::io::Printer *printer,
+                              const grpc::protobuf::MethodDescriptor *method,
+                              std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["method_name"] = method->name();
+  (*vars)["response_type"] = PrefixedName(method->output_type()->name());
+  (*vars)["caps_name"] = grpc_generator::CapitalizeFirstLetter(method->name());
+
+  printer->Print(*vars, "- (GRXSource *)$method_name$WithRequest:"
+                 "(id<GRXSource>)request client:(PBgRPCClient *)client {\n");
+  printer->Indent();
+  printer->Print(*vars,
+                 "return [self responseWithMethod:$@\"$caps_name\"\n");
+  printer->Print(*vars,
+                 "                          class:[$response_type$ class]\n");
+  printer->Print("                        request:request\n");
+  printer->Print("                         client:client];\n");
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+}
+
+grpc::string GetHeader(const grpc::protobuf::ServiceDescriptor *service,
+                       const grpc::string message_header) {
+  grpc::string output;
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  grpc::protobuf::io::Printer printer(&output_stream, '$');
+  std::map<grpc::string, grpc::string> vars;
+  printer.Print("#import \"PBgRPCClient.h\"\n");
+  printer.Print("#import \"PBStub.h\"\n");
+  vars["message_header"] = message_header;
+  printer.Print(vars, "#import \"$message_header$\"\n\n");
+  printer.Print("@protocol GRXSource\n");
+  printer.Print("@class GRXSource\n\n");
+  vars["service_name"] = service->name();
+  printer.Print("@protocol $service_name$Stub <NSObject>\n\n");
+  printer.Print("#pragma mark Simple block handlers\n\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintSimpleBlockSignature(&printer, service->method(i), &vars);
+    printer.Print(";\n");
+  }
+  printer.Print("\n");
+  printer.Print("#pragma mark Simple delegate handlers.\n\n");
+  printer.Print("# TODO(jcanizales): Use high-level snippets to remove this duplication.");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintSimpleDelegateSignature(&printer, service->method(i), &vars);
+    printer.Print(";\n");
+  }
+  printer.Print("\n");
+  printer.Print("#pragma mark Advanced handlers.\n\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintAdvancedSignature(&printer, service->method(i), &vars);
+    printer.Print(";\n");
+  }
+  printer.Print("\n");
+  printer.Print("@end\n\n");
+  printer.Print("// Basic stub that only does marshalling and parsing\n");
+  printer.Print(vars, "@interface $service_name$Stub :"
+                " PBStub<$service_name$Stub>\n");
+  printer.Print("- (instancetype)initWithHost:(NSString *)host;\n");
+  printer.Print("@end\n");
+  return output;
+}
+
+grpc::string GetSource(const grpc::protobuf::ServiceDescriptor *service) {
+  grpc::string output;
+  grpc::protobuf::io::StringOutputStream output_stream(&output);
+  grpc::protobuf::io::Printer printer(&output_stream, '$');
+  std::map<grpc::string, grpc::string> vars;
+  vars["service_name"] = service->name();
+  printer.Print(vars, "#import \"$service_name$Stub.pb.h\"\n");
+  printer.Print("#import \"PBGeneratedMessage+GRXSource.h\"\n\n");
+  vars["full_name"] = service->full_name();
+  printer.Print(vars,
+                "static NSString *const kInterface = @\"$full_name$\";\n");
+  printer.Print("@implementation $service_name$Stub\n\n");
+  printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
+  printer.Indent();
+  printer.Print("if ((self = [super initWithHost:host "
+                "interface:kInterface])) {\n");
+  printer.Print("}\n");
+  printer.Print("return self;\n");
+  printer.Outdent();
+  printer.Print("}\n\n");
+  printer.Print("#pragma mark Simple block handlers.\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintSourceMethodSimpleBlock(&printer, service->method(i), &vars);
+  }
+  printer.Print("\n");
+  printer.Print("#pragma mark Simple delegate handlers.\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintSourceMethodSimpleDelegate(&printer, service->method(i), &vars);
+  }
+  printer.Print("\n");
+  printer.Print("#pragma mark Advanced handlers.\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintSourceMethodAdvanced(&printer, service->method(i), &vars);
+  }
+  printer.Print("\n");
+  printer.Print("#pragma mark Handlers for subclasses "
+                "(stub wrappers) to override.\n");
+  for (int i = 0; i < service->method_count(); i++) {
+    PrintSourceMethodHandler(&printer, service->method(i), &vars);
+  }
+  printer.Print("@end\n");
+  return output;
+}
+
+} // namespace grpc_objective_c_generator
diff --git a/src/php/tests/unit_tests/CompletionQueueTest.php b/src/compiler/objective_c_generator.h
old mode 100755
new mode 100644
similarity index 75%
copy from src/php/tests/unit_tests/CompletionQueueTest.php
copy to src/compiler/objective_c_generator.h
index 76ee61d..93c730b
--- a/src/php/tests/unit_tests/CompletionQueueTest.php
+++ b/src/compiler/objective_c_generator.h
@@ -1,4 +1,3 @@
-<?php
 /*
  *
  * Copyright 2015, Google Inc.
@@ -31,16 +30,19 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-class CompletionQueueTest extends PHPUnit_Framework_TestCase{
-  public function testNextReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->next(Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
 
-  public function testPluckReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->pluck(0, Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
-}
+#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H
+
+#include "src/compiler/config.h"
+
+namespace grpc_objective_c_generator {
+
+grpc::string GetHeader(const grpc::protobuf::ServiceDescriptor *service,
+                       const grpc::string message_header);
+
+grpc::string GetSource(const grpc::protobuf::ServiceDescriptor *service);
+
+}  // namespace grpc_objective_c_generator
+
+#endif  // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H
diff --git a/src/php/tests/unit_tests/CompletionQueueTest.php b/src/compiler/objective_c_generator_helpers.h
old mode 100755
new mode 100644
similarity index 68%
copy from src/php/tests/unit_tests/CompletionQueueTest.php
copy to src/compiler/objective_c_generator_helpers.h
index 76ee61d..6a7c139
--- a/src/php/tests/unit_tests/CompletionQueueTest.php
+++ b/src/compiler/objective_c_generator_helpers.h
@@ -1,4 +1,3 @@
-<?php
 /*
  *
  * Copyright 2015, Google Inc.
@@ -31,16 +30,29 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-class CompletionQueueTest extends PHPUnit_Framework_TestCase{
-  public function testNextReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->next(Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
 
-  public function testPluckReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->pluck(0, Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
+#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
+#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
+
+#include <map>
+#include "src/compiler/config.h"
+#include "src/compiler/generator_helpers.h"
+
+namespace grpc_objective_c_generator {
+
+const grpc::string prefix = "PBG";
+
+inline grpc::string MessageHeaderName(const grpc::protobuf::FileDescriptor *file) {
+  return grpc_generator::FileNameInUpperCamel(file) + ".pb.h";
 }
+
+inline grpc::string StubFileName(grpc::string service_name) {
+  return prefix + service_name + "Stub";
+}
+
+inline grpc::string PrefixedName(grpc::string name) {
+  return prefix + name;
+}
+
+}
+#endif  // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
new file mode 100644
index 0000000..eebce0c
--- /dev/null
+++ b/src/compiler/objective_c_plugin.cc
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+// Generates Objective C gRPC service interface out of Protobuf IDL.
+
+#include <memory>
+
+#include "src/compiler/config.h"
+#include "src/compiler/objective_c_generator.h"
+#include "src/compiler/objective_c_generator_helpers.h"
+
+class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
+ public:
+  ObjectiveCGrpcGenerator() {}
+  virtual ~ObjectiveCGrpcGenerator() {}
+
+  virtual bool Generate(const grpc::protobuf::FileDescriptor *file,
+                        const grpc::string &parameter,
+                        grpc::protobuf::compiler::GeneratorContext *context,
+                        grpc::string *error) const {
+
+    if (file->service_count() == 0) {
+      // No services.  Do nothing.
+      return true;
+    }
+
+    for (int i = 0; i < file->service_count(); i++) {
+      const grpc::protobuf::ServiceDescriptor *service = file->service(i);
+      grpc::string file_name = grpc_objective_c_generator::StubFileName(
+          service->name());
+
+      // Generate .pb.h
+      grpc::string header_code = grpc_objective_c_generator::GetHeader(
+          service, grpc_objective_c_generator::MessageHeaderName(file));
+      std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
+        context->Open(file_name + ".pb.h"));
+      grpc::protobuf::io::CodedOutputStream header_coded_out(
+          header_output.get());
+      header_coded_out.WriteRaw(header_code.data(), header_code.size());
+
+      // Generate .pb.m
+      grpc::string source_code = grpc_objective_c_generator::GetSource(service);
+      std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
+        context->Open(file_name + ".pb.m"));
+      grpc::protobuf::io::CodedOutputStream source_coded_out(
+          source_output.get());
+      source_coded_out.WriteRaw(source_code.data(), source_code.size());
+    }
+
+    return true;
+  }
+
+ private:
+  // Insert the given code into the given file at the given insertion point.
+  void Insert(grpc::protobuf::compiler::GeneratorContext *context,
+              const grpc::string &filename, const grpc::string &insertion_point,
+              const grpc::string &code) const {
+    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
+        context->OpenForInsert(filename, insertion_point));
+    grpc::protobuf::io::CodedOutputStream coded_out(output.get());
+    coded_out.WriteRaw(code.data(), code.size());
+  }
+};
+
+int main(int argc, char *argv[]) {
+  ObjectiveCGrpcGenerator generator;
+  return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
+}
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index e4f8545..72149bc 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -36,25 +36,28 @@
 #include <cctype>
 #include <cstring>
 #include <map>
+#include <memory>
 #include <ostream>
 #include <sstream>
+#include <tuple>
 #include <vector>
 
+#include "grpc++/config.h"
+#include "src/compiler/config.h"
 #include "src/compiler/generator_helpers.h"
 #include "src/compiler/python_generator.h"
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/descriptor.h>
 
 using grpc_generator::StringReplace;
 using grpc_generator::StripProto;
-using google::protobuf::Descriptor;
-using google::protobuf::FileDescriptor;
-using google::protobuf::MethodDescriptor;
-using google::protobuf::ServiceDescriptor;
-using google::protobuf::io::Printer;
-using google::protobuf::io::StringOutputStream;
+using grpc::protobuf::Descriptor;
+using grpc::protobuf::FileDescriptor;
+using grpc::protobuf::MethodDescriptor;
+using grpc::protobuf::ServiceDescriptor;
+using grpc::protobuf::compiler::GeneratorContext;
+using grpc::protobuf::io::CodedOutputStream;
+using grpc::protobuf::io::Printer;
+using grpc::protobuf::io::StringOutputStream;
+using grpc::protobuf::io::ZeroCopyOutputStream;
 using std::initializer_list;
 using std::make_pair;
 using std::map;
@@ -63,6 +66,41 @@
 using std::vector;
 
 namespace grpc_python_generator {
+
+PythonGrpcGenerator::PythonGrpcGenerator(const GeneratorConfiguration& config)
+    : config_(config) {}
+
+PythonGrpcGenerator::~PythonGrpcGenerator() {}
+
+bool PythonGrpcGenerator::Generate(
+    const FileDescriptor* file, const grpc::string& parameter,
+    GeneratorContext* context, grpc::string* error) const {
+  // Get output file name.
+  grpc::string file_name;
+  static const int proto_suffix_length = strlen(".proto");
+  if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
+      file->name().find_last_of(".proto") == file->name().size() - 1) {
+    file_name = file->name().substr(
+        0, file->name().size() - proto_suffix_length) + "_pb2.py";
+  } else {
+    *error = "Invalid proto file name. Proto file must end with .proto";
+    return false;
+  }
+
+  std::unique_ptr<ZeroCopyOutputStream> output(
+      context->OpenForInsert(file_name, "module_scope"));
+  CodedOutputStream coded_out(output.get());
+  bool success = false;
+  grpc::string code = "";
+  tie(success, code) = grpc_python_generator::GetServices(file, config_);
+  if (success) {
+    coded_out.WriteRaw(code.data(), code.size());
+    return true;
+  } else {
+    return false;
+  }
+}
+
 namespace {
 //////////////////////////////////
 // BEGIN FORMATTING BOILERPLATE //
@@ -70,14 +108,15 @@
 
 // Converts an initializer list of the form { key0, value0, key1, value1, ... }
 // into a map of key* to value*. Is merely a readability helper for later code.
-map<std::string, std::string> ListToDict(const initializer_list<std::string>& values) {
+map<grpc::string, grpc::string> ListToDict(
+    const initializer_list<grpc::string>& values) {
   assert(values.size() % 2 == 0);
-  map<std::string, std::string> value_map;
+  map<grpc::string, grpc::string> value_map;
   auto value_iter = values.begin();
   for (unsigned i = 0; i < values.size()/2; ++i) {
-    std::string key = *value_iter;
+    grpc::string key = *value_iter;
     ++value_iter;
-    std::string value = *value_iter;
+    grpc::string value = *value_iter;
     value_map[key] = value;
     ++value_iter;
   }
@@ -111,8 +150,8 @@
 
 bool PrintServicer(const ServiceDescriptor* service,
                    Printer* out) {
-  std::string doc = "<fill me in later!>";
-  map<std::string, std::string> dict = ListToDict({
+  grpc::string doc = "<fill me in later!>";
+  map<grpc::string, grpc::string> dict = ListToDict({
         "Service", service->name(),
         "Documentation", doc,
       });
@@ -123,7 +162,7 @@
     out->Print("__metaclass__ = abc.ABCMeta\n");
     for (int i = 0; i < service->method_count(); ++i) {
       auto meth = service->method(i);
-      std::string arg_name = meth->client_streaming() ?
+      grpc::string arg_name = meth->client_streaming() ?
           "request_iterator" : "request";
       out->Print("@abc.abstractmethod\n");
       out->Print("def $Method$(self, $ArgName$, context):\n",
@@ -138,8 +177,8 @@
 }
 
 bool PrintServer(const ServiceDescriptor* service, Printer* out) {
-  std::string doc = "<fill me in later!>";
-  map<std::string, std::string> dict = ListToDict({
+  grpc::string doc = "<fill me in later!>";
+  map<grpc::string, grpc::string> dict = ListToDict({
         "Service", service->name(),
         "Documentation", doc,
       });
@@ -167,8 +206,8 @@
 
 bool PrintStub(const ServiceDescriptor* service,
                Printer* out) {
-  std::string doc = "<fill me in later!>";
-  map<std::string, std::string> dict = ListToDict({
+  grpc::string doc = "<fill me in later!>";
+  map<grpc::string, grpc::string> dict = ListToDict({
         "Service", service->name(),
         "Documentation", doc,
       });
@@ -179,7 +218,7 @@
     out->Print("__metaclass__ = abc.ABCMeta\n");
     for (int i = 0; i < service->method_count(); ++i) {
       const MethodDescriptor* meth = service->method(i);
-      std::string arg_name = meth->client_streaming() ?
+      grpc::string arg_name = meth->client_streaming() ?
           "request_iterator" : "request";
       auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
       out->Print("@abc.abstractmethod\n");
@@ -196,29 +235,29 @@
 
 // TODO(protobuf team): Export `ModuleName` from protobuf's
 // `src/google/protobuf/compiler/python/python_generator.cc` file.
-std::string ModuleName(const std::string& filename) {
-  std::string basename = StripProto(filename);
+grpc::string ModuleName(const grpc::string& filename) {
+  grpc::string basename = StripProto(filename);
   basename = StringReplace(basename, "-", "_");
   basename = StringReplace(basename, "/", ".");
   return basename + "_pb2";
 }
 
 bool GetModuleAndMessagePath(const Descriptor* type,
-                             pair<std::string, std::string>* out) {
+                             pair<grpc::string, grpc::string>* out) {
   const Descriptor* path_elem_type = type;
   vector<const Descriptor*> message_path;
   do {
     message_path.push_back(path_elem_type);
     path_elem_type = path_elem_type->containing_type();
   } while (path_elem_type != nullptr);
-  std::string file_name = type->file()->name();
+  grpc::string file_name = type->file()->name();
   static const int proto_suffix_length = strlen(".proto");
   if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
         file_name.find_last_of(".proto") == file_name.size() - 1)) {
     return false;
   }
-  std::string module = ModuleName(file_name);
-  std::string message_type;
+  grpc::string module = ModuleName(file_name);
+  grpc::string message_type;
   for (auto path_iter = message_path.rbegin();
        path_iter != message_path.rend(); ++path_iter) {
     message_type += (*path_iter)->name() + ".";
@@ -229,28 +268,30 @@
   return true;
 }
 
-bool PrintServerFactory(const std::string& package_qualified_service_name,
+bool PrintServerFactory(const grpc::string& package_qualified_service_name,
                         const ServiceDescriptor* service, Printer* out) {
   out->Print("def early_adopter_create_$Service$_server(servicer, port, "
-             "root_certificates, key_chain_pairs):\n",
+             "private_key=None, certificate_chain=None):\n",
              "Service", service->name());
   {
     IndentScope raii_create_server_indent(out);
-    map<std::string, std::string> method_description_constructors;
-    map<std::string, pair<std::string, std::string>> input_message_modules_and_classes;
-    map<std::string, pair<std::string, std::string>> output_message_modules_and_classes;
+    map<grpc::string, grpc::string> method_description_constructors;
+    map<grpc::string, pair<grpc::string, grpc::string>>
+        input_message_modules_and_classes;
+    map<grpc::string, pair<grpc::string, grpc::string>>
+        output_message_modules_and_classes;
     for (int i = 0; i < service->method_count(); ++i) {
       const MethodDescriptor* method = service->method(i);
-      const std::string method_description_constructor =
-          std::string(method->client_streaming() ? "stream_" : "unary_") +
-          std::string(method->server_streaming() ? "stream_" : "unary_") +
+      const grpc::string method_description_constructor =
+          grpc::string(method->client_streaming() ? "stream_" : "unary_") +
+          grpc::string(method->server_streaming() ? "stream_" : "unary_") +
           "service_description";
-      pair<std::string, std::string> input_message_module_and_class;
+      pair<grpc::string, grpc::string> input_message_module_and_class;
       if (!GetModuleAndMessagePath(method->input_type(),
                                    &input_message_module_and_class)) {
         return false;
       }
-      pair<std::string, std::string> output_message_module_and_class;
+      pair<grpc::string, grpc::string> output_message_module_and_class;
       if (!GetModuleAndMessagePath(method->output_type(),
                                    &output_message_module_and_class)) {
         return false;
@@ -268,17 +309,20 @@
           make_pair(method->name(), output_message_module_and_class));
     }
     out->Print("method_service_descriptions = {\n");
-    for (auto& name_and_description_constructor :
-         method_description_constructors) {
+    for (auto name_and_description_constructor =
+	   method_description_constructors.begin();
+	 name_and_description_constructor !=
+	   method_description_constructors.end();
+	 name_and_description_constructor++) {
       IndentScope raii_descriptions_indent(out);
-      const std::string method_name = name_and_description_constructor.first;
+      const grpc::string method_name = name_and_description_constructor->first;
       auto input_message_module_and_class =
           input_message_modules_and_classes.find(method_name);
       auto output_message_module_and_class =
           output_message_modules_and_classes.find(method_name);
       out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
                  method_name, "Constructor",
-                 name_and_description_constructor.second);
+                 name_and_description_constructor->second);
       {
         IndentScope raii_description_arguments_indent(out);
         out->Print("servicer.$Method$,\n", "Method", method_name);
@@ -295,38 +339,43 @@
     }
     out->Print("}\n");
     out->Print(
-        "return implementations.secure_server("
+        "return implementations.server("
         "\"$PackageQualifiedServiceName$\","
-        " method_service_descriptions, port, root_certificates,"
-        " key_chain_pairs)\n",
+        " method_service_descriptions, port, private_key=private_key,"
+        " certificate_chain=certificate_chain)\n",
         "PackageQualifiedServiceName", package_qualified_service_name);
   }
   return true;
 }
 
-bool PrintStubFactory(const std::string& package_qualified_service_name,
+bool PrintStubFactory(const grpc::string& package_qualified_service_name,
                       const ServiceDescriptor* service, Printer* out) {
-  map<std::string, std::string> dict = ListToDict({
+  map<grpc::string, grpc::string> dict = ListToDict({
         "Service", service->name(),
       });
-  out->Print(dict, "def early_adopter_create_$Service$_stub(host, port):\n");
+  out->Print(dict, "def early_adopter_create_$Service$_stub(host, port,"
+             " metadata_transformer=None,"
+             " secure=False, root_certificates=None, private_key=None,"
+             " certificate_chain=None, server_host_override=None):\n");
   {
     IndentScope raii_create_server_indent(out);
-    map<std::string, std::string> method_description_constructors;
-    map<std::string, pair<std::string, std::string>> input_message_modules_and_classes;
-    map<std::string, pair<std::string, std::string>> output_message_modules_and_classes;
+    map<grpc::string, grpc::string> method_description_constructors;
+    map<grpc::string, pair<grpc::string, grpc::string>>
+        input_message_modules_and_classes;
+    map<grpc::string, pair<grpc::string, grpc::string>>
+        output_message_modules_and_classes;
     for (int i = 0; i < service->method_count(); ++i) {
       const MethodDescriptor* method = service->method(i);
-      const std::string method_description_constructor =
-          std::string(method->client_streaming() ? "stream_" : "unary_") +
-          std::string(method->server_streaming() ? "stream_" : "unary_") +
+      const grpc::string method_description_constructor =
+          grpc::string(method->client_streaming() ? "stream_" : "unary_") +
+          grpc::string(method->server_streaming() ? "stream_" : "unary_") +
           "invocation_description";
-      pair<std::string, std::string> input_message_module_and_class;
+      pair<grpc::string, grpc::string> input_message_module_and_class;
       if (!GetModuleAndMessagePath(method->input_type(),
                                    &input_message_module_and_class)) {
         return false;
       }
-      pair<std::string, std::string> output_message_module_and_class;
+      pair<grpc::string, grpc::string> output_message_module_and_class;
       if (!GetModuleAndMessagePath(method->output_type(),
                                    &output_message_module_and_class)) {
         return false;
@@ -344,17 +393,20 @@
           make_pair(method->name(), output_message_module_and_class));
     }
     out->Print("method_invocation_descriptions = {\n");
-    for (auto& name_and_description_constructor :
-         method_description_constructors) {
+    for (auto name_and_description_constructor =
+	   method_description_constructors.begin();
+	 name_and_description_constructor !=
+	   method_description_constructors.end();
+	 name_and_description_constructor++) {
       IndentScope raii_descriptions_indent(out);
-      const std::string method_name = name_and_description_constructor.first;
+      const grpc::string method_name = name_and_description_constructor->first;
       auto input_message_module_and_class =
           input_message_modules_and_classes.find(method_name);
       auto output_message_module_and_class =
           output_message_modules_and_classes.find(method_name);
       out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
                  method_name, "Constructor",
-                 name_and_description_constructor.second);
+                 name_and_description_constructor->second);
       {
         IndentScope raii_description_arguments_indent(out);
         out->Print(
@@ -370,30 +422,37 @@
     }
     out->Print("}\n");
     out->Print(
-        "return implementations.insecure_stub("
+        "return implementations.stub("
         "\"$PackageQualifiedServiceName$\","
-        " method_invocation_descriptions, host, port)\n",
+        " method_invocation_descriptions, host, port,"
+        " metadata_transformer=metadata_transformer, secure=secure,"
+        " root_certificates=root_certificates, private_key=private_key,"
+        " certificate_chain=certificate_chain,"
+        " server_host_override=server_host_override)\n",
         "PackageQualifiedServiceName", package_qualified_service_name);
   }
   return true;
 }
 
-bool PrintPreamble(const FileDescriptor* file, Printer* out) {
+bool PrintPreamble(const FileDescriptor* file,
+                   const GeneratorConfiguration& config, Printer* out) {
   out->Print("import abc\n");
-  out->Print("from grpc.early_adopter import implementations\n");
+  out->Print("from $Package$ import implementations\n",
+             "Package", config.implementations_package_root);
   out->Print("from grpc.framework.alpha import utilities\n");
   return true;
 }
 
 }  // namespace
 
-pair<bool, std::string> GetServices(const FileDescriptor* file) {
-  std::string output;
+pair<bool, grpc::string> GetServices(const FileDescriptor* file,
+                                    const GeneratorConfiguration& config) {
+  grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
     StringOutputStream output_stream(&output);
     Printer out(&output_stream, '$');
-    if (!PrintPreamble(file, &out)) {
+    if (!PrintPreamble(file, config, &out)) {
       return make_pair(false, "");
     }
     auto package = file->package();
diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h
index df29ca1..b47f3c1 100644
--- a/src/compiler/python_generator.h
+++ b/src/compiler/python_generator.h
@@ -34,18 +34,34 @@
 #ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H
 #define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H
 
-#include <string>
 #include <utility>
 
-namespace google {
-namespace protobuf {
-class FileDescriptor;
-}  // namespace protobuf
-}  // namespace google
+#include "src/compiler/config.h"
 
 namespace grpc_python_generator {
 
-std::pair<bool, std::string> GetServices(const google::protobuf::FileDescriptor* file);
+// Data pertaining to configuration of the generator with respect to anything
+// that may be used internally at Google.
+struct GeneratorConfiguration {
+  grpc::string implementations_package_root;
+};
+
+class PythonGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
+ public:
+  PythonGrpcGenerator(const GeneratorConfiguration& config);
+  ~PythonGrpcGenerator();
+
+  bool Generate(const grpc::protobuf::FileDescriptor* file,
+                const grpc::string& parameter,
+                grpc::protobuf::compiler::GeneratorContext* context,
+                grpc::string* error) const;
+ private:
+  GeneratorConfiguration config_;
+};
+
+std::pair<bool, grpc::string> GetServices(
+    const grpc::protobuf::FileDescriptor* file,
+    const GeneratorConfiguration& config);
 
 }  // namespace grpc_python_generator
 
diff --git a/src/compiler/python_plugin.cc b/src/compiler/python_plugin.cc
index e7d172f..d1f4944 100644
--- a/src/compiler/python_plugin.cc
+++ b/src/compiler/python_plugin.cc
@@ -33,60 +33,12 @@
 
 // Generates a Python gRPC service interface out of Protobuf IDL.
 
-#include <cstring>
-#include <memory>
-#include <string>
-#include <tuple>
-
+#include "src/compiler/config.h"
 #include "src/compiler/python_generator.h"
-#include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/compiler/plugin.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/descriptor.h>
-
-using google::protobuf::FileDescriptor;
-using google::protobuf::compiler::CodeGenerator;
-using google::protobuf::compiler::GeneratorContext;
-using google::protobuf::compiler::PluginMain;
-using google::protobuf::io::CodedOutputStream;
-using google::protobuf::io::ZeroCopyOutputStream;
-
-class PythonGrpcGenerator : public CodeGenerator {
- public:
-  PythonGrpcGenerator() {}
-  ~PythonGrpcGenerator() {}
-
-  bool Generate(const FileDescriptor* file, const std::string& parameter,
-                GeneratorContext* context, std::string* error) const {
-    // Get output file name.
-    std::string file_name;
-    static const int proto_suffix_length = strlen(".proto");
-    if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
-        file->name().find_last_of(".proto") == file->name().size() - 1) {
-      file_name = file->name().substr(
-          0, file->name().size() - proto_suffix_length) + "_pb2.py";
-    } else {
-      *error = "Invalid proto file name. Proto file must end with .proto";
-      return false;
-    }
-
-    std::unique_ptr<ZeroCopyOutputStream> output(
-        context->OpenForInsert(file_name, "module_scope"));
-    CodedOutputStream coded_out(output.get());
-    bool success = false;
-    std::string code = "";
-    tie(success, code) = grpc_python_generator::GetServices(file);
-    if (success) {
-      coded_out.WriteRaw(code.data(), code.size());
-      return true;
-    } else {
-      return false;
-    }
-  }
-};
 
 int main(int argc, char* argv[]) {
-  PythonGrpcGenerator generator;
-  return PluginMain(argc, argv, &generator);
+  grpc_python_generator::GeneratorConfiguration config;
+  config.implementations_package_root = "grpc.early_adopter";
+  grpc_python_generator::PythonGrpcGenerator generator(config);
+  return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
 }
diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc
index 32b6a8d..a0bb928 100644
--- a/src/compiler/ruby_generator.cc
+++ b/src/compiler/ruby_generator.cc
@@ -32,24 +32,20 @@
  */
 
 #include <cctype>
-#include <string>
 #include <map>
 #include <vector>
 
+#include "src/compiler/config.h"
 #include "src/compiler/ruby_generator.h"
 #include "src/compiler/ruby_generator_helpers-inl.h"
 #include "src/compiler/ruby_generator_map-inl.h"
 #include "src/compiler/ruby_generator_string-inl.h"
-#include <google/protobuf/io/printer.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/descriptor.h>
 
-using google::protobuf::FileDescriptor;
-using google::protobuf::ServiceDescriptor;
-using google::protobuf::MethodDescriptor;
-using google::protobuf::io::Printer;
-using google::protobuf::io::StringOutputStream;
+using grpc::protobuf::FileDescriptor;
+using grpc::protobuf::ServiceDescriptor;
+using grpc::protobuf::MethodDescriptor;
+using grpc::protobuf::io::Printer;
+using grpc::protobuf::io::StringOutputStream;
 using std::map;
 using std::vector;
 
@@ -57,38 +53,38 @@
 namespace {
 
 // Prints out the method using the ruby gRPC DSL.
-void PrintMethod(const MethodDescriptor *method, const std::string &package,
+void PrintMethod(const MethodDescriptor *method, const grpc::string &package,
                  Printer *out) {
-  std::string input_type = RubyTypeOf(method->input_type()->name(), package);
+  grpc::string input_type = RubyTypeOf(method->input_type()->name(), package);
   if (method->client_streaming()) {
     input_type = "stream(" + input_type + ")";
   }
-  std::string output_type = RubyTypeOf(method->output_type()->name(), package);
+  grpc::string output_type = RubyTypeOf(method->output_type()->name(), package);
   if (method->server_streaming()) {
     output_type = "stream(" + output_type + ")";
   }
-  std::map<std::string, std::string> method_vars =
+  std::map<grpc::string, grpc::string> method_vars =
       ListToDict({"mth.name", method->name(), "input.type", input_type,
                   "output.type", output_type, });
   out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n");
 }
 
 // Prints out the service using the ruby gRPC DSL.
-void PrintService(const ServiceDescriptor *service, const std::string &package,
+void PrintService(const ServiceDescriptor *service, const grpc::string &package,
                   Printer *out) {
   if (service->method_count() == 0) {
     return;
   }
 
   // Begin the service module
-  std::map<std::string, std::string> module_vars =
+  std::map<grpc::string, grpc::string> module_vars =
       ListToDict({"module.name", CapitalizeFirst(service->name()), });
   out->Print(module_vars, "module $module.name$\n");
   out->Indent();
 
   // TODO(temiola): add documentation
-  std::string doc = "TODO: add proto service documentation here";
-  std::map<std::string, std::string> template_vars =
+  grpc::string doc = "TODO: add proto service documentation here";
+  std::map<grpc::string, grpc::string> template_vars =
       ListToDict({"Documentation", doc, });
   out->Print("\n");
   out->Print(template_vars, "# $Documentation$\n");
@@ -101,7 +97,7 @@
   out->Print("\n");
   out->Print("self.marshal_class_method = :encode\n");
   out->Print("self.unmarshal_class_method = :decode\n");
-  std::map<std::string, std::string> pkg_vars =
+  std::map<grpc::string, grpc::string> pkg_vars =
       ListToDict({"service.name", service->name(), "pkg.name", package, });
   out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n");
   out->Print("\n");
@@ -121,8 +117,8 @@
 
 }  // namespace
 
-std::string GetServices(const FileDescriptor *file) {
-  std::string output;
+grpc::string GetServices(const FileDescriptor *file) {
+  grpc::string output;
   StringOutputStream output_stream(&output);
   Printer out(&output_stream, '$');
 
@@ -133,7 +129,7 @@
   }
 
   // Write out a file header.
-  std::map<std::string, std::string> header_comment_vars = ListToDict(
+  std::map<grpc::string, grpc::string> header_comment_vars = ListToDict(
       {"file.name", file->name(), "file.package", file->package(), });
   out.Print("# Generated by the protocol buffer compiler.  DO NOT EDIT!\n");
   out.Print(header_comment_vars,
@@ -144,15 +140,15 @@
   // Write out require statemment to import the separately generated file
   // that defines the messages used by the service. This is generated by the
   // main ruby plugin.
-  std::map<std::string, std::string> dep_vars =
+  std::map<grpc::string, grpc::string> dep_vars =
       ListToDict({"dep.name", MessagesRequireName(file), });
   out.Print(dep_vars, "require '$dep.name$'\n");
 
   // Write out services within the modules
   out.Print("\n");
-  std::vector<std::string> modules = Split(file->package(), '.');
+  std::vector<grpc::string> modules = Split(file->package(), '.');
   for (size_t i = 0; i < modules.size(); ++i) {
-    std::map<std::string, std::string> module_vars =
+    std::map<grpc::string, grpc::string> module_vars =
         ListToDict({"module.name", CapitalizeFirst(modules[i]), });
     out.Print(module_vars, "module $module.name$\n");
     out.Indent();
diff --git a/src/compiler/ruby_generator.h b/src/compiler/ruby_generator.h
index 4dd38e0..a2ab36d 100644
--- a/src/compiler/ruby_generator.h
+++ b/src/compiler/ruby_generator.h
@@ -34,17 +34,11 @@
 #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H
 #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_H
 
-#include <string>
-
-namespace google {
-namespace protobuf {
-class FileDescriptor;
-}  // namespace protobuf
-}  // namespace google
+#include "src/compiler/config.h"
 
 namespace grpc_ruby_generator {
 
-std::string GetServices(const google::protobuf::FileDescriptor *file);
+grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
 
 }  // namespace grpc_ruby_generator
 
diff --git a/src/compiler/ruby_generator_helpers-inl.h b/src/compiler/ruby_generator_helpers-inl.h
index f3a087b..9da7cab 100644
--- a/src/compiler/ruby_generator_helpers-inl.h
+++ b/src/compiler/ruby_generator_helpers-inl.h
@@ -34,15 +34,13 @@
 #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H
 #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_HELPERS_INL_H
 
-#include <string>
-
-#include <google/protobuf/descriptor.h>
+#include "src/compiler/config.h"
 #include "src/compiler/ruby_generator_string-inl.h"
 
 namespace grpc_ruby_generator {
 
-inline bool ServicesFilename(const google::protobuf::FileDescriptor *file,
-                             std::string *file_name_or_error) {
+inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
+                             grpc::string *file_name_or_error) {
   // Get output file name.
   static const unsigned proto_suffix_length = 6;  // length of ".proto"
   if (file->name().size() > proto_suffix_length &&
@@ -57,8 +55,8 @@
   }
 }
 
-inline std::string MessagesRequireName(
-    const google::protobuf::FileDescriptor *file) {
+inline grpc::string MessagesRequireName(
+    const grpc::protobuf::FileDescriptor *file) {
   return Replace(file->name(), ".proto", "");
 }
 
diff --git a/src/compiler/ruby_generator_map-inl.h b/src/compiler/ruby_generator_map-inl.h
index f902b6d..6b87774 100644
--- a/src/compiler/ruby_generator_map-inl.h
+++ b/src/compiler/ruby_generator_map-inl.h
@@ -34,11 +34,12 @@
 #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H
 #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_MAP_INL_H
 
+#include "src/compiler/config.h"
+
 #include <iostream>
 #include <initializer_list>
 #include <map>
 #include <ostream>  // NOLINT
-#include <string>
 #include <vector>
 
 using std::initializer_list;
@@ -49,18 +50,18 @@
 
 // Converts an initializer list of the form { key0, value0, key1, value1, ... }
 // into a map of key* to value*. Is merely a readability helper for later code.
-inline std::map<std::string, std::string> ListToDict(
-    const initializer_list<std::string> &values) {
+inline std::map<grpc::string, grpc::string> ListToDict(
+    const initializer_list<grpc::string> &values) {
   if (values.size() % 2 != 0) {
     std::cerr << "Not every 'key' has a value in `values`."
               << std::endl;
   }
-  std::map<std::string, std::string> value_map;
+  std::map<grpc::string, grpc::string> value_map;
   auto value_iter = values.begin();
   for (unsigned i = 0; i < values.size() / 2; ++i) {
-    std::string key = *value_iter;
+    grpc::string key = *value_iter;
     ++value_iter;
-    std::string value = *value_iter;
+    grpc::string value = *value_iter;
     value_map[key] = value;
     ++value_iter;
   }
diff --git a/src/compiler/ruby_generator_string-inl.h b/src/compiler/ruby_generator_string-inl.h
index bdd314c..8da3a88 100644
--- a/src/compiler/ruby_generator_string-inl.h
+++ b/src/compiler/ruby_generator_string-inl.h
@@ -34,8 +34,9 @@
 #ifndef GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H
 #define GRPC_INTERNAL_COMPILER_RUBY_GENERATOR_STRING_INL_H
 
+#include "src/compiler/config.h"
+
 #include <algorithm>
-#include <string>
 #include <sstream>
 #include <vector>
 
@@ -45,10 +46,10 @@
 namespace grpc_ruby_generator {
 
 // Split splits a string using char into elems.
-inline std::vector<std::string> &Split(const std::string &s, char delim,
-                                       std::vector<std::string> *elems) {
+inline std::vector<grpc::string> &Split(const grpc::string &s, char delim,
+                                        std::vector<grpc::string> *elems) {
   std::stringstream ss(s);
-  std::string item;
+  grpc::string item;
   while (getline(ss, item, delim)) {
     elems->push_back(item);
   }
@@ -56,17 +57,17 @@
 }
 
 // Split splits a string using char, returning the result in a vector.
-inline std::vector<std::string> Split(const std::string &s, char delim) {
-  std::vector<std::string> elems;
+inline std::vector<grpc::string> Split(const grpc::string &s, char delim) {
+  std::vector<grpc::string> elems;
   Split(s, delim, &elems);
   return elems;
 }
 
 // Replace replaces from with to in s.
-inline std::string Replace(std::string s, const std::string &from,
-                           const std::string &to) {
+inline grpc::string Replace(grpc::string s, const grpc::string &from,
+                            const grpc::string &to) {
   size_t start_pos = s.find(from);
-  if (start_pos == std::string::npos) {
+  if (start_pos == grpc::string::npos) {
     return s;
   }
   s.replace(start_pos, from.length(), to);
@@ -74,10 +75,10 @@
 }
 
 // ReplaceAll replaces all instances of search with replace in s.
-inline std::string ReplaceAll(std::string s, const std::string &search,
-                              const std::string &replace) {
+inline grpc::string ReplaceAll(grpc::string s, const grpc::string &search,
+                               const grpc::string &replace) {
   size_t pos = 0;
-  while ((pos = s.find(search, pos)) != std::string::npos) {
+  while ((pos = s.find(search, pos)) != grpc::string::npos) {
     s.replace(pos, search.length(), replace);
     pos += replace.length();
   }
@@ -85,10 +86,10 @@
 }
 
 // ReplacePrefix replaces from with to in s if search is a prefix of s.
-inline bool ReplacePrefix(std::string *s, const std::string &from,
-                          const std::string &to) {
+inline bool ReplacePrefix(grpc::string *s, const grpc::string &from,
+                          const grpc::string &to) {
   size_t start_pos = s->find(from);
-  if (start_pos == std::string::npos || start_pos != 0) {
+  if (start_pos == grpc::string::npos || start_pos != 0) {
     return false;
   }
   s->replace(start_pos, from.length(), to);
@@ -96,7 +97,7 @@
 }
 
 // CapitalizeFirst capitalizes the first char in a string.
-inline std::string CapitalizeFirst(std::string s) {
+inline grpc::string CapitalizeFirst(grpc::string s) {
   if (s.empty()) {
     return s;
   }
@@ -105,15 +106,15 @@
 }
 
 // RubyTypeOf updates a proto type to the required ruby equivalent.
-inline std::string RubyTypeOf(const std::string &a_type,
-                              const std::string &package) {
-  std::string res(a_type);
+inline grpc::string RubyTypeOf(const grpc::string &a_type,
+                               const grpc::string &package) {
+  grpc::string res(a_type);
   ReplacePrefix(&res, package, "");  // remove the leading package if present
   ReplacePrefix(&res, ".", "");      // remove the leading . (no package)
-  if (res.find('.') == std::string::npos) {
+  if (res.find('.') == grpc::string::npos) {
     return res;
   } else {
-    std::vector<std::string> prefixes_and_type = Split(res, '.');
+    std::vector<grpc::string> prefixes_and_type = Split(res, '.');
     for (unsigned int i = 0; i < prefixes_and_type.size(); ++i) {
       if (i != 0) {
         res += "::";  // switch '.' to the ruby module delim
diff --git a/src/compiler/ruby_plugin.cc b/src/compiler/ruby_plugin.cc
index 4a6e9f7..bd10d46 100644
--- a/src/compiler/ruby_plugin.cc
+++ b/src/compiler/ruby_plugin.cc
@@ -32,43 +32,35 @@
  */
 
 // Generates Ruby gRPC service interface out of Protobuf IDL.
-//
-// This is a Proto2 compiler plugin.  See net/proto2/compiler/proto/plugin.proto
-// and net/proto2/compiler/public/plugin.h for more information on plugins.
 
 #include <memory>
-#include <string>
 
+#include "src/compiler/config.h"
 #include "src/compiler/ruby_generator.h"
 #include "src/compiler/ruby_generator_helpers-inl.h"
-#include <google/protobuf/compiler/code_generator.h>
-#include <google/protobuf/compiler/plugin.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#include <google/protobuf/descriptor.h>
 
-class RubyGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
+class RubyGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
  public:
   RubyGrpcGenerator() {}
   ~RubyGrpcGenerator() {}
 
-  bool Generate(const google::protobuf::FileDescriptor *file,
-                const std::string &parameter,
-                google::protobuf::compiler::GeneratorContext *context,
-                std::string *error) const {
-    std::string code = grpc_ruby_generator::GetServices(file);
+  bool Generate(const grpc::protobuf::FileDescriptor *file,
+                const grpc::string &parameter,
+                grpc::protobuf::compiler::GeneratorContext *context,
+                grpc::string *error) const {
+    grpc::string code = grpc_ruby_generator::GetServices(file);
     if (code.size() == 0) {
       return true;  // don't generate a file if there are no services
     }
 
     // Get output file name.
-    std::string file_name;
+    grpc::string file_name;
     if (!grpc_ruby_generator::ServicesFilename(file, &file_name)) {
       return false;
     }
-    std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
+    std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
         context->Open(file_name));
-    google::protobuf::io::CodedOutputStream coded_out(output.get());
+    grpc::protobuf::io::CodedOutputStream coded_out(output.get());
     coded_out.WriteRaw(code.data(), code.size());
     return true;
   }
@@ -76,5 +68,5 @@
 
 int main(int argc, char *argv[]) {
   RubyGrpcGenerator generator;
-  return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+  return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
 }
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index f565cbf..9da8b33 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -189,7 +189,8 @@
         /* translate host to :authority since :authority may be
            omitted */
         grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
-            channeld->mdctx, channeld->authority_key, op->data.metadata->value);
+            channeld->mdctx, grpc_mdstr_ref(channeld->authority_key),
+            grpc_mdstr_ref(op->data.metadata->value));
         grpc_mdelem_unref(op->data.metadata);
         op->data.metadata = authority;
         /* pass the event up */
diff --git a/src/core/httpcli/parser.c b/src/core/httpcli/parser.c
index f4decda..7b2a620 100644
--- a/src/core/httpcli/parser.c
+++ b/src/core/httpcli/parser.c
@@ -177,6 +177,8 @@
   }
   gpr_log(GPR_ERROR, "should never reach here");
   abort();
+
+  return 0;
 }
 
 void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) {
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 8b019e8..aec6265 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -52,10 +52,11 @@
 
 static gpr_event g_shutdown_iocp;
 static gpr_event g_iocp_done;
+static gpr_atm g_orphans = 0;
 
 static HANDLE g_iocp;
 
-static int do_iocp_work() {
+static void do_iocp_work() {
   BOOL success;
   DWORD bytes = 0;
   DWORD flags = 0;
@@ -71,14 +72,14 @@
                                       gpr_time_to_millis(wait_time));
   if (!success && !overlapped) {
     /* The deadline got attained. */
-    return 0;
+    return;
   }
   GPR_ASSERT(completion_key && overlapped);
   if (overlapped == &g_iocp_custom_overlap) {
     if (completion_key == (ULONG_PTR) &g_iocp_kick_token) {
       /* We were awoken from a kick. */
       gpr_log(GPR_DEBUG, "do_iocp_work - got a kick");
-      return 1;
+      return;
     }
     gpr_log(GPR_ERROR, "Unknown custom completion key.");
     abort();
@@ -97,8 +98,13 @@
   }
   success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
                                    FALSE, &flags);
-  gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s", bytes, flags,
-          success ? "succeeded" : "failed");
+  gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s %s", bytes, flags,
+          success ? "succeeded" : "failed", socket->orphan ? "orphan" : "");
+  if (socket->orphan) {
+    grpc_winsocket_destroy(socket);
+    gpr_atm_full_fetch_add(&g_orphans, -1);
+    return;
+  }
   info->bytes_transfered = bytes;
   info->wsa_error = success ? 0 : WSAGetLastError();
   GPR_ASSERT(overlapped == &info->overlapped);
@@ -113,12 +119,10 @@
   }
   gpr_mu_unlock(&socket->state_mu);
   if (f) f(opaque, 1);
-
-  return 1;
 }
 
 static void iocp_loop(void *p) {
-  while (!gpr_event_get(&g_shutdown_iocp)) {
+  while (gpr_atm_acq_load(&g_orphans) || !gpr_event_get(&g_shutdown_iocp)) {
     grpc_maybe_call_delayed_callbacks(NULL, 1);
     do_iocp_work();
   }
@@ -138,13 +142,19 @@
   gpr_thd_new(&id, iocp_loop, NULL, NULL);
 }
 
-void grpc_iocp_shutdown(void) {
+void grpc_iocp_kick(void) {
   BOOL success;
-  gpr_event_set(&g_shutdown_iocp, (void *)1);
+
   success = PostQueuedCompletionStatus(g_iocp, 0,
                                        (ULONG_PTR) &g_iocp_kick_token,
                                        &g_iocp_custom_overlap);
   GPR_ASSERT(success);
+}
+
+void grpc_iocp_shutdown(void) {
+  BOOL success;
+  gpr_event_set(&g_shutdown_iocp, (void *)1);
+  grpc_iocp_kick();
   gpr_event_wait(&g_iocp_done, gpr_inf_future);
   success = CloseHandle(g_iocp);
   GPR_ASSERT(success);
@@ -166,6 +176,10 @@
   GPR_ASSERT(ret == g_iocp);
 }
 
+void grpc_iocp_socket_orphan(grpc_winsocket *socket) {
+  gpr_atm_full_fetch_add(&g_orphans, 1);
+}
+
 static void socket_notify_on_iocp(grpc_winsocket *socket,
                                   void(*cb)(void *, int), void *opaque,
                                   grpc_winsocket_callback_info *info) {
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
index 3313319..fa3f5ee 100644
--- a/src/core/iomgr/iocp_windows.h
+++ b/src/core/iomgr/iocp_windows.h
@@ -42,6 +42,7 @@
 void grpc_iocp_init(void);
 void grpc_iocp_shutdown(void);
 void grpc_iocp_add_socket(grpc_winsocket *);
+void grpc_iocp_socket_orphan(grpc_winsocket *);
 
 void grpc_socket_notify_on_write(grpc_winsocket *, void(*cb)(void *, int success),
                                  void *opaque);
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
index 058685b..d0e6706 100644
--- a/src/core/iomgr/iomgr.c
+++ b/src/core/iomgr/iomgr.c
@@ -117,7 +117,16 @@
       gpr_mu_lock(&g_mu);
     }
     if (g_refs) {
-      if (gpr_cv_wait(&g_rcv, &g_mu, shutdown_deadline) && g_cbs_head == NULL) {
+      int timeout = 0;
+      gpr_timespec short_deadline = gpr_time_add(gpr_now(),
+                                                 gpr_time_from_millis(100));
+      while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
+        if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
+          timeout = 1;
+          break;
+        }
+      }
+      if (timeout) {
         gpr_log(GPR_DEBUG,
                 "Failed to free %d iomgr objects before shutdown deadline: "
                 "memory leaks are likely",
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
index 99f38b0..22dad41 100644
--- a/src/core/iomgr/socket_windows.c
+++ b/src/core/iomgr/socket_windows.c
@@ -55,7 +55,7 @@
   return r;
 }
 
-void shutdown_op(grpc_winsocket_callback_info *info) {
+static void shutdown_op(grpc_winsocket_callback_info *info) {
   if (!info->cb) return;
   grpc_iomgr_add_delayed_callback(info->cb, info->opaque, 0);
 }
@@ -68,8 +68,13 @@
 
 void grpc_winsocket_orphan(grpc_winsocket *socket) {
   gpr_log(GPR_DEBUG, "grpc_winsocket_orphan");
+  grpc_iocp_socket_orphan(socket);
+  socket->orphan = 1;
   grpc_iomgr_unref();
   closesocket(socket->socket);
+}
+
+void grpc_winsocket_destroy(grpc_winsocket *socket) {
   gpr_mu_destroy(&socket->state_mu);
   gpr_free(socket);
 }
diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h
index d4776ab..cbae916 100644
--- a/src/core/iomgr/socket_windows.h
+++ b/src/core/iomgr/socket_windows.h
@@ -57,12 +57,13 @@
 typedef struct grpc_winsocket {
   SOCKET socket;
 
-  int added_to_iocp;
-
   grpc_winsocket_callback_info write_info;
   grpc_winsocket_callback_info read_info;
 
   gpr_mu state_mu;
+
+  int added_to_iocp;
+  int orphan;
 } grpc_winsocket;
 
 /* Create a wrapped windows handle.
@@ -71,5 +72,6 @@
 
 void grpc_winsocket_shutdown(grpc_winsocket *socket);
 void grpc_winsocket_orphan(grpc_winsocket *socket);
+void grpc_winsocket_destroy(grpc_winsocket *socket);
 
 #endif  /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
index 68ee85c..66bb3ef 100644
--- a/src/core/iomgr/tcp_server.h
+++ b/src/core/iomgr/tcp_server.h
@@ -71,6 +71,8 @@
    up when grpc_tcp_server_destroy is called. */
 int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index);
 
-void grpc_tcp_server_destroy(grpc_tcp_server *server);
+void grpc_tcp_server_destroy(grpc_tcp_server *server,
+                             void (*shutdown_done)(void *shutdown_done_arg),
+                             void *shutdown_done_arg);
 
-#endif  /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 90b7eb4..895f85f 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -102,12 +102,18 @@
   gpr_cv cv;
 
   /* active port count: how many ports are actually still listening */
-  int active_ports;
+  size_t active_ports;
+  /* destroyed port count: how many ports are completely destroyed */
+  size_t destroyed_ports;
 
   /* all listening ports */
   server_port *ports;
   size_t nports;
   size_t port_capacity;
+
+  /* shutdown callback */
+  void (*shutdown_complete)(void *);
+  void *shutdown_complete_arg;
 };
 
 grpc_tcp_server *grpc_tcp_server_create(void) {
@@ -115,6 +121,7 @@
   gpr_mu_init(&s->mu);
   gpr_cv_init(&s->cv);
   s->active_ports = 0;
+  s->destroyed_ports = 0;
   s->cb = NULL;
   s->cb_arg = NULL;
   s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
@@ -123,29 +130,64 @@
   return s;
 }
 
-void grpc_tcp_server_destroy(grpc_tcp_server *s) {
+static void finish_shutdown(grpc_tcp_server *s) {
+  s->shutdown_complete(s->shutdown_complete_arg);
+
+  gpr_mu_destroy(&s->mu);
+  gpr_cv_destroy(&s->cv);
+
+  gpr_free(s->ports);
+  gpr_free(s);
+}
+
+static void destroyed_port(void *server, int success) {
+  grpc_tcp_server *s = server;
+  gpr_mu_lock(&s->mu);
+  s->destroyed_ports++;
+  if (s->destroyed_ports == s->nports) {
+    gpr_mu_unlock(&s->mu);
+    finish_shutdown(s);
+  } else {
+    gpr_mu_unlock(&s->mu);
+  }
+}
+
+static void dont_care_about_shutdown_completion(void *ignored) {}
+
+void grpc_tcp_server_destroy(
+    grpc_tcp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg),
+    void *shutdown_complete_arg) {
   size_t i;
   gpr_mu_lock(&s->mu);
+
+  s->shutdown_complete = shutdown_complete
+                             ? shutdown_complete
+                             : dont_care_about_shutdown_completion;
+  s->shutdown_complete_arg = shutdown_complete_arg;
+
   /* shutdown all fd's */
   for (i = 0; i < s->nports; i++) {
     grpc_fd_shutdown(s->ports[i].emfd);
   }
   /* wait while that happens */
+  /* TODO(ctiller): make this asynchronous also */
   while (s->active_ports) {
     gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
   }
   gpr_mu_unlock(&s->mu);
 
   /* delete ALL the things */
-  for (i = 0; i < s->nports; i++) {
-    server_port *sp = &s->ports[i];
-    if (sp->addr.sockaddr.sa_family == AF_UNIX) {
-      unlink_if_unix_domain_socket(&sp->addr.un);
+  if (s->nports) {
+    for (i = 0; i < s->nports; i++) {
+      server_port *sp = &s->ports[i];
+      if (sp->addr.sockaddr.sa_family == AF_UNIX) {
+        unlink_if_unix_domain_socket(&sp->addr.un);
+      }
+      grpc_fd_orphan(sp->emfd, destroyed_port, s);
     }
-    grpc_fd_orphan(sp->emfd, NULL, NULL);
+  } else {
+    finish_shutdown(s);
   }
-  gpr_free(s->ports);
-  gpr_free(s);
 }
 
 /* get max listen queue size on linux */
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index 0c3ab1d..a43d567 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -92,7 +92,9 @@
   return s;
 }
 
-void grpc_tcp_server_destroy(grpc_tcp_server *s) {
+void grpc_tcp_server_destroy(grpc_tcp_server *s,
+                             void (*shutdown_done)(void *shutdown_done_arg),
+                             void *shutdown_done_arg) {
   size_t i;
   gpr_mu_lock(&s->mu);
   /* shutdown all fd's */
@@ -112,11 +114,15 @@
   }
   gpr_free(s->ports);
   gpr_free(s);
+
+  if (shutdown_done) {
+    shutdown_done(shutdown_done_arg);
+  }
 }
 
 /* Prepare a recently-created socket for listening. */
-static int prepare_socket(SOCKET sock,
-                          const struct sockaddr *addr, int addr_len) {
+static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
+                          int addr_len) {
   struct sockaddr_storage sockname_temp;
   socklen_t sockname_len;
 
@@ -147,15 +153,15 @@
   }
 
   sockname_len = sizeof(sockname_temp);
-  if (getsockname(sock, (struct sockaddr *) &sockname_temp, &sockname_len)
-        == SOCKET_ERROR) {
+  if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
+      SOCKET_ERROR) {
     char *utf8_message = gpr_format_message(WSAGetLastError());
     gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
     gpr_free(utf8_message);
     goto error;
   }
 
-  return grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp);
+  return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
 
 error:
   if (sock != INVALID_SOCKET) closesocket(sock);
@@ -221,8 +227,7 @@
     DWORD transfered_bytes = 0;
     DWORD flags;
     BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
-                                              &transfered_bytes, FALSE,
-                                              &flags);
+                                              &transfered_bytes, FALSE, &flags);
     if (!wsa_success) {
       char *utf8_message = gpr_format_message(WSAGetLastError());
       gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
@@ -257,9 +262,9 @@
 
   if (sock == INVALID_SOCKET) return -1;
 
-  status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
-                    &guid, sizeof(guid), &AcceptEx, sizeof(AcceptEx),
-                    &ioctl_num_bytes, NULL, NULL);
+  status =
+      WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+               &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
 
   if (status != 0) {
     char *utf8_message = gpr_format_message(WSAGetLastError());
@@ -307,9 +312,8 @@
     for (i = 0; i < s->nports; i++) {
       sockname_len = sizeof(sockname_temp);
       if (0 == getsockname(s->ports[i].socket->socket,
-                           (struct sockaddr *) &sockname_temp,
-                           &sockname_len)) {
-        port = grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp);
+                           (struct sockaddr *)&sockname_temp, &sockname_len)) {
+        port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
         if (port > 0) {
           allocated_addr = malloc(addr_len);
           memcpy(allocated_addr, addr, addr_len);
@@ -330,7 +334,7 @@
   if (grpc_sockaddr_is_wildcard(addr, &port)) {
     grpc_sockaddr_make_wildcard6(port, &wildcard);
 
-    addr = (struct sockaddr *) &wildcard;
+    addr = (struct sockaddr *)&wildcard;
     addr_len = sizeof(wildcard);
   }
 
@@ -369,4 +373,4 @@
   gpr_mu_unlock(&s->mu);
 }
 
-#endif  /* GPR_WINSOCK_SOCKET */
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index c155b80..0812727 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -85,10 +85,10 @@
   if (status == GRPC_SECURITY_OK) {
     gpr_mu_lock(&state->mu);
     if (!state->is_shutdown) {
-      grpc_create_chttp2_transport(
-          setup_transport, state->server,
-          grpc_server_get_channel_args(state->server),
-          secure_endpoint, NULL, 0, grpc_mdctx_create(), 0);
+      grpc_create_chttp2_transport(setup_transport, state->server,
+                                   grpc_server_get_channel_args(state->server),
+                                   secure_endpoint, NULL, 0,
+                                   grpc_mdctx_create(), 0);
     } else {
       /* We need to consume this here, because the server may already have gone
        * away. */
@@ -104,7 +104,8 @@
 static void on_accept(void *statep, grpc_endpoint *tcp) {
   grpc_server_secure_state *state = statep;
   state_ref(state);
-  grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done, state);
+  grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done,
+                              state);
 }
 
 /* Server callback: start listening on our ports */
@@ -120,12 +121,14 @@
   grpc_server_secure_state *state = statep;
   gpr_mu_lock(&state->mu);
   state->is_shutdown = 1;
-  grpc_tcp_server_destroy(state->tcp);
+  grpc_tcp_server_destroy(state->tcp, grpc_server_listener_destroy_done,
+                          server);
   gpr_mu_unlock(&state->mu);
   state_unref(state);
 }
 
-int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) {
+int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
+                                      grpc_server_credentials *creds) {
   grpc_resolved_addresses *resolved = NULL;
   grpc_tcp_server *tcp = NULL;
   grpc_server_secure_state *state = NULL;
@@ -213,7 +216,7 @@
     grpc_resolved_addresses_destroy(resolved);
   }
   if (tcp) {
-    grpc_tcp_server_destroy(tcp);
+    grpc_tcp_server_destroy(tcp, NULL, NULL);
   }
   if (state) {
     gpr_free(state);
diff --git a/src/php/tests/unit_tests/CompletionQueueTest.php b/src/core/support/thd.c
old mode 100755
new mode 100644
similarity index 66%
copy from src/php/tests/unit_tests/CompletionQueueTest.php
copy to src/core/support/thd.c
index 76ee61d..ec308f3
--- a/src/php/tests/unit_tests/CompletionQueueTest.php
+++ b/src/core/support/thd.c
@@ -1,4 +1,3 @@
-<?php
 /*
  *
  * Copyright 2015, Google Inc.
@@ -31,16 +30,37 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-class CompletionQueueTest extends PHPUnit_Framework_TestCase{
-  public function testNextReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->next(Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
 
-  public function testPluckReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->pluck(0, Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
+/* Posix implementation for gpr threads. */
+
+#include <memory.h>
+
+#include <grpc/support/thd.h>
+
+enum {
+  GPR_THD_JOINABLE = 1
+};
+
+gpr_thd_options gpr_thd_options_default(void) {
+  gpr_thd_options options;
+  memset(&options, 0, sizeof(options));
+  return options;
+}
+
+void gpr_thd_options_set_detached(gpr_thd_options *options) {
+  options->flags &= ~GPR_THD_JOINABLE;
+}
+
+void gpr_thd_options_set_joinable(gpr_thd_options *options) {
+  options->flags |= GPR_THD_JOINABLE;
+}
+
+int gpr_thd_options_is_detached(const gpr_thd_options *options) {
+  if (!options) return 1;
+  return (options->flags & GPR_THD_JOINABLE) == 0;
+}
+
+int gpr_thd_options_is_joinable(const gpr_thd_options *options) {
+  if (!options) return 0;
+  return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
 }
diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c
index f50ea58..fa4eb50 100644
--- a/src/core/support/thd_posix.c
+++ b/src/core/support/thd_posix.c
@@ -68,7 +68,11 @@
   a->arg = arg;
 
   GPR_ASSERT(pthread_attr_init(&attr) == 0);
-  GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+  if (gpr_thd_options_is_detached(options)) {
+    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+  } else {
+    GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0);
+  }
   thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
   GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
   if (!thread_started) {
@@ -78,14 +82,12 @@
   return thread_started;
 }
 
-gpr_thd_options gpr_thd_options_default(void) {
-  gpr_thd_options options;
-  memset(&options, 0, sizeof(options));
-  return options;
-}
-
 gpr_thd_id gpr_thd_currentid(void) {
   return (gpr_thd_id)pthread_self();
 }
 
+void gpr_thd_join(gpr_thd_id t) {
+  pthread_join((pthread_t)t, NULL);
+}
+
 #endif /* GPR_POSIX_SYNC */
diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c
index 347cad5..3cc7982 100644
--- a/src/core/support/thd_win32.c
+++ b/src/core/support/thd_win32.c
@@ -31,7 +31,7 @@
  *
  */
 
-/* Posix implementation for gpr threads. */
+/* Windows implementation for gpr threads. */
 
 #include <grpc/support/port_platform.h>
 
@@ -40,47 +40,81 @@
 #include <windows.h>
 #include <string.h>
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 
-struct thd_arg {
+#if defined(_MSC_VER)
+#define thread_local __declspec(thread)
+#elif defined(__GNUC__)
+#define thread_local __thread
+#else
+#error "Unknown compiler - please file a bug report"
+#endif
+
+struct thd_info {
   void (*body)(void *arg); /* body of a thread */
   void *arg;               /* argument to a thread */
+  HANDLE join_event;       /* if joinable, the join event */
+  int joinable;            /* true if not detached */
 };
 
+static thread_local struct thd_info *g_thd_info;
+
+/* Destroys a thread info */
+static void destroy_thread(struct thd_info *t) {
+  if (t->joinable) CloseHandle(t->join_event);
+  gpr_free(t);
+}
+
 /* Body of every thread started via gpr_thd_new. */
 static DWORD WINAPI thread_body(void *v) {
-  struct thd_arg a = *(struct thd_arg *)v;
-  gpr_free(v);
-  (*a.body)(a.arg);
+  g_thd_info = (struct thd_info *)v;
+  g_thd_info->body(g_thd_info->arg);
+  if (g_thd_info->joinable) {
+    BOOL ret = SetEvent(g_thd_info->join_event);
+    GPR_ASSERT(ret);
+  } else {
+    destroy_thread(g_thd_info);
+  }
   return 0;
 }
 
 int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
                 const gpr_thd_options *options) {
   HANDLE handle;
-  DWORD thread_id;
-  struct thd_arg *a = gpr_malloc(sizeof(*a));
-  a->body = thd_body;
-  a->arg = arg;
+  struct thd_info *info = gpr_malloc(sizeof(*info));
+  info->body = thd_body;
+  info->arg = arg;
   *t = 0;
-  handle = CreateThread(NULL, 64 * 1024, thread_body, a, 0, &thread_id);
-  if (handle == NULL) {
-    gpr_free(a);
+  if (gpr_thd_options_is_joinable(options)) {
+    info->joinable = 1;
+    info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (info->join_event == NULL) {
+      gpr_free(info);
+      return 0;
+    }
   } else {
-    CloseHandle(handle); /* threads are "detached" */
+    info->joinable = 0;
   }
-  *t = (gpr_thd_id)thread_id;
+  handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
+  if (handle == NULL) {
+    destroy_thread(info);
+  } else {
+    *t = (gpr_thd_id)info;
+    CloseHandle(handle);
+  }
   return handle != NULL;
 }
 
-gpr_thd_options gpr_thd_options_default(void) {
-  gpr_thd_options options;
-  memset(&options, 0, sizeof(options));
-  return options;
+gpr_thd_id gpr_thd_currentid(void) {
+  return (gpr_thd_id)g_thd_info;
 }
 
-gpr_thd_id gpr_thd_currentid(void) {
-  return (gpr_thd_id)GetCurrentThreadId();
+void gpr_thd_join(gpr_thd_id t) {
+  struct thd_info *info = (struct thd_info *)t;
+  DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
+  GPR_ASSERT(ret == WAIT_OBJECT_0);
+  destroy_thread(info);
 }
 
 #endif /* GPR_WIN32 */
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index cfce943..dba6305 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -1006,6 +1006,8 @@
   const grpc_op *op;
   grpc_ioreq *req;
 
+  GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
+
   if (nops == 0) {
     grpc_cq_begin_op(call->cq, call, GRPC_OP_COMPLETE);
     grpc_cq_end_op_complete(call->cq, tag, call, do_nothing, NULL, GRPC_OP_OK);
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index cb81cb5..06434f8 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -119,4 +119,13 @@
 /* Given the top call_element, get the call object. */
 grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element);
 
+extern int grpc_trace_batch;
+
+void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
+                         grpc_call *call, const grpc_op *ops, size_t nops,
+                         void *tag);
+
+#define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \
+  if (grpc_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag)
+
 #endif  /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */
diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c
new file mode 100644
index 0000000..a33583a
--- /dev/null
+++ b/src/core/surface/call_log_batch.c
@@ -0,0 +1,121 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "src/core/surface/call.h"
+
+#include "src/core/support/string.h"
+#include <grpc/support/alloc.h>
+
+int grpc_trace_batch = 0;
+
+static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) {
+  size_t i;
+  for(i = 0; i < count; i++) {
+    gpr_strvec_add(b, gpr_strdup("\nkey="));
+    gpr_strvec_add(b, gpr_strdup(md[i].key));
+
+    gpr_strvec_add(b, gpr_strdup(" value="));
+    gpr_strvec_add(b, gpr_hexdump(md[i].value, md[i].value_length,
+                                  GPR_HEXDUMP_PLAINTEXT));
+  }
+}
+
+char *grpc_op_string(const grpc_op *op) {
+  char *tmp;
+  char *out;
+
+  gpr_strvec b;
+  gpr_strvec_init(&b);
+
+  switch (op->op) {
+    case GRPC_OP_SEND_INITIAL_METADATA:
+      gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA"));
+      add_metadata(&b, op->data.send_initial_metadata.metadata,
+                   op->data.send_initial_metadata.count);
+      break;
+    case GRPC_OP_SEND_MESSAGE:
+      gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+      gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT"));
+      break;
+    case GRPC_OP_SEND_STATUS_FROM_SERVER:
+      gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s",
+                   op->data.send_status_from_server.status,
+                   op->data.send_status_from_server.status_details);
+      gpr_strvec_add(&b, tmp);
+      add_metadata(&b, op->data.send_status_from_server.trailing_metadata,
+                   op->data.send_status_from_server.trailing_metadata_count);
+      break;
+    case GRPC_OP_RECV_INITIAL_METADATA:
+      gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p",
+                   op->data.recv_initial_metadata);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_RECV_MESSAGE:
+      gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_RECV_STATUS_ON_CLIENT:
+      gpr_asprintf(&tmp,
+                   "RECV_STATUS_ON_CLIENT metadata=%p status=%p details=%p",
+                   op->data.recv_status_on_client.trailing_metadata,
+                   op->data.recv_status_on_client.status,
+                   op->data.recv_status_on_client.status_details);
+      gpr_strvec_add(&b, tmp);
+      break;
+    case GRPC_OP_RECV_CLOSE_ON_SERVER:
+      gpr_asprintf(&tmp, "RECV_CLOSE_ON_SERVER cancelled=%p",
+                   op->data.recv_close_on_server.cancelled);
+      gpr_strvec_add(&b, tmp);
+  }
+  out = gpr_strvec_flatten(&b, NULL);
+  gpr_strvec_destroy(&b);
+
+  return out;
+}
+
+void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
+                         grpc_call *call, const grpc_op *ops, size_t nops,
+                         void *tag) {
+  char *tmp;
+  size_t i;
+  gpr_log(file, line, severity,
+          "grpc_call_start_batch(%p, %p, %d, 0x%x)", call, ops, nops, tag);
+  for(i = 0; i < nops; i++) {
+    tmp = grpc_op_string(&ops[i]);
+    gpr_log(file, line, severity, "ops[%d]: %s", i, tmp);
+    gpr_free(tmp);
+  }
+}
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index 6a1d83c..24f4a05 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -432,3 +432,11 @@
 grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
   return &cc->pollset;
 }
+
+void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc) {
+  gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+  grpc_pollset_kick(&cc->pollset);
+  grpc_pollset_work(&cc->pollset,
+                    gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
+  gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+}
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index 3054264..3a7cc99 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -114,4 +114,6 @@
 
 grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */
+void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc);
+
+#endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index e48c420..d4f0eb4 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -36,6 +36,7 @@
 #include "src/core/debug/trace.h"
 #include "src/core/statistics/census_interface.h"
 #include "src/core/channel/channel_stack.h"
+#include "src/core/surface/call.h"
 #include "src/core/surface/init.h"
 #include "src/core/surface/surface_trace.h"
 #include "src/core/transport/chttp2_transport.h"
@@ -57,6 +58,7 @@
     grpc_register_tracer("channel", &grpc_trace_channel);
     grpc_register_tracer("surface", &grpc_surface_trace);
     grpc_register_tracer("http", &grpc_http_trace);
+    grpc_register_tracer("batch", &grpc_trace_batch);
     grpc_security_pre_init();
     grpc_tracer_init("GRPC_TRACE");
     grpc_iomgr_init();
@@ -82,4 +84,3 @@
   gpr_mu_unlock(&g_init_mu);
   return r;
 }
-
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index 424734c..17cba9a 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -137,6 +137,7 @@
   size_t cq_count;
 
   gpr_mu mu;
+  gpr_cv cv;
 
   registered_method *registered_methods;
   requested_call_array requested_calls;
@@ -149,6 +150,7 @@
   channel_data root_channel_data;
 
   listener *listeners;
+  int listeners_destroyed;
   gpr_refcount internal_refcount;
 };
 
@@ -263,6 +265,7 @@
   if (gpr_unref(&server->internal_refcount)) {
     grpc_channel_args_destroy(server->channel_args);
     gpr_mu_destroy(&server->mu);
+    gpr_cv_destroy(&server->cv);
     gpr_free(server->channel_filters);
     requested_call_array_destroy(&server->requested_calls);
     while ((rm = server->registered_methods) != NULL) {
@@ -589,9 +592,8 @@
 }
 
 static const grpc_channel_filter server_surface_filter = {
-    call_op,           channel_op,           sizeof(call_data),
-    init_call_elem,    destroy_call_elem,    sizeof(channel_data),
-    init_channel_elem, destroy_channel_elem, "server",
+    call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem,
+    sizeof(channel_data), init_channel_elem, destroy_channel_elem, "server",
 };
 
 static void addcq(grpc_server *server, grpc_completion_queue *cq) {
@@ -620,6 +622,7 @@
   if (cq) addcq(server, cq);
 
   gpr_mu_init(&server->mu);
+  gpr_cv_init(&server->cv);
 
   server->unregistered_cq = cq;
   /* decremented by grpc_server_destroy */
@@ -733,7 +736,8 @@
   channel = grpc_channel_create_from_filters(filters, num_filters,
                                              s->channel_args, mdctx, 0);
   chand = (channel_data *)grpc_channel_stack_element(
-              grpc_channel_get_channel_stack(channel), 0)->channel_data;
+              grpc_channel_get_channel_stack(channel), 0)
+              ->channel_data;
   chand->server = s;
   server_ref(s);
   chand->channel = channel;
@@ -754,7 +758,7 @@
       method = grpc_mdstr_from_string(mdctx, rm->method);
       hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
       for (probes = 0; chand->registered_methods[(hash + probes) % slots]
-                               .server_registered_method != NULL;
+                           .server_registered_method != NULL;
            probes++)
         ;
       if (probes > max_probes) max_probes = probes;
@@ -781,6 +785,15 @@
   return result;
 }
 
+static int num_listeners(grpc_server *server) {
+  listener *l;
+  int n = 0;
+  for (l = server->listeners; l; l = l->next) {
+    n++;
+  }
+  return n;
+}
+
 static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
                               void *shutdown_tag) {
   listener *l;
@@ -878,11 +891,6 @@
   for (l = server->listeners; l; l = l->next) {
     l->destroy(server, l->arg);
   }
-  while (server->listeners) {
-    l = server->listeners;
-    server->listeners = l->next;
-    gpr_free(l);
-  }
 }
 
 void grpc_server_shutdown(grpc_server *server) {
@@ -893,8 +901,18 @@
   shutdown_internal(server, 1, tag);
 }
 
+void grpc_server_listener_destroy_done(void *s) {
+  grpc_server *server = s;
+  gpr_mu_lock(&server->mu);
+  server->listeners_destroyed++;
+  gpr_cv_signal(&server->cv);
+  gpr_mu_unlock(&server->mu);
+}
+
 void grpc_server_destroy(grpc_server *server) {
   channel_data *c;
+  listener *l;
+  size_t i;
   gpr_mu_lock(&server->mu);
   if (!server->shutdown) {
     gpr_mu_unlock(&server->mu);
@@ -902,6 +920,23 @@
     gpr_mu_lock(&server->mu);
   }
 
+  while (server->listeners_destroyed != num_listeners(server)) {
+    for (i = 0; i < server->cq_count; i++) {
+      gpr_mu_unlock(&server->mu);
+      grpc_cq_hack_spin_pollset(server->cqs[i]);
+      gpr_mu_lock(&server->mu);
+    }
+
+    gpr_cv_wait(&server->cv, &server->mu,
+                gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
+  }
+
+  while (server->listeners) {
+    l = server->listeners;
+    server->listeners = l->next;
+    gpr_free(l);
+  }
+
   for (c = server->root_channel_data.next; c != &server->root_channel_data;
        c = c->next) {
     shutdown_channel(c);
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
index e33f69b..2cfa38f 100644
--- a/src/core/surface/server.h
+++ b/src/core/surface/server.h
@@ -48,9 +48,12 @@
    and when it shuts down, it will call destroy */
 void grpc_server_add_listener(grpc_server *server, void *listener,
                               void (*start)(grpc_server *server, void *arg,
-                                            grpc_pollset **pollsets, size_t npollsets),
+                                            grpc_pollset **pollsets,
+                                            size_t npollsets),
                               void (*destroy)(grpc_server *server, void *arg));
 
+void grpc_server_listener_destroy_done(void *server);
+
 /* Setup a transport - creates a channel stack, binds the transport to the
    server */
 grpc_transport_setup_result grpc_server_setup_transport(
@@ -60,4 +63,4 @@
 
 const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
 
-#endif  /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */
+#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 27434b3..f3b9219 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -66,7 +66,8 @@
 }
 
 /* Server callback: start listening on our ports */
-static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets, size_t pollset_count) {
+static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets,
+                  size_t pollset_count) {
   grpc_tcp_server *tcp = tcpp;
   grpc_tcp_server_start(tcp, pollsets, pollset_count, new_transport, server);
 }
@@ -75,7 +76,7 @@
    callbacks) */
 static void destroy(grpc_server *server, void *tcpp) {
   grpc_tcp_server *tcp = tcpp;
-  grpc_tcp_server_destroy(tcp);
+  grpc_tcp_server_destroy(tcp, grpc_server_listener_destroy_done, server);
 }
 
 int grpc_server_add_http2_port(grpc_server *server, const char *addr) {
@@ -131,7 +132,7 @@
     grpc_resolved_addresses_destroy(resolved);
   }
   if (tcp) {
-    grpc_tcp_server_destroy(tcp);
+    grpc_tcp_server_destroy(tcp, NULL, NULL);
   }
   return 0;
 }
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 2b15b2a..4c0394d 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -1710,6 +1710,8 @@
 
   gpr_log(GPR_ERROR, "should never reach here");
   abort();
+
+  return 0;
 }
 
 /* tcp read callback */
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 1c15716..066cc26 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -97,7 +97,7 @@
 static void internal_string_unref(internal_string *s);
 static void discard_metadata(grpc_mdctx *ctx);
 static void gc_mdtab(grpc_mdctx *ctx);
-static void metadata_context_destroy(grpc_mdctx *ctx);
+static void metadata_context_destroy_locked(grpc_mdctx *ctx);
 
 static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }
 
@@ -122,8 +122,7 @@
       discard_metadata(ctx);
     }
     if (ctx->strtab_count == 0) {
-      gpr_mu_unlock(&ctx->mu);
-      metadata_context_destroy(ctx);
+      metadata_context_destroy_locked(ctx);
       return;
     }
   }
@@ -185,8 +184,7 @@
   }
 }
 
-static void metadata_context_destroy(grpc_mdctx *ctx) {
-  gpr_mu_lock(&ctx->mu);
+static void metadata_context_destroy_locked(grpc_mdctx *ctx) {
   GPR_ASSERT(ctx->strtab_count == 0);
   GPR_ASSERT(ctx->mdtab_count == 0);
   GPR_ASSERT(ctx->mdtab_free == 0);
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 33645ca..018ddc4 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -567,7 +567,8 @@
     EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
     if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
       gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
-      result = TSI_INTERNAL_ERROR;
+      EC_KEY_free(ecdh);
+      return TSI_INTERNAL_ERROR;
     }
     SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
     EC_KEY_free(ecdh);
@@ -604,6 +605,7 @@
   unsigned char* current;
   *protocol_name_list = NULL;
   *protocol_name_list_length = 0;
+  if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
   for (i = 0; i < num_alpn_protocols; i++) {
     if (alpn_protocols_lengths[i] == 0) {
       gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
diff --git a/src/php/ext/grpc/event.h b/src/cpp/client/generic_stub.cc
old mode 100755
new mode 100644
similarity index 76%
copy from src/php/ext/grpc/event.h
copy to src/cpp/client/generic_stub.cc
index ef5846a..3bf7bdf
--- a/src/php/ext/grpc/event.h
+++ b/src/cpp/client/generic_stub.cc
@@ -31,21 +31,21 @@
  *
  */
 
-#ifndef NET_GRPC_PHP_GRPC_EVENT_H_
-#define NET_GRPC_PHP_GRPC_EVENT_H_
+#include <grpc++/generic_stub.h>
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <grpc++/impl/rpc_method.h>
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
+namespace grpc {
 
-#include "grpc/grpc.h"
+// begin a call to a named method
+std::unique_ptr<GenericClientAsyncReaderWriter> GenericStub::Call(
+    ClientContext* context, const grpc::string& method,
+    CompletionQueue* cq, void* tag) {
+  return std::unique_ptr<GenericClientAsyncReaderWriter>(
+      new GenericClientAsyncReaderWriter(
+          channel_.get(), cq, RpcMethod(method.c_str()), context, tag));
+}
 
-/* Create a new Event object that wraps an existing grpc_event struct */
-zval *grpc_php_convert_event(grpc_event *event);
 
-#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */
+} // namespace grpc
+
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index f3ca430..8945b03 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -31,8 +31,6 @@
  *
  */
 
-#include <string>
-
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index e3c6637..0a73b2c 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -31,40 +31,23 @@
  *
  */
 
-#include <string>
-
-#include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
 
 #include <grpc++/channel_arguments.h>
-#include <grpc++/config.h>
-#include <grpc++/credentials.h>
 #include "src/cpp/client/channel.h"
+#include "src/cpp/client/secure_credentials.h"
 
 namespace grpc {
 
-class SecureCredentials GRPC_FINAL : public Credentials {
- public:
-  explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {}
-  ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); }
-  grpc_credentials* GetRawCreds() { return c_creds_; }
-
-  std::shared_ptr<grpc::ChannelInterface> CreateChannel(
-      const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE {
-    grpc_channel_args channel_args;
-    args.SetChannelArgs(&channel_args);
-    return std::shared_ptr<ChannelInterface>(new Channel(
-        args.GetSslTargetNameOverride().empty()
-            ? target
-            : args.GetSslTargetNameOverride(),
-        grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)));
-  }
-
-  SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
-
- private:
-  grpc_credentials* const c_creds_;
-};
+std::shared_ptr<grpc::ChannelInterface> SecureCredentials::CreateChannel(
+    const string& target, const grpc::ChannelArguments& args) {
+  grpc_channel_args channel_args;
+  args.SetChannelArgs(&channel_args);
+  return std::shared_ptr<ChannelInterface>(new Channel(
+      args.GetSslTargetNameOverride().empty() ? target
+                                              : args.GetSslTargetNameOverride(),
+      grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)));
+}
 
 namespace {
 std::unique_ptr<Credentials> WrapCredentials(grpc_credentials* creds) {
diff --git a/src/php/tests/unit_tests/CompletionQueueTest.php b/src/cpp/client/secure_credentials.h
old mode 100755
new mode 100644
similarity index 64%
copy from src/php/tests/unit_tests/CompletionQueueTest.php
copy to src/cpp/client/secure_credentials.h
index 76ee61d..77d5758
--- a/src/php/tests/unit_tests/CompletionQueueTest.php
+++ b/src/cpp/client/secure_credentials.h
@@ -1,4 +1,3 @@
-<?php
 /*
  *
  * Copyright 2015, Google Inc.
@@ -31,16 +30,32 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-class CompletionQueueTest extends PHPUnit_Framework_TestCase{
-  public function testNextReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->next(Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
 
-  public function testPluckReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->pluck(0, Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
-}
+#ifndef GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+#define GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+
+#include <grpc/grpc_security.h>
+
+#include <grpc++/config.h>
+#include <grpc++/credentials.h>
+
+namespace grpc {
+
+class SecureCredentials GRPC_FINAL : public Credentials {
+ public:
+  explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {}
+  ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); }
+  grpc_credentials* GetRawCreds() { return c_creds_; }
+
+  std::shared_ptr<grpc::ChannelInterface> CreateChannel(
+      const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE;
+  SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
+
+ private:
+  grpc_credentials* const c_creds_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+
diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc
index 5c26a1a..e75e77e 100644
--- a/src/cpp/common/call.cc
+++ b/src/cpp/common/call.cc
@@ -60,7 +60,8 @@
       status_code_(GRPC_STATUS_OK),
       status_details_(nullptr),
       status_details_capacity_(0),
-      send_status_(nullptr),
+      send_status_available_(false),
+      send_status_code_(GRPC_STATUS_OK),
       trailing_metadata_count_(0),
       trailing_metadata_(nullptr),
       cancelled_buf_(0),
@@ -104,7 +105,9 @@
 
   status_code_ = GRPC_STATUS_OK;
 
-  send_status_ = nullptr;
+  send_status_available_ = false;
+  send_status_code_ = GRPC_STATUS_OK;
+  send_status_details_.clear();
   trailing_metadata_count_ = 0;
   trailing_metadata_ = nullptr;
 
@@ -148,7 +151,7 @@
     // TODO(yangg) handle duplicates?
     metadata->insert(std::pair<grpc::string, grpc::string>(
         arr->metadata[i].key,
-        {arr->metadata[i].value, arr->metadata[i].value_length}));
+        grpc::string(arr->metadata[i].value, arr->metadata[i].value_length)));
   }
   grpc_metadata_array_destroy(arr);
   grpc_metadata_array_init(arr);
@@ -186,6 +189,7 @@
 
 void CallOpBuffer::AddRecvMessage(ByteBuffer* message) {
   recv_message_buffer_ = message;
+  recv_message_buffer_->Clear();
 }
 
 void CallOpBuffer::AddClientSendClose() { client_send_close_ = true; }
@@ -207,7 +211,9 @@
   } else {
     trailing_metadata_count_ = 0;
   }
-  send_status_ = &status;
+  send_status_available_ = true;
+  send_status_code_ = static_cast<grpc_status_code>(status.code());
+  send_status_details_ = status.details();
 }
 
 void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
@@ -256,16 +262,15 @@
         &status_details_capacity_;
     (*nops)++;
   }
-  if (send_status_) {
+  if (send_status_available_) {
     ops[*nops].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
     ops[*nops].data.send_status_from_server.trailing_metadata_count =
         trailing_metadata_count_;
     ops[*nops].data.send_status_from_server.trailing_metadata =
         trailing_metadata_;
-    ops[*nops].data.send_status_from_server.status =
-        static_cast<grpc_status_code>(send_status_->code());
+    ops[*nops].data.send_status_from_server.status = send_status_code_;
     ops[*nops].data.send_status_from_server.status_details =
-        send_status_->details().c_str();
+        send_status_details_.empty() ? nullptr : send_status_details_.c_str();
     (*nops)++;
   }
   if (recv_closed_) {
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index fede2da..cea2d24 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -36,7 +36,6 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/time.h>
 #include "src/cpp/util/time.h"
 
 namespace grpc {
@@ -57,15 +56,12 @@
   }
 };
 
-CompletionQueue::NextStatus
-CompletionQueue::AsyncNext(void** tag, bool* ok,
-			   std::chrono::system_clock::time_point deadline) {
+CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
+    void** tag, bool* ok, gpr_timespec deadline) {
   std::unique_ptr<grpc_event, EventDeleter> ev;
 
-  gpr_timespec gpr_deadline;
-  Timepoint2Timespec(deadline, &gpr_deadline);
   for (;;) {
-    ev.reset(grpc_completion_queue_next(cq_, gpr_deadline));
+    ev.reset(grpc_completion_queue_next(cq_, deadline));
     if (!ev) { /* got a NULL back because deadline passed */
       return TIMEOUT;
     }
@@ -81,6 +77,13 @@
   }
 }
 
+CompletionQueue::NextStatus CompletionQueue::AsyncNext(
+    void** tag, bool* ok, std::chrono::system_clock::time_point deadline) {
+  gpr_timespec gpr_deadline;
+  Timepoint2Timespec(deadline, &gpr_deadline);
+  return AsyncNextInternal(tag, ok, gpr_deadline);
+}
+
 bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
   std::unique_ptr<grpc_event, EventDeleter> ev;
 
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index 88f7a9b..3e262dd 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -31,37 +31,23 @@
  *
  */
 
-#include <grpc/grpc_security.h>
-
-#include <grpc++/server_credentials.h>
+#include "src/cpp/server/secure_server_credentials.h"
 
 namespace grpc {
 
-namespace {
-class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
- public:
-  explicit SecureServerCredentials(grpc_server_credentials* creds)
-      : creds_(creds) {}
-  ~SecureServerCredentials() GRPC_OVERRIDE {
-    grpc_server_credentials_release(creds_);
-  }
-
-  int AddPortToServer(const grpc::string& addr,
-                      grpc_server* server) GRPC_OVERRIDE {
-    return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
-  }
-
- private:
-  grpc_server_credentials* const creds_;
-};
-}  // namespace
+int SecureServerCredentials::AddPortToServer(
+    const grpc::string& addr, grpc_server* server) {
+  return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
+}
 
 std::shared_ptr<ServerCredentials> SslServerCredentials(
     const SslServerCredentialsOptions& options) {
   std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs;
-  for (const auto& key_cert_pair : options.pem_key_cert_pairs) {
-    pem_key_cert_pairs.push_back(
-        {key_cert_pair.private_key.c_str(), key_cert_pair.cert_chain.c_str()});
+  for (auto key_cert_pair = options.pem_key_cert_pairs.begin();
+       key_cert_pair != options.pem_key_cert_pairs.end(); key_cert_pair++) {
+    grpc_ssl_pem_key_cert_pair p = {key_cert_pair->private_key.c_str(),
+                                    key_cert_pair->cert_chain.c_str()};
+    pem_key_cert_pairs.push_back(p);
   }
   grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create(
       options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
diff --git a/src/php/ext/grpc/completion_queue.h b/src/cpp/server/secure_server_credentials.h
old mode 100755
new mode 100644
similarity index 68%
rename from src/php/ext/grpc/completion_queue.h
rename to src/cpp/server/secure_server_credentials.h
index 1d386cc..b9803f1
--- a/src/php/ext/grpc/completion_queue.h
+++ b/src/cpp/server/secure_server_credentials.h
@@ -31,32 +31,30 @@
  *
  */
 
-#ifndef NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_
-#define NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_
+#ifndef GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
+#define GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <grpc/grpc_security.h>
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
+#include <grpc++/server_credentials.h>
 
-#include "grpc/grpc.h"
+namespace grpc {
 
-/* Class entry for the PHP CompletionQueue class */
-extern zend_class_entry *grpc_ce_completion_queue;
+class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
+ public:
+  explicit SecureServerCredentials(grpc_server_credentials* creds)
+      : creds_(creds) {}
+  ~SecureServerCredentials() GRPC_OVERRIDE {
+    grpc_server_credentials_release(creds_);
+  }
 
-/* Wrapper class for grpc_completion_queue that can be associated with a
-   PHP object */
-typedef struct wrapped_grpc_completion_queue {
-  zend_object std;
+  int AddPortToServer(const grpc::string& addr,
+                      grpc_server* server) GRPC_OVERRIDE;
 
-  grpc_completion_queue *wrapped;
-} wrapped_grpc_completion_queue;
+ private:
+  grpc_server_credentials* const creds_;
+};
 
-/* Initialize the CompletionQueue class */
-void grpc_init_completion_queue(TSRMLS_D);
+}  // namespace grpc
 
-#endif /* NET_GRPC_PHP_GRPC_COMPLETION_QUEUE_H_ */
+#endif  // GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 5a4ca69..046133c 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -107,6 +107,7 @@
           request_payload_(mrd->request_payload_),
           method_(mrd->method_) {
       ctx_.call_ = mrd->call_;
+      ctx_.cq_ = &cq_;
       GPR_ASSERT(mrd->in_flight_);
       mrd->in_flight_ = false;
       mrd->request_metadata_.count = 0;
@@ -182,7 +183,7 @@
 
 Server::~Server() {
   {
-    std::unique_lock<std::mutex> lock(mu_);
+    grpc::unique_lock<grpc::mutex> lock(mu_);
     if (started_ && !shutdown_) {
       lock.unlock();
       Shutdown();
@@ -247,8 +248,8 @@
 
   // Start processing rpcs.
   if (!sync_methods_.empty()) {
-    for (auto& m : sync_methods_) {
-      m.Request(server_);
+    for (auto m = sync_methods_.begin(); m != sync_methods_.end(); m++) {
+      m->Request(server_);
     }
 
     ScheduleCallback();
@@ -258,7 +259,7 @@
 }
 
 void Server::Shutdown() {
-  std::unique_lock<std::mutex> lock(mu_);
+  grpc::unique_lock<grpc::mutex> lock(mu_);
   if (started_ && !shutdown_) {
     shutdown_ = true;
     grpc_server_shutdown(server_);
@@ -272,7 +273,7 @@
 }
 
 void Server::Wait() {
-  std::unique_lock<std::mutex> lock(mu_);
+  grpc::unique_lock<grpc::mutex> lock(mu_);
   while (num_running_cb_ != 0) {
     callback_cv_.wait(lock);
   }
@@ -364,6 +365,7 @@
       }
     }
     ctx->call_ = call_;
+    ctx->cq_ = cq_;
     Call call(call_, server_, cq_);
     if (orig_status && call_) {
       ctx->BeginCompletionOp(&call);
@@ -403,7 +405,7 @@
 
 void Server::ScheduleCallback() {
   {
-    std::unique_lock<std::mutex> lock(mu_);
+    grpc::unique_lock<grpc::mutex> lock(mu_);
     num_running_cb_++;
   }
   thread_pool_->ScheduleCallback(std::bind(&Server::RunRpc, this));
@@ -424,7 +426,7 @@
   }
 
   {
-    std::unique_lock<std::mutex> lock(mu_);
+    grpc::unique_lock<grpc::mutex> lock(mu_);
     num_running_cb_--;
     if (shutdown_) {
       callback_cv_.notify_all();
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 58bf9d9..c5e115f 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -86,24 +86,26 @@
     thread_pool_owned = true;
   }
   std::unique_ptr<Server> server(new Server(thread_pool_, thread_pool_owned));
-  for (auto* service : services_) {
-    if (!server->RegisterService(service)) {
+  for (auto service = services_.begin(); service != services_.end();
+       service++) {
+    if (!server->RegisterService(*service)) {
       return nullptr;
     }
   }
-  for (auto* service : async_services_) {
-    if (!server->RegisterAsyncService(service)) {
+  for (auto service = async_services_.begin();
+       service != async_services_.end(); service++) {
+    if (!server->RegisterAsyncService(*service)) {
       return nullptr;
     }
   }
   if (generic_service_) {
     server->RegisterAsyncGenericService(generic_service_);
   }
-  for (auto& port : ports_) {
-    int r = server->AddListeningPort(port.addr, port.creds.get());
+  for (auto port = ports_.begin(); port != ports_.end(); port++) {
+    int r = server->AddListeningPort(port->addr, port->creds.get());
     if (!r) return nullptr;
-    if (port.selected_port != nullptr) {
-      *port.selected_port = r;
+    if (port->selected_port != nullptr) {
+      *port->selected_port = r;
     }
   }
   if (!server->Start()) {
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index bb3c2d1..ffd6d30 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -33,9 +33,8 @@
 
 #include <grpc++/server_context.h>
 
-#include <mutex>
-
 #include <grpc++/impl/call.h>
+#include <grpc++/impl/sync.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include "src/cpp/util/time.h"
@@ -57,14 +56,14 @@
   void Unref();
 
  private:
-  std::mutex mu_;
+  grpc::mutex mu_;
   int refs_;
   bool finalized_;
   bool cancelled_;
 };
 
 void ServerContext::CompletionOp::Unref() {
-  std::unique_lock<std::mutex> lock(mu_);
+  grpc::unique_lock<grpc::mutex> lock(mu_);
   if (--refs_ == 0) {
     lock.unlock();
     delete this;
@@ -73,13 +72,13 @@
 
 bool ServerContext::CompletionOp::CheckCancelled(CompletionQueue* cq) {
   cq->TryPluck(this);
-  std::lock_guard<std::mutex> g(mu_);
+  grpc::lock_guard<grpc::mutex> g(mu_);
   return finalized_ ? cancelled_ : false;
 }
 
 bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) {
   GPR_ASSERT(CallOpBuffer::FinalizeResult(tag, status));
-  std::unique_lock<std::mutex> lock(mu_);
+  grpc::unique_lock<grpc::mutex> lock(mu_);
   finalized_ = true;
   if (!*status) cancelled_ = true;
   if (--refs_ == 0) {
diff --git a/src/cpp/server/thread_pool.cc b/src/cpp/server/thread_pool.cc
index d3013b8..e8d0e89 100644
--- a/src/cpp/server/thread_pool.cc
+++ b/src/cpp/server/thread_pool.cc
@@ -31,48 +31,52 @@
  *
  */
 
+#include <grpc++/impl/sync.h>
+#include <grpc++/impl/thd.h>
+
 #include "src/cpp/server/thread_pool.h"
 
 namespace grpc {
 
+void ThreadPool::ThreadFunc() {
+  for (;;) {
+    // Wait until work is available or we are shutting down.
+    grpc::unique_lock<grpc::mutex> lock(mu_);
+    if (!shutdown_ && callbacks_.empty()) {
+      cv_.wait(lock);
+    }
+    // Drain callbacks before considering shutdown to ensure all work
+    // gets completed.
+    if (!callbacks_.empty()) {
+      auto cb = callbacks_.front();
+      callbacks_.pop();
+      lock.unlock();
+      cb();
+    } else if (shutdown_) {
+      return;
+    }
+  }
+}
+
 ThreadPool::ThreadPool(int num_threads) : shutdown_(false) {
   for (int i = 0; i < num_threads; i++) {
-    threads_.push_back(std::thread([this]() {
-      for (;;) {
-        // Wait until work is available or we are shutting down.
-        auto have_work = [this]() { return shutdown_ || !callbacks_.empty(); };
-        std::unique_lock<std::mutex> lock(mu_);
-        if (!have_work()) {
-          cv_.wait(lock, have_work);
-        }
-        // Drain callbacks before considering shutdown to ensure all work
-        // gets completed.
-        if (!callbacks_.empty()) {
-          auto cb = callbacks_.front();
-          callbacks_.pop();
-          lock.unlock();
-          cb();
-        } else if (shutdown_) {
-          return;
-        }
-      }
-    }));
+    threads_.push_back(grpc::thread(&ThreadPool::ThreadFunc, this));
   }
 }
 
 ThreadPool::~ThreadPool() {
   {
-    std::lock_guard<std::mutex> lock(mu_);
+    grpc::lock_guard<grpc::mutex> lock(mu_);
     shutdown_ = true;
     cv_.notify_all();
   }
-  for (auto& t : threads_) {
-    t.join();
+  for (auto t = threads_.begin(); t != threads_.end(); t++) {
+    t->join();
   }
 }
 
 void ThreadPool::ScheduleCallback(const std::function<void()>& callback) {
-  std::lock_guard<std::mutex> lock(mu_);
+  grpc::lock_guard<grpc::mutex> lock(mu_);
   callbacks_.push(callback);
   cv_.notify_one();
 }
diff --git a/src/cpp/server/thread_pool.h b/src/cpp/server/thread_pool.h
index 6225d82..0f24d6e 100644
--- a/src/cpp/server/thread_pool.h
+++ b/src/cpp/server/thread_pool.h
@@ -35,11 +35,11 @@
 #define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
 
 #include <grpc++/config.h>
+
+#include <grpc++/impl/sync.h>
+#include <grpc++/impl/thd.h>
 #include <grpc++/thread_pool_interface.h>
 
-#include <condition_variable>
-#include <thread>
-#include <mutex>
 #include <queue>
 #include <vector>
 
@@ -53,11 +53,13 @@
   void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
 
  private:
-  std::mutex mu_;
-  std::condition_variable cv_;
+  grpc::mutex mu_;
+  grpc::condition_variable cv_;
   bool shutdown_;
   std::queue<std::function<void()>> callbacks_;
-  std::vector<std::thread> threads_;
+  std::vector<grpc::thread> threads_;
+
+  void ThreadFunc();
 };
 
 }  // namespace grpc
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
index 44d2283..059ea72 100644
--- a/src/cpp/util/time.cc
+++ b/src/cpp/util/time.cc
@@ -42,11 +42,15 @@
 
 namespace grpc {
 
-// TODO(yangg) prevent potential overflow.
 void Timepoint2Timespec(const system_clock::time_point& from,
                         gpr_timespec* to) {
   system_clock::duration deadline = from.time_since_epoch();
   seconds secs = duration_cast<seconds>(deadline);
+  if (from == system_clock::time_point::max() ||
+      secs.count() >= gpr_inf_future.tv_sec || secs.count() < 0) {
+    *to = gpr_inf_future;
+    return;
+  }
   nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
   to->tv_sec = secs.count();
   to->tv_nsec = nsecs.count();
diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
index e432880..e0f0474 100644
--- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index af8a886..f203252 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -7,7 +7,7 @@
     <description>Core C# implementation of gRPC - an RPC library and framework. See project site for more info.
      This is an experimental release, not ready to use.
     </description>
-    <version>0.1.0</version>
+    <version>0.2.0</version>
     <authors>Google Inc.</authors>
     <owners>jtattermusch</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 168939c..81218cb 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -9,6 +9,6 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
 
 [assembly: InternalsVisibleTo("Grpc.Core.Tests")]
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index f5956bd..ca7683d 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -46,11 +46,15 @@
                 MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
                 MathExamples.DivExample(stub);
 
-                MathExamples.FibExample(stub);
+                MathExamples.DivAsyncExample(stub).Wait();
 
-                MathExamples.SumExample(stub);
+                MathExamples.FibExample(stub).Wait();
 
-                MathExamples.DivManyExample(stub);
+                MathExamples.SumExample(stub).Wait();
+
+                MathExamples.DivManyExample(stub).Wait();
+
+                MathExamples.DependendRequestsExample(stub).Wait();
             }
 
             GrpcEnvironment.Shutdown();
diff --git a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
index 11fc099..1989ca8 100644
--- a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.Examples.MathServer/.gitignore b/src/csharp/Grpc.Examples.MathServer/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
new file mode 100644
index 0000000..3f7e6c0
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{BF62FE08-373A-43D6-9D73-41CAA38B7011}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>Grpc.Examples.MathServer</RootNamespace>
+    <AssemblyName>Grpc.Examples.MathServer</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Externalconsole>true</Externalconsole>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Externalconsole>true</Externalconsole>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="MathServer.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Grpc.Examples\Grpc.Examples.csproj">
+      <Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project>
+      <Name>Grpc.Examples</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
new file mode 100644
index 0000000..884a84d
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
@@ -0,0 +1,61 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Grpc.Core;
+
+namespace math
+{
+    class MainClass
+    {
+        public static void Main(string[] args)
+        {
+            String host = "0.0.0.0";
+
+            GrpcEnvironment.Initialize();
+
+            Server server = new Server();
+            server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl()));
+            int port = server.AddListeningPort(host + ":0");
+            server.Start();
+
+            Console.WriteLine("MathServer listening on port " + port);
+
+            Console.WriteLine("Press any key to stop the server...");
+            Console.ReadKey();
+
+            server.ShutdownAsync().Wait();
+            GrpcEnvironment.Shutdown();
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..6b3d051
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,12 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.Examples.MathServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.1.*")]
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index cf5a640..f9c1caf 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -37,6 +37,18 @@
     <Reference Include="Google.ProtocolBuffers">
       <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
     </Reference>
+    <Reference Include="System.Reactive.Interfaces">
+      <HintPath>..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Reactive.Core">
+      <HintPath>..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Reactive.Linq">
+      <HintPath>..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Reactive.PlatformServices">
+      <HintPath>..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 85f213c..fa5d668 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -33,6 +33,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Reactive.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using Grpc.Core;
@@ -120,14 +121,12 @@
         [Test]
         public void Sum()
         {
-            var res = client.Sum();
-            foreach (var num in new long[] { 10, 20, 30 })
-            {
-                res.Inputs.OnNext(Num.CreateBuilder().SetNum_(num).Build());
-            }
-            res.Inputs.OnCompleted();
+            var clientStreamingResult = client.Sum();
+            var numList = new List<long> { 10, 20, 30 }.ConvertAll(
+                     n => Num.CreateBuilder().SetNum_(n).Build());
+            numList.Subscribe(clientStreamingResult.Inputs);
 
-            Assert.AreEqual(60, res.Task.Result.Num_);
+            Assert.AreEqual(60, clientStreamingResult.Task.Result.Num_);
         }
 
         [Test]
@@ -142,13 +141,7 @@
 
             var recorder = new RecordingObserver<DivReply>();
             var requestObserver = client.DivMany(recorder);
-
-            foreach (var arg in divArgsList)
-            {
-                requestObserver.OnNext(arg);
-            }
-            requestObserver.OnCompleted();
-
+            divArgsList.Subscribe(requestObserver);
             var result = recorder.ToList().Result;
 
             CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
diff --git a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
index 43c7616..d78e921 100644
--- a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config
index 51c17bc..06c5e6a 100644
--- a/src/csharp/Grpc.Examples.Tests/packages.config
+++ b/src/csharp/Grpc.Examples.Tests/packages.config
@@ -1,5 +1,10 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
-  <package id="NUnit" version="2.6.4" targetFramework="net45" />
+<?xml version="1.0" encoding="utf-8"?>

+<packages>

+  <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />

+  <package id="NUnit" version="2.6.4" targetFramework="net45" />

+  <package id="Rx-Core" version="2.2.5" targetFramework="net45" />

+  <package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" />

+  <package id="Rx-Linq" version="2.2.5" targetFramework="net45" />

+  <package id="Rx-Main" version="2.2.5" targetFramework="net45" />

+  <package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" />

 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index b8bb7ea..032372b 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -45,51 +45,45 @@
             Console.WriteLine("Div Result: " + result);
         }
 
-        public static void DivAsyncExample(MathGrpc.IMathServiceClient stub)
+        public static async Task DivAsyncExample(MathGrpc.IMathServiceClient stub)
         {
-            Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
-            DivReply result = call.Result;
+            Task<DivReply> resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
+            DivReply result = await resultTask;
+            Console.WriteLine("DivAsync Result: " + result);
+        }
+
+        public static async Task DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub)
+        {
+            Task<DivReply> resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
+            DivReply result = await resultTask;
             Console.WriteLine(result);
         }
 
-        public static void DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub)
-        {
-            Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
-            DivReply result = call.Result;
-            Console.WriteLine(result);
-        }
-
-        public static void FibExample(MathGrpc.IMathServiceClient stub)
+        public static async Task FibExample(MathGrpc.IMathServiceClient stub)
         {
             var recorder = new RecordingObserver<Num>();
             stub.Fib(new FibArgs.Builder { Limit = 5 }.Build(), recorder);
-
-            List<Num> numbers = recorder.ToList().Result;
-            Console.WriteLine("Fib Result: " + string.Join("|", recorder.ToList().Result));
+            List<Num> result = await recorder.ToList();
+            Console.WriteLine("Fib Result: " + string.Join("|", result));
         }
 
-        public static void SumExample(MathGrpc.IMathServiceClient stub)
+        public static async Task SumExample(MathGrpc.IMathServiceClient stub)
         {
-            List<Num> numbers = new List<Num>
+            var numbers = new List<Num>
             {
                 new Num.Builder { Num_ = 1 }.Build(),
                 new Num.Builder { Num_ = 2 }.Build(),
                 new Num.Builder { Num_ = 3 }.Build()
             };
 
-            var res = stub.Sum();
-            foreach (var num in numbers)
-            {
-                res.Inputs.OnNext(num);
-            }
-            res.Inputs.OnCompleted();
-
-            Console.WriteLine("Sum Result: " + res.Task.Result);
+            var clientStreamingResult = stub.Sum();
+            numbers.Subscribe(clientStreamingResult.Inputs);
+            Console.WriteLine("Sum Result: " + await clientStreamingResult.Task);
         }
 
-        public static void DivManyExample(MathGrpc.IMathServiceClient stub)
+        public static async Task DivManyExample(MathGrpc.IMathServiceClient stub)
         {
-            List<DivArgs> divArgsList = new List<DivArgs>
+            var divArgsList = new List<DivArgs>
             {
                 new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
                 new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
@@ -97,26 +91,27 @@
             };
 
             var recorder = new RecordingObserver<DivReply>();
-
             var inputs = stub.DivMany(recorder);
-            foreach (var input in divArgsList)
-            {
-                inputs.OnNext(input);
-            }
-            inputs.OnCompleted();
-
-            Console.WriteLine("DivMany Result: " + string.Join("|", recorder.ToList().Result));
+            divArgsList.Subscribe(inputs);
+            var result = await recorder.ToList();
+            Console.WriteLine("DivMany Result: " + string.Join("|", result));
         }
 
-        public static void DependendRequestsExample(MathGrpc.IMathServiceClient stub)
+        public static async Task DependendRequestsExample(MathGrpc.IMathServiceClient stub)
         {
-            var numberList = new List<Num>
+            var numbers = new List<Num>
             {
-                new Num.Builder { Num_ = 1 }.Build(),
-                new Num.Builder { Num_ = 2 }.Build(), new Num.Builder { Num_ = 3 }.Build()
+                new Num.Builder { Num_ = 1 }.Build(), 
+                new Num.Builder { Num_ = 2 }.Build(),
+                new Num.Builder { Num_ = 3 }.Build()
             };
 
-            numberList.ToObservable();
+            var clientStreamingResult = stub.Sum();
+            numbers.Subscribe(clientStreamingResult.Inputs);
+            Num sum = await clientStreamingResult.Task;
+
+            DivReply result = await stub.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build());
+            Console.WriteLine("Avg Result: " + result);
         }
     }
 }
diff --git a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
index b55d241..fd1cdbb 100644
--- a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
index c93dd1e..d9d36f0 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
index f3def1a..b0b163b 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
index f09a448..fe6c8a8 100644
--- a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.nuspec b/src/csharp/Grpc.nuspec
index 96a6aaf..4c106a2 100644
--- a/src/csharp/Grpc.nuspec
+++ b/src/csharp/Grpc.nuspec
@@ -7,7 +7,7 @@
     <description>C# implementation of gRPC - an RPC library and framework. See project site for more info.
      This is an experimental release, not ready to use.
     </description>
-    <version>0.1.0</version>
+    <version>0.2.0</version>
     <authors>Google Inc.</authors>
     <owners>jtattermusch</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
@@ -17,7 +17,7 @@
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2</tags>
     <dependencies>
-      <dependency id="Grpc.Core" version="0.1.0" />
+      <dependency id="Grpc.Core" version="0.2.0" />
     </dependencies>
   </metadata>
 </package>
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 2e6d288..2f8c2e1 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -17,6 +17,8 @@
 EndProject

 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.csproj", "{A654F3B8-E859-4E6A-B30D-227527DBEF0D}"

 EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.csproj", "{BF62FE08-373A-43D6-9D73-41CAA38B7011}"

+EndProject

 Global

 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

 		Debug|x86 = Debug|x86

@@ -47,6 +49,10 @@
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86

 		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86

 		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86

 		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86

diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 9a1c908..e182468 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -731,7 +731,7 @@
   }
 }
 
-GPR_EXPORT void grpcsharp_credentials_release(grpc_credentials *creds) {
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *creds) {
   grpc_credentials_release(creds);
 }
 
@@ -765,7 +765,7 @@
   return creds;
 }
 
-GPR_EXPORT void grpcsharp_server_credentials_release(
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_credentials_release(
     grpc_server_credentials *creds) {
   grpc_server_credentials_release(creds);
 }
diff --git a/src/node/binding.gyp b/src/node/binding.gyp
index 7ef3bdf..83f72fa 100644
--- a/src/node/binding.gyp
+++ b/src/node/binding.gyp
@@ -18,12 +18,29 @@
       ],
       'link_settings': {
         'libraries': [
-          '-lrt',
           '-lpthread',
           '-lgrpc',
           '-lgpr'
-        ],
+        ]
       },
+      "conditions": [
+        ['OS == "mac"', {
+          'xcode_settings': {
+            'MACOSX_DEPLOYMENT_TARGET': '10.9',
+            'OTHER_CFLAGS': [
+              '-std=c++11',
+              '-stdlib=libc++'
+            ]
+          }
+        }],
+        ['OS != "mac"', {
+          'link_settings': {
+            'libraries': [
+              '-lrt'
+            ]
+          }
+        }]
+      ],
       "target_name": "grpc",
       "sources": [
         "ext/byte_buffer.cc",
diff --git a/src/node/examples/qps_test.js b/src/node/examples/qps_test.js
new file mode 100644
index 0000000..00293b4
--- /dev/null
+++ b/src/node/examples/qps_test.js
@@ -0,0 +1,136 @@
+/*
+ *
+ * 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 script runs a QPS test. It sends requests for a specified length of time
+ * with a specified number pending at any one time. It then outputs the measured
+ * QPS. Usage:
+ * node qps_test.js [--concurrent=count] [--time=seconds]
+ * concurrent defaults to 100 and time defaults to 10
+ */
+
+'use strict';
+
+var async = require('async');
+var parseArgs = require('minimist');
+
+var grpc = require('..');
+var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing;
+var interop_server = require('../interop/interop_server.js');
+
+/**
+ * Runs the QPS test. Sends requests constantly for the given number of seconds,
+ * and keeps concurrent_calls requests pending at all times. When the test ends,
+ * the callback is called with the number of calls that completed within the
+ * time limit.
+ * @param {number} concurrent_calls The number of calls to have pending
+ *     simultaneously
+ * @param {number} seconds The number of seconds to run the test for
+ * @param {function(Error, number)} callback Callback for test completion
+ */
+function runTest(concurrent_calls, seconds, callback) {
+  var testServer = interop_server.getServer(0, false);
+  testServer.server.listen();
+  var client = new testProto.TestService('localhost:' + testServer.port);
+
+  var warmup_num = 100;
+
+  /**
+   * Warms up the client to avoid counting startup time in the test result
+   * @param {function(Error)} callback Called when warmup is complete
+   */
+  function warmUp(callback) {
+    var pending = warmup_num;
+    function startCall() {
+      client.emptyCall({}, function(err, resp) {
+        if (err) {
+          callback(err);
+          return;
+        }
+        pending--;
+        if (pending === 0) {
+          callback(null);
+        }
+      });
+    }
+    for (var i = 0; i < warmup_num; i++) {
+      startCall();
+    }
+  }
+  /**
+   * Run the QPS test. Starts concurrent_calls requests, then starts a new
+   * request whenever one completes until time runs out.
+   * @param {function(Error, number)} callback Called when the test is complete.
+   *     The second argument is the number of calls that finished within the
+   *     time limit
+   */
+  function run(callback) {
+    var running = 0;
+    var count = 0;
+    var start = process.hrtime();
+    function responseCallback(err, resp) {
+      if (process.hrtime(start)[0] < seconds) {
+        count += 1;
+        client.emptyCall({}, responseCallback);
+      } else {
+        running -= 1;
+        if (running <= 0) {
+          callback(null, count);
+        }
+      }
+    }
+    for (var i = 0; i < concurrent_calls; i++) {
+      running += 1;
+      client.emptyCall({}, responseCallback);
+    }
+  }
+  async.waterfall([warmUp, run], function(err, count) {
+      testServer.server.shutdown();
+      callback(err, count);
+    });
+}
+
+if (require.main === module) {
+  var argv = parseArgs(process.argv.slice(2), {
+    default: {'concurrent': 100,
+              'time': 10}
+  });
+  runTest(argv.concurrent, argv.time, function(err, count) {
+    if (err) {
+      throw err;
+    }
+    console.log('Concurrent calls:', argv.concurrent);
+    console.log('Time:', argv.time, 'seconds');
+    console.log('QPS:', (count/argv.time));
+  });
+}
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index 82b54b5..01bd92e 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -32,7 +32,6 @@
  */
 
 #include <string.h>
-#include <malloc.h>
 
 #include <node.h>
 #include <nan.h>
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 787e274..d37bf76 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -31,8 +31,6 @@
  *
  */
 
-#include <malloc.h>
-
 #include <vector>
 
 #include <node.h>
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index e47bac8..3c2396b 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -38,8 +38,6 @@
 #include <node.h>
 #include <nan.h>
 
-#include <malloc.h>
-
 #include <vector>
 #include "grpc/grpc.h"
 #include "grpc/grpc_security.h"
diff --git a/src/node/index.js b/src/node/index.js
index ad3dd96..0b768ed 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -56,7 +56,7 @@
     });
     return result;
   } else if (value.className === 'Service') {
-    return client.makeClientConstructor(value);
+    return client.makeProtobufClientConstructor(value);
   } else if (value.className === 'Message' || value.className === 'Enum') {
     return value.build();
   } else {
@@ -119,7 +119,7 @@
 /**
  * See docs for server.makeServerConstructor
  */
-exports.buildServer = server.makeServerConstructor;
+exports.buildServer = server.makeProtobufServerConstructor;
 
 /**
  * Status name to code number mapping
@@ -141,3 +141,7 @@
 exports.ServerCredentials = grpc.ServerCredentials;
 
 exports.getGoogleAuthDelegate = getGoogleAuthDelegate;
+
+exports.makeGenericClientConstructor = client.makeClientConstructor;
+
+exports.makeGenericServerConstructor = server.makeServerConstructor;
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 8060baf..3341486 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -35,6 +35,7 @@
 
 var fs = require('fs');
 var path = require('path');
+var _ = require('underscore');
 var grpc = require('..');
 var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
 var GoogleAuth = require('google-auth-library');
@@ -45,6 +46,8 @@
 var AUTH_SCOPE_RESPONSE = 'xapi.zoo';
 var AUTH_USER = ('155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk' +
     '@developer.gserviceaccount.com');
+var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' +
+    '@developer.gserviceaccount.com');
 
 /**
  * Create a buffer filled with size zeroes
@@ -265,11 +268,12 @@
 
 /**
  * Run one of the authentication tests.
+ * @param {string} expected_user The expected username in the response
  * @param {Client} client The client to test against
  * @param {function} done Callback to call when the test is completed. Included
  *     primarily for use with mocha
  */
-function authTest(client, done) {
+function authTest(expected_user, client, done) {
   (new GoogleAuth()).getApplicationDefault(function(err, credential) {
     assert.ifError(err);
     if (credential.createScopedRequired()) {
@@ -290,7 +294,7 @@
       assert.strictEqual(resp.payload.type, testProto.PayloadType.COMPRESSABLE);
       assert.strictEqual(resp.payload.body.limit - resp.payload.body.offset,
                          314159);
-      assert.strictEqual(resp.username, AUTH_USER);
+      assert.strictEqual(resp.username, expected_user);
       assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
     });
     call.on('status', function(status) {
@@ -314,8 +318,8 @@
   empty_stream: emptyStream,
   cancel_after_begin: cancelAfterBegin,
   cancel_after_first_response: cancelAfterFirstResponse,
-  compute_engine_creds: authTest,
-  service_account_creds: authTest
+  compute_engine_creds: _.partial(authTest, COMPUTE_ENGINE_USER),
+  service_account_creds: _.partial(authTest, AUTH_USER)
 };
 
 /**
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 54b8dbd..fad369c 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -35,9 +35,6 @@
 
 var _ = require('underscore');
 
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
 var grpc = require('bindings')('grpc.node');
 
 var common = require('./common.js');
@@ -244,13 +241,13 @@
           callback(err);
           return;
         }
+        emitter.emit('status', response.status);
         if (response.status.code !== grpc.status.OK) {
           var error = new Error(response.status.details);
           error.code = response.status.code;
           callback(error);
           return;
         }
-        emitter.emit('status', response.status);
         emitter.emit('metadata', response.metadata);
         callback(null, deserialize(response.read));
       });
@@ -315,13 +312,13 @@
           callback(err);
           return;
         }
+        stream.emit('status', response.status);
         if (response.status.code !== grpc.status.OK) {
           var error = new Error(response.status.details);
           error.code = response.status.code;
           callback(error);
           return;
         }
-        stream.emit('status', response.status);
         callback(null, deserialize(response.read));
       });
     });
@@ -463,13 +460,18 @@
 };
 
 /**
- * Creates a constructor for clients for the given service
- * @param {ProtoBuf.Reflect.Service} service The service to generate a client
- *     for
+ * Creates a constructor for a client with the given methods. The methods object
+ * maps method name to an object with the following keys:
+ * path: The path on the server for accessing the method. For example, for
+ *     protocol buffers, we use "/service_name/method_name"
+ * requestStream: bool indicating whether the client sends a stream
+ * resonseStream: bool indicating whether the server sends a stream
+ * requestSerialize: function to serialize request objects
+ * responseDeserialize: function to deserialize response objects
+ * @param {Object} methods An object mapping method names to method attributes
  * @return {function(string, Object)} New client constructor
  */
-function makeClientConstructor(service) {
-  var prefix = '/' + common.fullyQualifiedName(service) + '/';
+function makeClientConstructor(methods) {
   /**
    * Create a client with the given methods
    * @constructor
@@ -489,30 +491,41 @@
     this.channel = new grpc.Channel(address, options);
   }
 
-  _.each(service.children, function(method) {
+  _.each(methods, function(attrs, name) {
     var method_type;
-    if (method.requestStream) {
-      if (method.responseStream) {
+    if (attrs.requestStream) {
+      if (attrs.responseStream) {
         method_type = 'bidi';
       } else {
         method_type = 'client_stream';
       }
     } else {
-      if (method.responseStream) {
+      if (attrs.responseStream) {
         method_type = 'server_stream';
       } else {
         method_type = 'unary';
       }
     }
-    var serialize = common.serializeCls(method.resolvedRequestType.build());
-    var deserialize = common.deserializeCls(
-        method.resolvedResponseType.build());
-    Client.prototype[decapitalize(method.name)] = requester_makers[method_type](
-        prefix + capitalize(method.name), serialize, deserialize);
-    Client.prototype[decapitalize(method.name)].serialize = serialize;
-    Client.prototype[decapitalize(method.name)].deserialize = deserialize;
+    var serialize = attrs.requestSerialize;
+    var deserialize = attrs.responseDeserialize;
+    Client.prototype[name] = requester_makers[method_type](
+        attrs.path, serialize, deserialize);
+    Client.prototype[name].serialize = serialize;
+    Client.prototype[name].deserialize = deserialize;
   });
 
+  return Client;
+}
+
+/**
+ * Creates a constructor for clients for the given service
+ * @param {ProtoBuf.Reflect.Service} service The service to generate a client
+ *     for
+ * @return {function(string, Object)} New client constructor
+ */
+function makeProtobufClientConstructor(service) {
+  var method_attrs = common.getProtobufServiceAttrs(service);
+  var Client = makeClientConstructor(method_attrs);
   Client.service = service;
 
   return Client;
@@ -520,6 +533,8 @@
 
 exports.makeClientConstructor = makeClientConstructor;
 
+exports.makeProtobufClientConstructor = makeProtobufClientConstructor;
+
 /**
  * See docs for client.status
  */
diff --git a/src/node/src/common.js b/src/node/src/common.js
index eec8f0f..55a6b13 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -36,6 +36,7 @@
 var _ = require('underscore');
 
 var capitalize = require('underscore.string/capitalize');
+var decapitalize = require('underscore.string/decapitalize');
 
 /**
  * Get a function that deserializes a specific type of protobuf.
@@ -110,6 +111,26 @@
 }
 
 /**
+ * Return a map from method names to method attributes for the service.
+ * @param {ProtoBuf.Reflect.Service} service The service to get attributes for
+ * @return {Object} The attributes map
+ */
+function getProtobufServiceAttrs(service) {
+  var prefix = '/' + fullyQualifiedName(service) + '/';
+  return _.object(_.map(service.children, function(method) {
+    return [decapitalize(method.name), {
+      path: prefix + capitalize(method.name),
+      requestStream: method.requestStream,
+      responseStream: method.responseStream,
+      requestSerialize: serializeCls(method.resolvedRequestType.build()),
+      requestDeserialize: deserializeCls(method.resolvedRequestType.build()),
+      responseSerialize: serializeCls(method.resolvedResponseType.build()),
+      responseDeserialize: deserializeCls(method.resolvedResponseType.build())
+    }];
+  }));
+}
+
+/**
  * See docs for deserializeCls
  */
 exports.deserializeCls = deserializeCls;
@@ -128,3 +149,5 @@
  * See docs for wrapIgnoreNull
  */
 exports.wrapIgnoreNull = wrapIgnoreNull;
+
+exports.getProtobufServiceAttrs = getProtobufServiceAttrs;
diff --git a/src/node/src/server.js b/src/node/src/server.js
index b72d110..05de162 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -35,9 +35,6 @@
 
 var _ = require('underscore');
 
-var capitalize = require('underscore.string/capitalize');
-var decapitalize = require('underscore.string/decapitalize');
-
 var grpc = require('bindings')('grpc.node');
 
 var common = require('./common');
@@ -73,6 +70,9 @@
       status.details = error.details;
     }
   }
+  if (error.hasOwnProperty('metadata')) {
+    status.metadata = error.metadata;
+  }
   var error_batch = {};
   error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
   call.startBatch(error_batch, function(){});
@@ -105,15 +105,20 @@
  * @param {*} value The value to respond with
  * @param {function(*):Buffer=} serialize Serialization function for the
  *     response
+ * @param {Object=} metadata Optional trailing metadata to send with status
  */
-function sendUnaryResponse(call, value, serialize) {
+function sendUnaryResponse(call, value, serialize, metadata) {
   var end_batch = {};
-  end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
-  end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+  var status = {
     code: grpc.status.OK,
     details: 'OK',
     metadata: {}
   };
+  if (metadata) {
+    status.metadata = metadata;
+  }
+  end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
+  end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
   call.startBatch(end_batch, function (){});
 }
 
@@ -146,6 +151,7 @@
   function setStatus(err) {
     var code = grpc.status.INTERNAL;
     var details = 'Unknown Error';
+    var metadata = {};
     if (err.hasOwnProperty('message')) {
       details = err.message;
     }
@@ -155,7 +161,10 @@
         details = err.details;
       }
     }
-    stream.status = {code: code, details: details, metadata: {}};
+    if (err.hasOwnProperty('metadata')) {
+      metadata = err.metadata;
+    }
+    stream.status = {code: code, details: details, metadata: metadata};
   }
   /**
    * Terminate the call. This includes indicating that reads are done, draining
@@ -169,6 +178,17 @@
     stream.end();
   }
   stream.on('error', terminateCall);
+  /**
+   * Override of Writable#end method that allows for sending metadata with a
+   * success status.
+   * @param {Object=} metadata Metadata to send with the status
+   */
+  stream.end = function(metadata) {
+    if (metadata) {
+      stream.status.metadata = metadata;
+    }
+    Writable.prototype.end.call(this);
+  };
 }
 
 /**
@@ -338,11 +358,13 @@
     if (emitter.cancelled) {
       return;
     }
-    handler.func(emitter, function sendUnaryData(err, value) {
+    handler.func(emitter, function sendUnaryData(err, value, trailer) {
       if (err) {
+        err.metadata = trailer;
         handleError(call, err);
+      } else {
+        sendUnaryResponse(call, value, handler.serialize, trailer);
       }
-      sendUnaryResponse(call, value, handler.serialize);
     });
   });
 }
@@ -381,12 +403,14 @@
   var metadata_batch = {};
   metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
   call.startBatch(metadata_batch, function() {});
-  handler.func(stream, function(err, value) {
+  handler.func(stream, function(err, value, trailer) {
     stream.terminate();
     if (err) {
+      err.metadata = trailer;
       handleError(call, err);
+    } else {
+      sendUnaryResponse(call, value, handler.serialize, trailer);
     }
-    sendUnaryResponse(call, value, handler.serialize);
   });
 }
 
@@ -532,26 +556,20 @@
 };
 
 /**
- * Creates a constructor for servers with a service defined by the methods
- * object. The methods object has string keys and values of this form:
- * {serialize: function, deserialize: function, client_stream: bool,
- *  server_stream: bool}
- * @param {Object} methods Method descriptor for each method the server should
- *     expose
- * @param {string} prefix The prefex to prepend to each method name
- * @return {function(Object, Object)} New server constructor
+ * Create a constructor for servers with services defined by service_attr_map.
+ * That is an object that maps (namespaced) service names to objects that in
+ * turn map method names to objects with the following keys:
+ * path: The path on the server for accessing the method. For example, for
+ *     protocol buffers, we use "/service_name/method_name"
+ * requestStream: bool indicating whether the client sends a stream
+ * resonseStream: bool indicating whether the server sends a stream
+ * requestDeserialize: function to deserialize request objects
+ * responseSerialize: function to serialize response objects
+ * @param {Object} service_attr_map An object mapping service names to method
+ *     attribute map objects
+ * @return {function(Object, function, Object=)} New server constructor
  */
-function makeServerConstructor(services) {
-  var qual_names = [];
-  _.each(services, function(service) {
-    _.each(service.children, function(method) {
-      var name = common.fullyQualifiedName(method);
-      if (_.indexOf(qual_names, name) !== -1) {
-        throw new Error('Method ' + name + ' exposed by more than one service');
-      }
-      qual_names.push(name);
-    });
-  });
+function makeServerConstructor(service_attr_map) {
   /**
    * Create a server with the given handlers for all of the methods.
    * @constructor
@@ -565,41 +583,34 @@
   function SurfaceServer(service_handlers, getMetadata, options) {
     var server = new Server(getMetadata, options);
     this.inner_server = server;
-    _.each(services, function(service) {
-      var service_name = common.fullyQualifiedName(service);
+    _.each(service_attr_map, function(service_attrs, service_name) {
       if (service_handlers[service_name] === undefined) {
         throw new Error('Handlers for service ' +
             service_name + ' not provided.');
       }
-      var prefix = '/' + common.fullyQualifiedName(service) + '/';
-      _.each(service.children, function(method) {
+      _.each(service_attrs, function(attrs, name) {
         var method_type;
-        if (method.requestStream) {
-          if (method.responseStream) {
+        if (attrs.requestStream) {
+          if (attrs.responseStream) {
             method_type = 'bidi';
           } else {
             method_type = 'client_stream';
           }
         } else {
-          if (method.responseStream) {
+          if (attrs.responseStream) {
             method_type = 'server_stream';
           } else {
             method_type = 'unary';
           }
         }
-        if (service_handlers[service_name][decapitalize(method.name)] ===
-            undefined) {
-          throw new Error('Method handler for ' +
-              common.fullyQualifiedName(method) + ' not provided.');
+        if (service_handlers[service_name][name] === undefined) {
+          throw new Error('Method handler for ' + attrs.path +
+              ' not provided.');
         }
-        var serialize = common.serializeCls(
-            method.resolvedResponseType.build());
-        var deserialize = common.deserializeCls(
-            method.resolvedRequestType.build());
-        server.register(
-            prefix + capitalize(method.name),
-            service_handlers[service_name][decapitalize(method.name)],
-            serialize, deserialize, method_type);
+        var serialize = attrs.responseSerialize;
+        var deserialize = attrs.requestDeserialize;
+        server.register(attrs.path, service_handlers[service_name][name],
+                        serialize, deserialize, method_type);
       });
     }, this);
   }
@@ -636,6 +647,39 @@
 }
 
 /**
+ * Create a constructor for servers that serve the given services.
+ * @param {Array<ProtoBuf.Reflect.Service>} services The services that the
+ *     servers will serve
+ * @return {function(Object, function, Object=)} New server constructor
+ */
+function makeProtobufServerConstructor(services) {
+  var qual_names = [];
+  var service_attr_map = {};
+  _.each(services, function(service) {
+    var service_name = common.fullyQualifiedName(service);
+    _.each(service.children, function(method) {
+      var name = common.fullyQualifiedName(method);
+      if (_.indexOf(qual_names, name) !== -1) {
+        throw new Error('Method ' + name + ' exposed by more than one service');
+      }
+      qual_names.push(name);
+    });
+    var method_attrs = common.getProtobufServiceAttrs(service);
+    if (!service_attr_map.hasOwnProperty(service_name)) {
+      service_attr_map[service_name] = {};
+    }
+    service_attr_map[service_name] = _.extend(service_attr_map[service_name],
+                                              method_attrs);
+  });
+  return makeServerConstructor(service_attr_map);
+}
+
+/**
  * See documentation for makeServerConstructor
  */
 exports.makeServerConstructor = makeServerConstructor;
+
+/**
+ * See documentation for makeProtobufServerConstructor
+ */
+exports.makeProtobufServerConstructor = makeProtobufServerConstructor;
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 91d8197..590c644 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -45,6 +45,8 @@
 
 var mathService = math_proto.lookup('math.Math');
 
+var capitalize = require('underscore.string/capitalize');
+
 describe('Surface server constructor', function() {
   it('Should fail with conflicting method names', function() {
     assert.throws(function() {
@@ -75,6 +77,216 @@
     }, /math.Math/);
   });
 });
+describe('Generic client and server', function() {
+  function toString(val) {
+    return val.toString();
+  }
+  function toBuffer(str) {
+    return new Buffer(str);
+  }
+  var string_service_attrs = {
+    'capitalize' : {
+      path: '/string/capitalize',
+      requestStream: false,
+      responseStream: false,
+      requestSerialize: toBuffer,
+      requestDeserialize: toString,
+      responseSerialize: toBuffer,
+      responseDeserialize: toString
+    }
+  };
+  describe('String client and server', function() {
+    var client;
+    var server;
+    before(function() {
+      var Server = grpc.makeGenericServerConstructor({
+        string: string_service_attrs
+      });
+      server = new Server({
+        string: {
+          capitalize: function(call, callback) {
+            callback(null, capitalize(call.request));
+          }
+        }
+      });
+      var port = server.bind('localhost:0');
+      server.listen();
+      var Client = grpc.makeGenericClientConstructor(string_service_attrs);
+      client = new Client('localhost:' + port);
+    });
+    after(function() {
+      server.shutdown();
+    });
+    it('Should respond with a capitalized string', function(done) {
+      client.capitalize('abc', function(err, response) {
+        assert.ifError(err);
+        assert.strictEqual(response, 'Abc');
+        done();
+      });
+    });
+  });
+});
+describe('Trailing metadata', function() {
+  var client;
+  var server;
+  before(function() {
+    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_service = test_proto.lookup('TestService');
+    var Server = grpc.buildServer([test_service]);
+    server = new Server({
+      TestService: {
+        unary: function(call, cb) {
+          var req = call.request;
+          if (req.error) {
+            cb(new Error('Requested error'), null, {metadata: ['yes']});
+          } else {
+            cb(null, {count: 1}, {metadata: ['yes']});
+          }
+        },
+        clientStream: function(stream, cb){
+          var count = 0;
+          var errored;
+          stream.on('data', function(data) {
+            if (data.error) {
+              errored = true;
+              cb(new Error('Requested error'), null, {metadata: ['yes']});
+            } else {
+              count += 1;
+            }
+          });
+          stream.on('end', function() {
+            if (!errored) {
+              cb(null, {count: count}, {metadata: ['yes']});
+            }
+          });
+        },
+        serverStream: function(stream) {
+          var req = stream.request;
+          if (req.error) {
+            var err = new Error('Requested error');
+            err.metadata = {metadata: ['yes']};
+            stream.emit('error', err);
+          } else {
+            for (var i = 0; i < 5; i++) {
+              stream.write({count: i});
+            }
+            stream.end({metadata: ['yes']});
+          }
+        },
+        bidiStream: function(stream) {
+          var count = 0;
+          stream.on('data', function(data) {
+            if (data.error) {
+              var err = new Error('Requested error');
+              err.metadata = {
+                metadata: ['yes'],
+                count: ['' + count]
+              };
+              stream.emit('error', err);
+            } else {
+              stream.write({count: count});
+              count += 1;
+            }
+          });
+          stream.on('end', function() {
+            stream.end({metadata: ['yes']});
+          });
+        }
+      }
+    });
+    var port = server.bind('localhost:0');
+    var Client = surface_client.makeProtobufClientConstructor(test_service);
+    client = new Client('localhost:' + port);
+    server.listen();
+  });
+  after(function() {
+    server.shutdown();
+  });
+  it('should be present when a unary call succeeds', function(done) {
+    var call = client.unary({error: false}, function(err, data) {
+      assert.ifError(err);
+    });
+    call.on('status', function(status) {
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+  it('should be present when a unary call fails', function(done) {
+    var call = client.unary({error: true}, function(err, data) {
+      assert(err);
+    });
+    call.on('status', function(status) {
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+  it('should be present when a client stream call succeeds', function(done) {
+    var call = client.clientStream(function(err, data) {
+      assert.ifError(err);
+    });
+    call.write({error: false});
+    call.write({error: false});
+    call.end();
+    call.on('status', function(status) {
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+  it('should be present when a client stream call fails', function(done) {
+    var call = client.clientStream(function(err, data) {
+      assert(err);
+    });
+    call.write({error: false});
+    call.write({error: true});
+    call.end();
+    call.on('status', function(status) {
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+  it('should be present when a server stream call succeeds', function(done) {
+    var call = client.serverStream({error: false});
+    call.on('data', function(){});
+    call.on('status', function(status) {
+      assert.strictEqual(status.code, grpc.status.OK);
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+  it('should be present when a server stream call fails', function(done) {
+    var call = client.serverStream({error: true});
+    call.on('data', function(){});
+    call.on('status', function(status) {
+      assert.notStrictEqual(status.code, grpc.status.OK);
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+  it('should be present when a bidi stream succeeds', function(done) {
+    var call = client.bidiStream();
+    call.write({error: false});
+    call.write({error: false});
+    call.end();
+    call.on('data', function(){});
+    call.on('status', function(status) {
+      assert.strictEqual(status.code, grpc.status.OK);
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+  it('should be present when a bidi stream fails', function(done) {
+    var call = client.bidiStream();
+    call.write({error: false});
+    call.write({error: true});
+    call.end();
+    call.on('data', function(){});
+    call.on('status', function(status) {
+      assert.notStrictEqual(status.code, grpc.status.OK);
+      assert.deepEqual(status.metadata.metadata, ['yes']);
+      done();
+    });
+  });
+});
 describe('Cancelling surface client', function() {
   var client;
   var server;
@@ -89,7 +301,7 @@
       }
     });
     var port = server.bind('localhost:0');
-    var Client = surface_client.makeClientConstructor(mathService);
+    var Client = surface_client.makeProtobufClientConstructor(mathService);
     client = new Client('localhost:' + port);
   });
   after(function() {
diff --git a/src/node/test/test_service.proto b/src/node/test/test_service.proto
new file mode 100644
index 0000000..5d3d891
--- /dev/null
+++ b/src/node/test/test_service.proto
@@ -0,0 +1,52 @@
+// 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.
+
+syntax = "proto2";
+
+message Request {
+  optional bool error = 1;
+}
+
+message Response {
+  optional int32 count = 1;
+}
+
+service TestService {
+  rpc Unary (Request) returns (Response) {
+  }
+
+  rpc ClientStream (stream Request) returns (Response) {
+  }
+
+  rpc ServerStream (Request) returns (stream Response) {
+  }
+
+  rpc BidiStream (stream Request) returns (stream Response) {
+  }
+}
\ No newline at end of file
diff --git a/src/php/bin/generate_proto_php.sh b/src/php/bin/generate_proto_php.sh
new file mode 100755
index 0000000..16f9374
--- /dev/null
+++ b/src/php/bin/generate_proto_php.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# 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.
+
+
+set +e
+cd $(dirname $0)
+
+gen_code='../tests/generated_code'
+interop='../tests/interop'
+
+protoc-gen-php -i $gen_code -o $gen_code $gen_code/math.proto
+
+protoc-gen-php -i $interop -o $interop $interop/test.proto
diff --git a/src/php/bin/interop_client.sh b/src/php/bin/interop_client.sh
index 2c61ea8..22e4a49 100755
--- a/src/php/bin/interop_client.sh
+++ b/src/php/bin/interop_client.sh
@@ -31,5 +31,8 @@
 
 set +e
 cd $(dirname $0)
-php -d extension_dir=../ext/grpc/modules/ -d extension=grpc.so \
+
+module_dir=`php --version | grep -q 'PHP 5.6' && echo '../ext/grpc' || echo '../ext/grpc/modules'`
+
+php -d extension_dir=$module_dir -d extension=grpc.so \
   ../tests/interop/interop_client.php $@ 1>&2
diff --git a/src/php/bin/run_tests.sh b/src/php/bin/run_tests.sh
index c3358ed..1335672 100755
--- a/src/php/bin/run_tests.sh
+++ b/src/php/bin/run_tests.sh
@@ -34,13 +34,15 @@
 cd $(dirname $0)
 default_extension_dir=`php -i | grep extension_dir | sed 's/.*=> //g'`
 
+module_dir=`php --version | grep -q 'PHP 5.6' && echo '../ext/grpc' || echo '../ext/grpc/modules'`
+
 # sym-link in system supplied extensions
 for f in $default_extension_dir/*.so
 do
-  ln -s $f ../ext/grpc/modules/$(basename $f) &> /dev/null || true
+  ln -s $f $module_dir/$(basename $f) &> /dev/null || true
 done
 
 php \
-  -d extension_dir=../ext/grpc/modules/ \
+  -d extension_dir=$module_dir \
   -d extension=grpc.so \
   `which phpunit` -v --debug --strict ../tests/unit_tests
diff --git a/src/php/composer.json b/src/php/composer.json
new file mode 100644
index 0000000..3c0cb37
--- /dev/null
+++ b/src/php/composer.json
@@ -0,0 +1,15 @@
+{
+  "name": "grpc/grpc",
+  "description": "gRPC library for PHP",
+  "version": "0.5.0",
+  "homepage": "http://grpc.io",
+  "license": "BSD-3-Clause",
+  "require": {
+    "php": ">=5.5.0"
+  },
+  "autoload": {
+    "psr-4": {
+      "Grpc\\": "lib/Grpc/"
+    }
+  }
+}
diff --git a/src/php/composer.lock b/src/php/composer.lock
new file mode 100644
index 0000000..47fc70f
--- /dev/null
+++ b/src/php/composer.lock
@@ -0,0 +1,19 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "This file is @generated automatically"
+    ],
+    "hash": "65467a098f5fd8b8fe5f7f6e10226f8a",
+    "packages": [],
+    "packages-dev": [],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": {
+        "php": ">=5.5.0"
+    },
+    "platform-dev": []
+}
diff --git a/src/php/ext/grpc/byte_buffer.c b/src/php/ext/grpc/byte_buffer.c
index 1ced1bf..4f3e6b6 100644
--- a/src/php/ext/grpc/byte_buffer.c
+++ b/src/php/ext/grpc/byte_buffer.c
@@ -35,18 +35,18 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
 #include "php_grpc.h"
 
 #include <string.h>
 
 #include "byte_buffer.h"
 
-#include "grpc/grpc.h"
-#include "grpc/support/slice.h"
+#include <grpc/grpc.h>
+#include <grpc/support/slice.h>
 
 grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
   gpr_slice slice = gpr_slice_from_copied_buffer(string, length);
@@ -57,6 +57,11 @@
 
 void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
                            size_t *out_length) {
+  if (buffer == NULL) {
+    *out_string = NULL;
+    *out_length = 0;
+    return;
+  }
   size_t length = grpc_byte_buffer_length(buffer);
   char *string = ecalloc(length + 1, sizeof(char));
   size_t offset = 0;
diff --git a/src/php/ext/grpc/byte_buffer.h b/src/php/ext/grpc/byte_buffer.h
index 7a40638..0e9d1e7 100644
--- a/src/php/ext/grpc/byte_buffer.h
+++ b/src/php/ext/grpc/byte_buffer.h
@@ -34,7 +34,7 @@
 #ifndef NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_
 #define NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_
 
-#include "grpc/grpc.h"
+#include <grpc/grpc.h>
 
 grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length);
 
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 7987471..b1525e9 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -37,23 +37,23 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
 #include "php_grpc.h"
 
-#include "zend_exceptions.h"
-#include "zend_hash.h"
+#include <zend_exceptions.h>
+#include <zend_hash.h>
 
 #include <stdbool.h>
 
-#include "grpc/support/log.h"
-#include "grpc/grpc.h"
+#include <grpc/support/log.h>
+#include <grpc/support/alloc.h>
+#include <grpc/grpc.h>
 
 #include "timeval.h"
 #include "channel.h"
-#include "completion_queue.h"
 #include "byte_buffer.h"
 
 zend_class_entry *grpc_ce_call;
@@ -61,7 +61,19 @@
 /* Frees and destroys an instance of wrapped_grpc_call */
 void free_wrapped_grpc_call(void *object TSRMLS_DC) {
   wrapped_grpc_call *call = (wrapped_grpc_call *)object;
+  grpc_event *event;
   if (call->owned && call->wrapped != NULL) {
+    if (call->queue != NULL) {
+      grpc_completion_queue_shutdown(call->queue);
+      event = grpc_completion_queue_next(call->queue, gpr_inf_future);
+      while (event != NULL) {
+        if (event->type == GRPC_QUEUE_SHUTDOWN) {
+          break;
+        }
+        event = grpc_completion_queue_next(call->queue, gpr_inf_future);
+      }
+      grpc_completion_queue_destroy(call->queue);
+    }
     grpc_call_destroy(call->wrapped);
   }
   efree(call);
@@ -88,17 +100,23 @@
 
 /* Wraps a grpc_call struct in a PHP object. Owned indicates whether the struct
    should be destroyed at the end of the object's lifecycle */
-zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned) {
+zval *grpc_php_wrap_call(grpc_call *wrapped, grpc_completion_queue *queue,
+                         bool owned) {
   zval *call_object;
   MAKE_STD_ZVAL(call_object);
   object_init_ex(call_object, grpc_ce_call);
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC);
   call->wrapped = wrapped;
+  call->queue = queue;
   return call_object;
 }
 
-zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) {
+/* Creates and returns a PHP array object with the data in a
+ * grpc_metadata_array. Returns NULL on failure */
+zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array) {
+  int count = metadata_array->count;
+  grpc_metadata *elements = metadata_array->metadata;
   int i;
   zval *array;
   zval **data = NULL;
@@ -139,6 +157,64 @@
   return array;
 }
 
+/* Populates a grpc_metadata_array with the data in a PHP array object.
+   Returns true on success and false on failure */
+bool create_metadata_array(zval *array, grpc_metadata_array *metadata) {
+  zval **inner_array;
+  zval **value;
+  HashTable *array_hash;
+  HashPosition array_pointer;
+  HashTable *inner_array_hash;
+  HashPosition inner_array_pointer;
+  char *key;
+  uint key_len;
+  ulong index;
+  if (Z_TYPE_P(array) != IS_ARRAY) {
+    return false;
+  }
+  grpc_metadata_array_init(metadata);
+  array_hash = Z_ARRVAL_P(array);
+  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
+       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
+                                     &array_pointer) == SUCCESS;
+       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
+    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
+                                     &array_pointer) != HASH_KEY_IS_STRING) {
+      return false;
+    }
+    if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
+      return false;
+    }
+    inner_array_hash = Z_ARRVAL_P(*inner_array);
+    metadata->capacity += zend_hash_num_elements(inner_array_hash);
+  }
+  metadata->metadata = gpr_malloc(metadata->capacity * sizeof(grpc_metadata));
+  for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
+       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
+                                     &array_pointer) == SUCCESS;
+       zend_hash_move_forward_ex(array_hash, &array_pointer)) {
+    if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
+                                     &array_pointer) != HASH_KEY_IS_STRING) {
+      return false;
+    }
+    inner_array_hash = Z_ARRVAL_P(*inner_array);
+    for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
+                                             &inner_array_pointer);
+         zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
+                                       &inner_array_pointer) == SUCCESS;
+         zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
+      if (Z_TYPE_P(*value) != IS_STRING) {
+        return false;
+      }
+      metadata->metadata[metadata->count].key = key;
+      metadata->metadata[metadata->count].value = Z_STRVAL_P(*value);
+      metadata->metadata[metadata->count].value_length = Z_STRLEN_P(*value);
+      metadata->count += 1;
+    }
+  }
+  return true;
+}
+
 /**
  * Constructs a new instance of the Call class.
  * @param Channel $channel The channel to associate the call with. Must not be
@@ -157,9 +233,10 @@
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO", &channel_obj,
                             grpc_ce_channel, &method, &method_len,
                             &deadline_obj, grpc_ce_timeval) == FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "Call expects a Channel, a String, and a Timeval",
-                         1 TSRMLS_CC);
+    zend_throw_exception(
+        spl_ce_InvalidArgumentException,
+        "Call expects a Channel, a String, and a Timeval",
+        1 TSRMLS_CC);
     return;
   }
   wrapped_grpc_channel *channel =
@@ -175,289 +252,253 @@
   wrapped_grpc_timeval *deadline =
       (wrapped_grpc_timeval *)zend_object_store_get_object(
           deadline_obj TSRMLS_CC);
-  call->wrapped = grpc_channel_create_call_old(
-      channel->wrapped, method, channel->target, deadline->wrapped);
+  call->queue = grpc_completion_queue_create();
+  call->wrapped = grpc_channel_create_call(
+      channel->wrapped, call->queue, method, channel->target,
+      deadline->wrapped);
 }
 
 /**
- * Add metadata to the call. All array keys must be strings. If the value is a
- * string, it is added as a key/value pair. If it is an array, each value is
- * added paired with the same string
- * @param array $metadata The metadata to add
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
+ * Start a batch of RPC actions.
+ * @param array batch Array of actions to take
+ * @return object Object with results of all actions
  */
-PHP_METHOD(Call, add_metadata) {
+PHP_METHOD(Call, startBatch) {
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  grpc_metadata metadata;
-  grpc_call_error error_code;
+  grpc_op ops[8];
+  size_t op_num = 0;
   zval *array;
-  zval **inner_array;
   zval **value;
+  zval **inner_value;
   HashTable *array_hash;
   HashPosition array_pointer;
-  HashTable *inner_array_hash;
-  HashPosition inner_array_pointer;
+  HashTable *status_hash;
   char *key;
   uint key_len;
   ulong index;
-  long flags = 0;
-  /* "a|l" == 1 array, 1 optional long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &flags) ==
+  grpc_metadata_array metadata;
+  grpc_metadata_array trailing_metadata;
+  grpc_metadata_array recv_metadata;
+  grpc_metadata_array recv_trailing_metadata;
+  grpc_status_code status;
+  char *status_details = NULL;
+  size_t status_details_capacity = 0;
+  grpc_byte_buffer *message;
+  int cancelled;
+  grpc_call_error error;
+  grpc_event *event;
+  zval *result;
+  char *message_str;
+  size_t message_len;
+  zval *recv_status;
+  grpc_metadata_array_init(&metadata);
+  grpc_metadata_array_init(&trailing_metadata);
+  grpc_metadata_array_init(&recv_metadata);
+  grpc_metadata_array_init(&recv_trailing_metadata);
+  MAKE_STD_ZVAL(result);
+  object_init(result);
+  /* "a" == 1 array */
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) ==
       FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "add_metadata expects an array and an optional long",
-                         1 TSRMLS_CC);
-    return;
+                         "start_batch expects an array", 1 TSRMLS_CC);
+    goto cleanup;
   }
   array_hash = Z_ARRVAL_P(array);
   for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
-       zend_hash_get_current_data_ex(array_hash, (void**)&inner_array,
+       zend_hash_get_current_data_ex(array_hash, (void**)&value,
                                      &array_pointer) == SUCCESS;
        zend_hash_move_forward_ex(array_hash, &array_pointer)) {
     if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
-                                     &array_pointer) != HASH_KEY_IS_STRING) {
+                                     &array_pointer) != HASH_KEY_IS_LONG) {
       zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "metadata keys must be strings", 1 TSRMLS_CC);
-      return;
+                           "batch keys must be integers", 1 TSRMLS_CC);
+      goto cleanup;
     }
-    if (Z_TYPE_P(*inner_array) != IS_ARRAY) {
-      zend_throw_exception(spl_ce_InvalidArgumentException,
-                           "metadata values must be arrays",
-                           1 TSRMLS_CC);
-      return;
-    }
-    inner_array_hash = Z_ARRVAL_P(*inner_array);
-    for (zend_hash_internal_pointer_reset_ex(inner_array_hash,
-                                             &inner_array_pointer);
-         zend_hash_get_current_data_ex(inner_array_hash, (void**)&value,
-                                       &inner_array_pointer) == SUCCESS;
-         zend_hash_move_forward_ex(inner_array_hash, &inner_array_pointer)) {
-      if (Z_TYPE_P(*value) != IS_STRING) {
+    switch(index) {
+      case GRPC_OP_SEND_INITIAL_METADATA:
+        if (!create_metadata_array(*value, &metadata)) {
+          zend_throw_exception(spl_ce_InvalidArgumentException,
+                               "Bad metadata value given", 1 TSRMLS_CC);
+          goto cleanup;
+        }
+        ops[op_num].data.send_initial_metadata.count =
+            metadata.count;
+        ops[op_num].data.send_initial_metadata.metadata =
+            metadata.metadata;
+        break;
+      case GRPC_OP_SEND_MESSAGE:
+        if (Z_TYPE_PP(value) != IS_STRING) {
+          zend_throw_exception(spl_ce_InvalidArgumentException,
+                               "Expected a string for send message",
+                               1 TSRMLS_CC);
+        }
+        ops[op_num].data.send_message =
+            string_to_byte_buffer(Z_STRVAL_PP(value), Z_STRLEN_PP(value));
+        break;
+      case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+        break;
+      case GRPC_OP_SEND_STATUS_FROM_SERVER:
+        status_hash = Z_ARRVAL_PP(value);
+        if (zend_hash_find(status_hash, "metadata", sizeof("metadata"),
+                           (void **)&inner_value) == SUCCESS) {
+          if (!create_metadata_array(*inner_value, &trailing_metadata)) {
+            zend_throw_exception(spl_ce_InvalidArgumentException,
+                                 "Bad trailing metadata value given",
+                                 1 TSRMLS_CC);
+            goto cleanup;
+          }
+          ops[op_num].data.send_status_from_server.trailing_metadata =
+              trailing_metadata.metadata;
+          ops[op_num].data.send_status_from_server.trailing_metadata_count =
+              trailing_metadata.count;
+        }
+        if (zend_hash_find(status_hash, "code", sizeof("code"),
+                           (void**)&inner_value) == SUCCESS) {
+          if (Z_TYPE_PP(inner_value) != IS_LONG) {
+            zend_throw_exception(spl_ce_InvalidArgumentException,
+                                 "Status code must be an integer",
+                                 1 TSRMLS_CC);
+            goto cleanup;
+          }
+          ops[op_num].data.send_status_from_server.status =
+              Z_LVAL_PP(inner_value);
+        } else {
+          zend_throw_exception(spl_ce_InvalidArgumentException,
+                               "Integer status code is required",
+                               1 TSRMLS_CC);
+          goto cleanup;
+        }
+        if (zend_hash_find(status_hash, "details", sizeof("details"),
+                           (void**)&inner_value) == SUCCESS) {
+          if (Z_TYPE_PP(inner_value) != IS_STRING) {
+            zend_throw_exception(spl_ce_InvalidArgumentException,
+                                 "Status details must be a string",
+                                 1 TSRMLS_CC);
+            goto cleanup;
+          }
+          ops[op_num].data.send_status_from_server.status_details =
+              Z_STRVAL_PP(inner_value);
+        } else {
+          zend_throw_exception(spl_ce_InvalidArgumentException,
+                               "String status details is required",
+                               1 TSRMLS_CC);
+          goto cleanup;
+        }
+        break;
+      case GRPC_OP_RECV_INITIAL_METADATA:
+        ops[op_num].data.recv_initial_metadata = &recv_metadata;
+        break;
+      case GRPC_OP_RECV_MESSAGE:
+        ops[op_num].data.recv_message = &message;
+        break;
+      case GRPC_OP_RECV_STATUS_ON_CLIENT:
+        ops[op_num].data.recv_status_on_client.trailing_metadata =
+            &recv_trailing_metadata;
+        ops[op_num].data.recv_status_on_client.status = &status;
+        ops[op_num].data.recv_status_on_client.status_details =
+            &status_details;
+        ops[op_num].data.recv_status_on_client.status_details_capacity =
+            &status_details_capacity;
+        break;
+      case GRPC_OP_RECV_CLOSE_ON_SERVER:
+        ops[op_num].data.recv_close_on_server.cancelled = &cancelled;
+        break;
+      default:
         zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "metadata values must be arrays of strings",
-                             1 TSRMLS_CC);
-        return;
-      }
-      metadata.key = key;
-      metadata.value = Z_STRVAL_P(*value);
-      metadata.value_length = Z_STRLEN_P(*value);
-      error_code = grpc_call_add_metadata_old(call->wrapped, &metadata, 0u);
-      MAYBE_THROW_CALL_ERROR(add_metadata, error_code);
+                             "Unrecognized key in batch", 1 TSRMLS_CC);
+        goto cleanup;
+    }
+    ops[op_num].op = (grpc_op_type)index;
+    op_num++;
+  }
+  error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped);
+  if (error != GRPC_CALL_OK) {
+    zend_throw_exception(spl_ce_LogicException,
+                         "start_batch was called incorrectly",
+                         (long)error TSRMLS_CC);
+    goto cleanup;
+  }
+  event = grpc_completion_queue_pluck(call->queue, call->wrapped,
+                                      gpr_inf_future);
+  if (event->data.op_complete != GRPC_OP_OK) {
+    zend_throw_exception(spl_ce_LogicException,
+                         "The batch failed for some reason",
+                         1 TSRMLS_CC);
+    goto cleanup;
+  }
+  for (int i = 0; i < op_num; i++) {
+    switch(ops[i].op) {
+      case GRPC_OP_SEND_INITIAL_METADATA:
+        add_property_bool(result, "send_metadata", true);
+        break;
+      case GRPC_OP_SEND_MESSAGE:
+        add_property_bool(result, "send_message", true);
+        break;
+      case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+        add_property_bool(result, "send_close", true);
+        break;
+      case GRPC_OP_SEND_STATUS_FROM_SERVER:
+        add_property_bool(result, "send_status", true);
+        break;
+      case GRPC_OP_RECV_INITIAL_METADATA:
+        array = grpc_parse_metadata_array(&recv_metadata);
+        add_property_zval(result, "metadata", array);
+        Z_DELREF_P(array);
+        break;
+      case GRPC_OP_RECV_MESSAGE:
+        byte_buffer_to_string(message, &message_str, &message_len);
+        if (message_str == NULL) {
+          add_property_null(result, "message");
+        } else {
+          add_property_stringl(result, "message", message_str, message_len,
+                               false);
+        }
+        break;
+      case GRPC_OP_RECV_STATUS_ON_CLIENT:
+        MAKE_STD_ZVAL(recv_status);
+        object_init(recv_status);
+        array = grpc_parse_metadata_array(&recv_trailing_metadata);
+        add_property_zval(recv_status, "metadata", array);
+        Z_DELREF_P(array);
+        add_property_long(recv_status, "code", status);
+        add_property_string(recv_status, "details", status_details, true);
+        add_property_zval(result, "status", recv_status);
+        Z_DELREF_P(recv_status);
+        break;
+      case GRPC_OP_RECV_CLOSE_ON_SERVER:
+        add_property_bool(result, "cancelled", cancelled);
+        break;
+      default:
+        break;
     }
   }
+cleanup:
+  grpc_metadata_array_destroy(&metadata);
+  grpc_metadata_array_destroy(&trailing_metadata);
+  grpc_metadata_array_destroy(&recv_metadata);
+  grpc_metadata_array_destroy(&recv_trailing_metadata);
+  if (status_details != NULL) {
+    gpr_free(status_details);
+  }
+  RETURN_DESTROY_ZVAL(result);
 }
 
 /**
- * Invoke the RPC. Starts sending metadata and request headers over the wire
- * @param CompletionQueue $queue The completion queue to use with this call
- * @param long $metadata_tag The tag to associate with returned metadata
- * @param long $finished_tag The tag to associate with the finished event
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
- */
-PHP_METHOD(Call, invoke) {
-  grpc_call_error error_code;
-  long tag1;
-  long tag2;
-  zval *queue_obj;
-  long flags = 0;
-  /* "Oll|l" == 1 Object, 3 mandatory longs, 1 optional long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oll|l", &queue_obj,
-                            grpc_ce_completion_queue, &tag1, &tag2,
-                            &flags) == FAILURE) {
-    zend_throw_exception(
-        spl_ce_InvalidArgumentException,
-        "invoke needs a CompletionQueue, 2 longs, and an optional long",
-        1 TSRMLS_CC);
-    return;
-  }
-  add_property_zval(getThis(), "completion_queue", queue_obj);
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  wrapped_grpc_completion_queue *queue =
-      (wrapped_grpc_completion_queue *)zend_object_store_get_object(
-          queue_obj TSRMLS_CC);
-  error_code = grpc_call_invoke_old(call->wrapped, queue->wrapped, (void *)tag1,
-                                    (void *)tag2, (gpr_uint32)flags);
-  MAYBE_THROW_CALL_ERROR(invoke, error_code);
-}
-
-/**
- * Accept an incoming RPC, binding a completion queue to it. To be called after
- * adding metadata to the call, but before sending messages. Can only be called
- * on the server
- * @param CompletionQueue $queue The completion queue to use with this call
- * @param long $finished_tag The tag to associate with the finished event
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
- */
-PHP_METHOD(Call, server_accept) {
-  long tag;
-  zval *queue_obj;
-  grpc_call_error error_code;
-  /* "Ol|l" == 1 Object, 1 long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &queue_obj,
-                            grpc_ce_completion_queue, &tag) == FAILURE) {
-    zend_throw_exception(
-        spl_ce_InvalidArgumentException,
-        "server_accept expects a CompletionQueue, a long, and an optional long",
-        1 TSRMLS_CC);
-    return;
-  }
-  add_property_zval(getThis(), "completion_queue", queue_obj);
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  wrapped_grpc_completion_queue *queue =
-      (wrapped_grpc_completion_queue *)zend_object_store_get_object(
-          queue_obj TSRMLS_CC);
-  error_code =
-      grpc_call_server_accept_old(call->wrapped, queue->wrapped, (void *)tag);
-  MAYBE_THROW_CALL_ERROR(server_accept, error_code);
-}
-
-PHP_METHOD(Call, server_end_initial_metadata) {
-  grpc_call_error error_code;
-  long flags = 0;
-  /* "|l" == 1 optional long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) ==
-      FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "server_end_initial_metadata expects an optional long",
-                         1 TSRMLS_CC);
-  }
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  error_code = grpc_call_server_end_initial_metadata_old(call->wrapped, flags);
-  MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code);
-}
-
-/**
- * Called by clients to cancel an RPC on the server.
- * @return Void
+ * Cancel the call. This will cause the call to end with STATUS_CANCELLED if it
+ * has not already ended with another status.
  */
 PHP_METHOD(Call, cancel) {
   wrapped_grpc_call *call =
       (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  grpc_call_error error_code = grpc_call_cancel(call->wrapped);
-  MAYBE_THROW_CALL_ERROR(cancel, error_code);
-}
-
-/**
- * Queue a byte buffer for writing
- * @param string $buffer The buffer to queue for writing
- * @param long $tag The tag to associate with this write
- * @param long $flags A bitwise combination of the Grpc\WRITE_* constants
- * (optional)
- * @return Void
- */
-PHP_METHOD(Call, start_write) {
-  grpc_call_error error_code;
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  char *buffer;
-  int buffer_len;
-  long tag;
-  long flags = 0;
-  /* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &buffer,
-                            &buffer_len, &tag, &flags) == FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "start_write expects a string and an optional long",
-                         1 TSRMLS_CC);
-    return;
-  }
-  error_code = grpc_call_start_write_old(
-      call->wrapped, string_to_byte_buffer(buffer, buffer_len), (void *)tag,
-      (gpr_uint32)flags);
-  MAYBE_THROW_CALL_ERROR(start_write, error_code);
-}
-
-/**
- * Queue a status for writing
- * @param long $status_code The status code to send
- * @param string $status_details The status details to send
- * @param long $tag The tag to associate with this status
- * @return Void
- */
-PHP_METHOD(Call, start_write_status) {
-  grpc_call_error error_code;
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  long status_code;
-  int status_details_length;
-  long tag;
-  char *status_details;
-  /* "lsl" == 1 long, 1 string, 1 long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &status_code,
-                            &status_details, &status_details_length,
-                            &tag) == FAILURE) {
-    zend_throw_exception(
-        spl_ce_InvalidArgumentException,
-        "start_write_status expects a long, a string, and a long", 1 TSRMLS_CC);
-    return;
-  }
-  error_code = grpc_call_start_write_status_old(call->wrapped,
-                                                (grpc_status_code)status_code,
-                                                status_details, (void *)tag);
-  MAYBE_THROW_CALL_ERROR(start_write_status, error_code);
-}
-
-/**
- * Indicate that there are no more messages to send
- * @return Void
- */
-PHP_METHOD(Call, writes_done) {
-  grpc_call_error error_code;
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  long tag;
-  /* "l" == 1 long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "writes_done expects a long", 1 TSRMLS_CC);
-    return;
-  }
-  error_code = grpc_call_writes_done_old(call->wrapped, (void *)tag);
-  MAYBE_THROW_CALL_ERROR(writes_done, error_code);
-}
-
-/**
- * Initiate a read on a call. Output event contains a byte buffer with the
- * result of the read
- * @param long $tag The tag to associate with this read
- * @return Void
- */
-PHP_METHOD(Call, start_read) {
-  grpc_call_error error_code;
-  wrapped_grpc_call *call =
-      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  long tag;
-  /* "l" == 1 long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "start_read expects a long", 1 TSRMLS_CC);
-    return;
-  }
-  error_code = grpc_call_start_read_old(call->wrapped, (void *)tag);
-  MAYBE_THROW_CALL_ERROR(start_read, error_code);
+  grpc_call_cancel(call->wrapped);
 }
 
 static zend_function_entry call_methods[] = {
     PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Call, server_accept, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, invoke, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, start_read, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, start_write_status, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, writes_done, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+    PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
 
 void grpc_init_call(TSRMLS_D) {
   zend_class_entry ce;
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index bce5d82..e7eb9a7 100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -38,23 +38,12 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
 #include "php_grpc.h"
 
-#include "grpc/grpc.h"
-
-// Throw an exception if error_code is not OK
-#define MAYBE_THROW_CALL_ERROR(func_name, error_code)            \
-  do {                                                           \
-    if (error_code != GRPC_CALL_OK) {                            \
-      zend_throw_exception(spl_ce_LogicException,                \
-                           #func_name " was called incorrectly", \
-                           (long)error_code TSRMLS_CC);          \
-      return;                                                    \
-    }                                                            \
-  } while (0)
+#include <grpc/grpc.h>
 
 /* Class entry for the Call PHP class */
 extern zend_class_entry *grpc_ce_call;
@@ -65,16 +54,18 @@
 
   bool owned;
   grpc_call *wrapped;
+  grpc_completion_queue *queue;
 } wrapped_grpc_call;
 
 /* Initializes the Call PHP class */
 void grpc_init_call(TSRMLS_D);
 
 /* Creates a Call object that wraps the given grpc_call struct */
-zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned);
+zval *grpc_php_wrap_call(grpc_call *wrapped, grpc_completion_queue *queue,
+                         bool owned);
 
 /* Creates and returns a PHP associative array of metadata from a C array of
  * call metadata */
-zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements);
+zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array);
 
 #endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 5e99332..b8262db 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -37,21 +37,20 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
 #include "php_grpc.h"
 
-#include "zend_exceptions.h"
+#include <zend_exceptions.h>
 
 #include <stdbool.h>
 
-#include "grpc/grpc.h"
-#include "grpc/support/log.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/grpc_security.h>
 
-#include "completion_queue.h"
 #include "server.h"
 #include "credentials.h"
 
@@ -63,6 +62,7 @@
   if (channel->wrapped != NULL) {
     grpc_channel_destroy(channel->wrapped);
   }
+  efree(channel->target);
   efree(channel);
 }
 
@@ -139,6 +139,9 @@
   HashTable *array_hash;
   zval **creds_obj = NULL;
   wrapped_grpc_credentials *creds = NULL;
+  zval **override_obj;
+  char *override;
+  int override_len;
   /* "s|a" == 1 string, 1 optional array */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target,
                             &target_length, &args_array) == FAILURE) {
@@ -146,6 +149,8 @@
                          "Channel expects a string and an array", 1 TSRMLS_CC);
     return;
   }
+  override = target;
+  override_len = target_length;
   if (args_array == NULL) {
     channel->wrapped = grpc_channel_create(target, NULL);
   } else {
@@ -162,6 +167,19 @@
           *creds_obj TSRMLS_CC);
       zend_hash_del(array_hash, "credentials", 12);
     }
+    if (zend_hash_find(array_hash, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
+                       sizeof(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
+                       (void **)&override_obj) == SUCCESS) {
+      if (Z_TYPE_PP(override_obj) != IS_STRING) {
+        zend_throw_exception(spl_ce_InvalidArgumentException,
+                             GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
+                             " must be a string",
+                             1 TSRMLS_CC);
+        return;
+      }
+      override = Z_STRVAL_PP(override_obj);
+      override_len = Z_STRLEN_PP(override_obj);
+    }
     php_grpc_read_args_array(args_array, &args);
     if (creds == NULL) {
       channel->wrapped = grpc_channel_create(target, &args);
@@ -172,8 +190,8 @@
     }
     efree(args.args);
   }
-  channel->target = ecalloc(target_length + 1, sizeof(char));
-  memcpy(channel->target, target, target_length);
+  channel->target = ecalloc(override_len + 1, sizeof(char));
+  memcpy(channel->target, override, override_len);
 }
 
 /**
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index 2c79668..c13fa4c 100755
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -38,12 +38,12 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
 #include "php_grpc.h"
 
-#include "grpc/grpc.h"
+#include <grpc/grpc.h>
 
 /* Class entry for the PHP Channel class */
 extern zend_class_entry *grpc_ce_channel;
diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c
deleted file mode 100644
index 93abf5d..0000000
--- a/src/php/ext/grpc/completion_queue.c
+++ /dev/null
@@ -1,170 +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.
- *
- */
-
-#include "completion_queue.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
-#include "php_grpc.h"
-
-#include "zend_exceptions.h"
-
-#include <stdbool.h>
-
-#include "grpc/grpc.h"
-
-#include "event.h"
-#include "timeval.h"
-
-zend_class_entry *grpc_ce_completion_queue;
-
-/* Frees and destroys a wrapped instance of grpc_completion_queue */
-void free_wrapped_grpc_completion_queue(void *object TSRMLS_DC) {
-  wrapped_grpc_completion_queue *queue = NULL;
-  grpc_event *event;
-  queue = (wrapped_grpc_completion_queue *)object;
-  if (queue->wrapped != NULL) {
-    grpc_completion_queue_shutdown(queue->wrapped);
-    event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
-    while (event != NULL) {
-      if (event->type == GRPC_QUEUE_SHUTDOWN) {
-        break;
-      }
-      event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
-    }
-    grpc_completion_queue_destroy(queue->wrapped);
-  }
-  efree(queue);
-}
-
-/* Initializes an instance of wrapped_grpc_channel to be associated with an
- * object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_completion_queue(
-    zend_class_entry *class_type TSRMLS_DC) {
-  zend_object_value retval;
-  wrapped_grpc_completion_queue *intern;
-
-  intern = (wrapped_grpc_completion_queue *)emalloc(
-      sizeof(wrapped_grpc_completion_queue));
-  memset(intern, 0, sizeof(wrapped_grpc_completion_queue));
-
-  zend_object_std_init(&intern->std, class_type TSRMLS_CC);
-  object_properties_init(&intern->std, class_type);
-  retval.handle = zend_objects_store_put(
-      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_completion_queue, NULL TSRMLS_CC);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
-}
-
-/**
- * Construct an instance of CompletionQueue
- */
-PHP_METHOD(CompletionQueue, __construct) {
-  wrapped_grpc_completion_queue *queue =
-      (wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
-                                                                    TSRMLS_CC);
-  queue->wrapped = grpc_completion_queue_create();
-}
-
-/**
- * Blocks until an event is available, the completion queue is being shutdown,
- * or timeout is reached. Returns NULL on timeout, otherwise the event that
- * occurred. Callers should call event.finish once they have processed the
- * event.
- * @param Timeval $timeout The timeout for the event
- * @return Event The event that occurred
- */
-PHP_METHOD(CompletionQueue, next) {
-  zval *timeout;
-  /* "O" == 1 Object */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &timeout,
-                            grpc_ce_timeval) == FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "next needs a Timeval", 1 TSRMLS_CC);
-    return;
-  }
-  wrapped_grpc_completion_queue *completion_queue =
-      (wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
-                                                                    TSRMLS_CC);
-  wrapped_grpc_timeval *wrapped_timeout =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
-  grpc_event *event = grpc_completion_queue_next(completion_queue->wrapped,
-                                                 wrapped_timeout->wrapped);
-  if (event == NULL) {
-    RETURN_NULL();
-  }
-  zval *wrapped_event = grpc_php_convert_event(event);
-  RETURN_DESTROY_ZVAL(wrapped_event);
-}
-
-PHP_METHOD(CompletionQueue, pluck) {
-  long tag;
-  zval *timeout;
-  /* "lO" == 1 long, 1 Object */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO", &tag, &timeout,
-                            grpc_ce_timeval) == FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "pluck needs a long and a Timeval", 1 TSRMLS_CC);
-  }
-  wrapped_grpc_completion_queue *completion_queue =
-      (wrapped_grpc_completion_queue *)zend_object_store_get_object(getThis()
-                                                                    TSRMLS_CC);
-  wrapped_grpc_timeval *wrapped_timeout =
-      (wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
-  grpc_event *event = grpc_completion_queue_pluck(
-      completion_queue->wrapped, (void *)tag, wrapped_timeout->wrapped);
-  if (event == NULL) {
-    RETURN_NULL();
-  }
-  zval *wrapped_event = grpc_php_convert_event(event);
-  RETURN_DESTROY_ZVAL(wrapped_event);
-}
-
-static zend_function_entry completion_queue_methods[] = {
-    PHP_ME(CompletionQueue, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(CompletionQueue, next, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(CompletionQueue, pluck, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
-
-void grpc_init_completion_queue(TSRMLS_D) {
-  zend_class_entry ce;
-  INIT_CLASS_ENTRY(ce, "Grpc\\CompletionQueue", completion_queue_methods);
-  ce.create_object = create_wrapped_grpc_completion_queue;
-  grpc_ce_completion_queue = zend_register_internal_class(&ce TSRMLS_CC);
-}
diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4
index 27c6778..11778e3 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -66,5 +66,5 @@
 
   PHP_SUBST(GRPC_SHARED_LIBADD)
 
-  PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c completion_queue.c credentials.c event.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99)
+  PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -std=c11)
 fi
diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c
index a94b0ea..a262b99 100644
--- a/src/php/ext/grpc/credentials.c
+++ b/src/php/ext/grpc/credentials.c
@@ -37,17 +37,17 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
 #include "php_grpc.h"
 
-#include "zend_exceptions.h"
-#include "zend_hash.h"
+#include <zend_exceptions.h>
+#include <zend_hash.h>
 
-#include "grpc/grpc.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_credentials;
 
diff --git a/src/php/ext/grpc/event.c b/src/php/ext/grpc/event.c
deleted file mode 100644
index 452c4b8..0000000
--- a/src/php/ext/grpc/event.c
+++ /dev/null
@@ -1,150 +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.
- *
- */
-
-#include "event.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
-
-#include <stdbool.h>
-
-#include "grpc/grpc.h"
-
-#include "byte_buffer.h"
-#include "call.h"
-#include "timeval.h"
-
-/* Create a new PHP object containing the event data in the event struct.
-   event must not be used after this function is called */
-zval *grpc_php_convert_event(grpc_event *event) {
-  zval *data_object;
-  char *detail_string;
-  size_t detail_len;
-  char *method_string;
-  size_t method_len;
-  char *host_string;
-  size_t host_len;
-  char *read_string;
-  size_t read_len;
-
-  zval *event_object;
-
-  if (event == NULL) {
-    return NULL;
-  }
-
-  MAKE_STD_ZVAL(event_object);
-  object_init(event_object);
-
-  add_property_zval(
-      event_object, "call",
-      grpc_php_wrap_call(event->call, event->type == GRPC_SERVER_RPC_NEW));
-  add_property_long(event_object, "type", event->type);
-  add_property_long(event_object, "tag", (long)event->tag);
-
-  switch (event->type) {
-    case GRPC_QUEUE_SHUTDOWN:
-      add_property_null(event_object, "data");
-      break;
-    case GRPC_READ:
-      if (event->data.read == NULL) {
-        add_property_null(event_object, "data");
-      } else {
-        byte_buffer_to_string(event->data.read, &read_string, &read_len);
-        add_property_stringl(event_object, "data", read_string, read_len, true);
-      }
-      break;
-    case GRPC_WRITE_ACCEPTED:
-      add_property_long(event_object, "data", (long)event->data.write_accepted);
-      break;
-    case GRPC_FINISH_ACCEPTED:
-      add_property_long(event_object, "data",
-                        (long)event->data.finish_accepted);
-      break;
-    case GRPC_CLIENT_METADATA_READ:
-      data_object = grpc_call_create_metadata_array(
-          event->data.client_metadata_read.count,
-          event->data.client_metadata_read.elements);
-      add_property_zval(event_object, "data", data_object);
-      break;
-    case GRPC_FINISHED:
-      MAKE_STD_ZVAL(data_object);
-      object_init(data_object);
-      add_property_long(data_object, "code", event->data.finished.status);
-      if (event->data.finished.details == NULL) {
-        add_property_null(data_object, "details");
-      } else {
-        detail_len = strlen(event->data.finished.details);
-        detail_string = ecalloc(detail_len + 1, sizeof(char));
-        memcpy(detail_string, event->data.finished.details, detail_len);
-        add_property_string(data_object, "details", detail_string, true);
-      }
-      add_property_zval(data_object, "metadata",
-                        grpc_call_create_metadata_array(
-                            event->data.finished.metadata_count,
-                            event->data.finished.metadata_elements));
-      add_property_zval(event_object, "data", data_object);
-      break;
-    case GRPC_SERVER_RPC_NEW:
-      MAKE_STD_ZVAL(data_object);
-      object_init(data_object);
-      method_len = strlen(event->data.server_rpc_new.method);
-      method_string = ecalloc(method_len + 1, sizeof(char));
-      memcpy(method_string, event->data.server_rpc_new.method, method_len);
-      add_property_string(data_object, "method", method_string, false);
-      host_len = strlen(event->data.server_rpc_new.host);
-      host_string = ecalloc(host_len + 1, sizeof(char));
-      memcpy(host_string, event->data.server_rpc_new.host, host_len);
-      add_property_string(data_object, "host", host_string, false);
-      add_property_zval(
-          data_object, "absolute_timeout",
-          grpc_php_wrap_timeval(event->data.server_rpc_new.deadline));
-      add_property_zval(data_object, "metadata",
-                        grpc_call_create_metadata_array(
-                            event->data.server_rpc_new.metadata_count,
-                            event->data.server_rpc_new.metadata_elements));
-      add_property_zval(event_object, "data", data_object);
-      break;
-    default:
-      add_property_null(event_object, "data");
-      break;
-  }
-  grpc_event_finish(event);
-  return event_object;
-}
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index 67e366c..3e669ec 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -34,8 +34,6 @@
 #include "call.h"
 #include "channel.h"
 #include "server.h"
-#include "completion_queue.h"
-#include "event.h"
 #include "timeval.h"
 #include "credentials.h"
 #include "server_credentials.h"
@@ -44,9 +42,9 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
 #include "php_grpc.h"
 
 // ZEND_DECLARE_MODULE_GLOBALS(grpc)
@@ -127,27 +125,12 @@
   REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
                          GRPC_CALL_ERROR_INVALID_FLAGS, CONST_CS);
 
-  /* Register op error constants */
-  REGISTER_LONG_CONSTANT("Grpc\\OP_OK", GRPC_OP_OK, CONST_CS);
-  REGISTER_LONG_CONSTANT("Grpc\\OP_ERROR", GRPC_OP_ERROR, CONST_CS);
-
   /* Register flag constants */
   REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", GRPC_WRITE_BUFFER_HINT,
                          CONST_CS);
   REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", GRPC_WRITE_NO_COMPRESS,
                          CONST_CS);
 
-  /* Register completion type constants */
-  REGISTER_LONG_CONSTANT("Grpc\\QUEUE_SHUTDOWN", GRPC_QUEUE_SHUTDOWN, CONST_CS);
-  REGISTER_LONG_CONSTANT("Grpc\\READ", GRPC_READ, CONST_CS);
-  REGISTER_LONG_CONSTANT("Grpc\\FINISH_ACCEPTED", GRPC_FINISH_ACCEPTED,
-                         CONST_CS);
-  REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", GRPC_WRITE_ACCEPTED, CONST_CS);
-  REGISTER_LONG_CONSTANT("Grpc\\CLIENT_METADATA_READ",
-                         GRPC_CLIENT_METADATA_READ, CONST_CS);
-  REGISTER_LONG_CONSTANT("Grpc\\FINISHED", GRPC_FINISHED, CONST_CS);
-  REGISTER_LONG_CONSTANT("Grpc\\SERVER_RPC_NEW", GRPC_SERVER_RPC_NEW, CONST_CS);
-
   /* Register status constants */
   REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK, CONST_CS);
   REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", GRPC_STATUS_CANCELLED,
@@ -181,10 +164,27 @@
   REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS,
                          CONST_CS);
 
+  /* Register op type constants */
+  REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_INITIAL_METADATA",
+                         GRPC_OP_SEND_INITIAL_METADATA, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_MESSAGE",
+                         GRPC_OP_SEND_MESSAGE, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_CLOSE_FROM_CLIENT",
+                         GRPC_OP_SEND_CLOSE_FROM_CLIENT, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_STATUS_FROM_SERVER",
+                         GRPC_OP_SEND_STATUS_FROM_SERVER, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_INITIAL_METADATA",
+                         GRPC_OP_RECV_INITIAL_METADATA, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE",
+                         GRPC_OP_RECV_MESSAGE, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT",
+                         GRPC_OP_RECV_STATUS_ON_CLIENT, CONST_CS);
+  REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
+                         GRPC_OP_RECV_CLOSE_ON_SERVER, CONST_CS);
+
   grpc_init_call(TSRMLS_C);
   grpc_init_channel(TSRMLS_C);
   grpc_init_server(TSRMLS_C);
-  grpc_init_completion_queue(TSRMLS_C);
   grpc_init_timeval(TSRMLS_C);
   grpc_init_credentials(TSRMLS_C);
   grpc_init_server_credentials(TSRMLS_C);
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index a5cfd95..dbb9425 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -37,30 +37,42 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
 #include "php_grpc.h"
 
-#include "zend_exceptions.h"
+#include <zend_exceptions.h>
 
 #include <stdbool.h>
 
-#include "grpc/grpc.h"
-#include "grpc/support/log.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/grpc_security.h>
 
 #include "server.h"
-#include "completion_queue.h"
 #include "channel.h"
 #include "server_credentials.h"
+#include "timeval.h"
 
 zend_class_entry *grpc_ce_server;
 
 /* Frees and destroys an instance of wrapped_grpc_server */
 void free_wrapped_grpc_server(void *object TSRMLS_DC) {
   wrapped_grpc_server *server = (wrapped_grpc_server *)object;
+  grpc_event *event;
+  if (server->queue != NULL) {
+    grpc_completion_queue_shutdown(server->queue);
+    event = grpc_completion_queue_next(server->queue, gpr_inf_future);
+    while (event != NULL) {
+      if (event->type == GRPC_QUEUE_SHUTDOWN) {
+        break;
+      }
+      event = grpc_completion_queue_next(server->queue, gpr_inf_future);
+    }
+    grpc_completion_queue_destroy(server->queue);
+  }
   if (server->wrapped != NULL) {
     grpc_server_shutdown(server->wrapped);
     grpc_server_destroy(server->wrapped);
@@ -95,26 +107,22 @@
 PHP_METHOD(Server, __construct) {
   wrapped_grpc_server *server =
       (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  zval *queue_obj;
   zval *args_array = NULL;
   grpc_channel_args args;
-  /* "O|a" == 1 Object, 1 optional array */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a", &queue_obj,
-                            grpc_ce_completion_queue, &args_array) == FAILURE) {
+  /* "|a" == 1 optional array */
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &args_array) ==
+      FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "Server expects a CompletionQueue and an array",
+                         "Server expects an array",
                          1 TSRMLS_CC);
     return;
   }
-  add_property_zval(getThis(), "completion_queue", queue_obj);
-  wrapped_grpc_completion_queue *queue =
-      (wrapped_grpc_completion_queue *)zend_object_store_get_object(
-          queue_obj TSRMLS_CC);
+  server->queue = grpc_completion_queue_create();
   if (args_array == NULL) {
-    server->wrapped = grpc_server_create(queue->wrapped, NULL);
+    server->wrapped = grpc_server_create(server->queue, NULL);
   } else {
     php_grpc_read_args_array(args_array, &args);
-    server->wrapped = grpc_server_create(queue->wrapped, &args);
+    server->wrapped = grpc_server_create(server->queue, &args);
     efree(args.args);
   }
 }
@@ -125,20 +133,44 @@
  * @param long $tag_cancel The tag to use if the call is cancelled
  * @return Void
  */
-PHP_METHOD(Server, request_call) {
+PHP_METHOD(Server, requestCall) {
   grpc_call_error error_code;
   wrapped_grpc_server *server =
       (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
-  long tag_new;
-  /* "l" == 1 long */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag_new) ==
-      FAILURE) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "request_call expects a long", 1 TSRMLS_CC);
-    return;
+  grpc_call *call;
+  grpc_call_details details;
+  grpc_metadata_array metadata;
+  zval *result;
+  grpc_event *event;
+  MAKE_STD_ZVAL(result);
+  object_init(result);
+  grpc_call_details_init(&details);
+  grpc_metadata_array_init(&metadata);
+  error_code = grpc_server_request_call(server->wrapped, &call, &details,
+                                        &metadata, server->queue, NULL);
+  if (error_code != GRPC_CALL_OK) {
+    zend_throw_exception(spl_ce_LogicException, "request_call failed",
+                         (long)error_code TSRMLS_CC);
+    goto cleanup;
   }
-  error_code = grpc_server_request_call_old(server->wrapped, (void *)tag_new);
-  MAYBE_THROW_CALL_ERROR(request_call, error_code);
+  event = grpc_completion_queue_pluck(server->queue, NULL, gpr_inf_future);
+  if (event->data.op_complete != GRPC_OP_OK) {
+    zend_throw_exception(spl_ce_LogicException,
+                         "Failed to request a call for some reason",
+                         1 TSRMLS_CC);
+    goto cleanup;
+  }
+  add_property_zval(result, "call", grpc_php_wrap_call(call, server->queue,
+                                                       true));
+  add_property_string(result, "method", details.method, true);
+  add_property_string(result, "host", details.host, true);
+  add_property_zval(result, "absolute_deadline",
+                    grpc_php_wrap_timeval(details.deadline));
+  add_property_zval(result, "metadata", grpc_parse_metadata_array(&metadata));
+cleanup:
+  grpc_call_details_destroy(&details);
+  grpc_metadata_array_destroy(&metadata);
+  RETURN_DESTROY_ZVAL(result);
 }
 
 /**
@@ -146,7 +178,7 @@
  * @param string $addr The address to add
  * @return true on success, false on failure
  */
-PHP_METHOD(Server, add_http2_port) {
+PHP_METHOD(Server, addHttp2Port) {
   wrapped_grpc_server *server =
       (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
   const char *addr;
@@ -161,14 +193,14 @@
   RETURN_LONG(grpc_server_add_http2_port(server->wrapped, addr));
 }
 
-PHP_METHOD(Server, add_secure_http2_port) {
+PHP_METHOD(Server, addSecureHttp2Port) {
   wrapped_grpc_server *server =
       (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
   const char *addr;
   int addr_len;
   zval *creds_obj;
   /* "sO" == 1 string, 1 object */
-  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len,
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO", &addr, &addr_len,
                             &creds_obj, grpc_ce_server_credentials) ==
       FAILURE) {
     zend_throw_exception(
@@ -195,9 +227,9 @@
 
 static zend_function_entry server_methods[] = {
     PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Server, request_call, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Server, add_http2_port, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Server, add_secure_http2_port, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Server, requestCall, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Server, addHttp2Port, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Server, addSecureHttp2Port, NULL, ZEND_ACC_PUBLIC)
     PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
 
 void grpc_init_server(TSRMLS_D) {
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
index b55689c..a2ee2ff 100755
--- a/src/php/ext/grpc/server.h
+++ b/src/php/ext/grpc/server.h
@@ -38,12 +38,12 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
 #include "php_grpc.h"
 
-#include "grpc/grpc.h"
+#include <grpc/grpc.h>
 
 /* Class entry for the Server PHP class */
 extern zend_class_entry *grpc_ce_server;
@@ -53,6 +53,7 @@
   zend_object std;
 
   grpc_server *wrapped;
+  grpc_completion_queue *queue;
 } wrapped_grpc_server;
 
 /* Initializes the Server class */
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index df64e65..c4c1fab 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -37,17 +37,17 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
 #include "php_grpc.h"
 
-#include "zend_exceptions.h"
-#include "zend_hash.h"
+#include <zend_exceptions.h>
+#include <zend_hash.h>
 
-#include "grpc/grpc.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
 
 zend_class_entry *grpc_ce_server_credentials;
 
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
index 8ed3697..7101d65 100755
--- a/src/php/ext/grpc/server_credentials.h
+++ b/src/php/ext/grpc/server_credentials.h
@@ -38,13 +38,13 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
 #include "php_grpc.h"
 
-#include "grpc/grpc.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
 
 /* Class entry for the Server_Credentials PHP class */
 extern zend_class_entry *grpc_ce_server_credentials;
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index f90f006..8a278d6 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -37,18 +37,18 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
 #include "php_grpc.h"
 
-#include "zend_exceptions.h"
+#include <zend_exceptions.h>
 
 #include <stdbool.h>
 
-#include "grpc/grpc.h"
-#include "grpc/support/time.h"
+#include <grpc/grpc.h>
+#include <grpc/support/time.h>
 
 zend_class_entry *grpc_ce_timeval;
 
@@ -227,7 +227,7 @@
  * Returns the infinite future time value as a timeval object
  * @return Timeval Infinite future time value
  */
-PHP_METHOD(Timeval, inf_future) {
+PHP_METHOD(Timeval, infFuture) {
   zval *grpc_php_timeval_inf_future = grpc_php_wrap_timeval(gpr_inf_future);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
 }
@@ -236,7 +236,7 @@
  * Returns the infinite past time value as a timeval object
  * @return Timeval Infinite past time value
  */
-PHP_METHOD(Timeval, inf_past) {
+PHP_METHOD(Timeval, infPast) {
   zval *grpc_php_timeval_inf_past = grpc_php_wrap_timeval(gpr_inf_past);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
 }
@@ -245,7 +245,7 @@
  * Sleep until this time, interpreted as an absolute timeout
  * @return void
  */
-PHP_METHOD(Timeval, sleep_until) {
+PHP_METHOD(Timeval, sleepUntil) {
   wrapped_grpc_timeval *this =
       (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
   gpr_sleep_until(this->wrapped);
@@ -255,11 +255,11 @@
     PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
     PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC)
     PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, inf_future, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, inf_past, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+    PHP_ME(Timeval, infFuture, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+    PHP_ME(Timeval, infPast, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
     PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
     PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Timeval, sleep_until, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Timeval, sleepUntil, NULL, ZEND_ACC_PUBLIC)
     PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
     PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
 
diff --git a/src/php/ext/grpc/timeval.h b/src/php/ext/grpc/timeval.h
index e3183f6..07cef03 100755
--- a/src/php/ext/grpc/timeval.h
+++ b/src/php/ext/grpc/timeval.h
@@ -38,13 +38,13 @@
 #include "config.h"
 #endif
 
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
 #include "php_grpc.h"
 
-#include "grpc/grpc.h"
-#include "grpc/support/time.h"
+#include <grpc/grpc.h>
+#include <grpc/support/time.h>
 
 /* Class entry for the Timeval PHP Class */
 extern zend_class_entry *grpc_ce_timeval;
diff --git a/src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php b/src/php/lib/Grpc/AbstractCall.php
old mode 100755
new mode 100644
similarity index 63%
rename from src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php
rename to src/php/lib/Grpc/AbstractCall.php
index 0459f21..1add972
--- a/src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -32,44 +32,47 @@
  *
  */
 namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
 
-/**
- * Represents an active call that allows for sending and recieving messages in
- * streams in any order.
- */
-class BidiStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
+abstract class AbstractCall {
+
+  protected $call;
+  protected $deserialize;
+  protected $metadata;
 
   /**
-   * Reads the next value from the server.
-   * @return The next value from the server, or null if there is none
+   * Create a new Call wrapper object.
+   * @param Channel $channel The channel to communicate on
+   * @param string $method The method to call on the remote server
    */
-  public function read() {
-    return $this->_read();
+  public function __construct(Channel $channel, $method, $deserialize) {
+    $this->call = new Call($channel, $method, Timeval::infFuture());
+    $this->deserialize = $deserialize;
+    $this->metadata = null;
   }
 
   /**
-   * Writes a single message to the server. This cannot be called after
-   * writesDone is called.
-   * @param $value The message to send
+   * @return The metadata sent by the server.
    */
-  public function write($value) {
-    $this->_write($value);
+  public function getMetadata() {
+    return $this->metadata;
   }
 
   /**
-   * Indicate that no more writes will be sent
+   * Cancels the call
    */
-  public function writesDone() {
-    $this->_writesDone();
+  public function cancel() {
+    $this->call->cancel();
   }
 
   /**
-   * Wait for the server to send the status, and return it.
-   * @return object The status object, with integer $code and string $details
-   *     members
+   * Deserialize a response value to an object.
+   * @param string $value The binary value to deserialize
+   * @return The deserialized value
    */
-  public function getStatus() {
-    return $this->_getStatus();
+  protected function deserializeResponse($value) {
+    if ($value === null) {
+      return null;
+    }
+    return call_user_func($this->deserialize, $value);
   }
-}
+}
\ No newline at end of file
diff --git a/src/php/lib/Grpc/AbstractSurfaceActiveCall.php b/src/php/lib/Grpc/AbstractSurfaceActiveCall.php
deleted file mode 100755
index 9d0af09..0000000
--- a/src/php/lib/Grpc/AbstractSurfaceActiveCall.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-
-/*
- *
- * 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.
- *
- */
-
-namespace Grpc;
-
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-
-/**
- * Represents an active call that allows sending and recieving messages.
- * Subclasses restrict how data can be sent and recieved.
- */
-abstract class AbstractSurfaceActiveCall {
-  private $active_call;
-  private $deserialize;
-
-  /**
-   * Create a new surface active call.
-   * @param Channel $channel The channel to communicate on
-   * @param string $method The method to call on the remote server
-   * @param callable $deserialize The function to deserialize a value
-   * @param array $metadata Metadata to send with the call, if applicable
-   * @param long $flags Write flags to use with this call
-   */
-  public function __construct(Channel $channel,
-                       $method,
-                       callable $deserialize,
-                       $metadata = array(),
-                       $flags = 0) {
-    $this->active_call = new ActiveCall($channel, $method, $metadata, $flags);
-    $this->deserialize = $deserialize;
-  }
-
-  /**
-   * @return The metadata sent by the server
-   */
-  public function getMetadata() {
-    return $this->metadata();
-  }
-
-  /**
-   * Cancels the call
-   */
-  public function cancel() {
-    $this->active_call->cancel();
-  }
-
-  protected function _read() {
-    $response = $this->active_call->read();
-    if ($response === null) {
-      return null;
-    }
-    return call_user_func($this->deserialize, $response);
-  }
-
-  protected function _write($value) {
-    return $this->active_call->write($value->serialize());
-  }
-
-  protected function _writesDone() {
-    $this->active_call->writesDone();
-  }
-
-  protected function _getStatus() {
-    return $this->active_call->getStatus();
-  }
-}
diff --git a/src/php/lib/Grpc/ActiveCall.php b/src/php/lib/Grpc/ActiveCall.php
deleted file mode 100755
index f0d0d55..0000000
--- a/src/php/lib/Grpc/ActiveCall.php
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-/*
- *
- * 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.
- *
- */
-namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-
-/**
- * Represents an active call that allows sending and recieving binary data
- */
-class ActiveCall {
-  private $completion_queue;
-  private $call;
-  private $flags;
-  private $metadata;
-
-  /**
-   * Create a new active call.
-   * @param Channel $channel The channel to communicate on
-   * @param string $method The method to call on the remote server
-   * @param array $metadata Metadata to send with the call, if applicable
-   * @param long $flags Write flags to use with this call
-   */
-  public function __construct(Channel $channel,
-                              $method,
-                              $metadata = array(),
-                              $flags = 0) {
-    $this->completion_queue = new CompletionQueue();
-    $this->call = new Call($channel, $method, Timeval::inf_future());
-    $this->call->add_metadata($metadata, 0);
-    $this->flags = $flags;
-
-    // Invoke the call.
-    $this->call->invoke($this->completion_queue,
-                        CLIENT_METADATA_READ,
-                        FINISHED, 0);
-    $metadata_event = $this->completion_queue->pluck(CLIENT_METADATA_READ,
-                                                     Timeval::inf_future());
-    $this->metadata = $metadata_event->data;
-  }
-
-  /**
-   * @return The metadata sent by the server.
-   */
-  public function getMetadata() {
-    return $this->metadata;
-  }
-
-  /**
-   * Cancels the call
-   */
-  public function cancel() {
-    $this->call->cancel();
-  }
-
-  /**
-   * Read a single message from the server.
-   * @return The next message from the server, or null if there is none.
-   */
-  public function read() {
-    $this->call->start_read(READ);
-    $read_event = $this->completion_queue->pluck(READ, Timeval::inf_future());
-    return $read_event->data;
-  }
-
-  /**
-   * Write a single message to the server. This cannot be called after
-   * writesDone is called.
-   * @param ByteBuffer $data The data to write
-   */
-  public function write($data) {
-    $this->call->start_write($data, WRITE_ACCEPTED, $this->flags);
-    $this->completion_queue->pluck(WRITE_ACCEPTED, Timeval::inf_future());
-  }
-
-  /**
-   * Indicate that no more writes will be sent.
-   */
-  public function writesDone() {
-    $this->call->writes_done(FINISH_ACCEPTED);
-    $this->completion_queue->pluck(FINISH_ACCEPTED, Timeval::inf_future());
-  }
-
-  /**
-   * Wait for the server to send the status, and return it.
-   * @return object The status object, with integer $code, string $details,
-   *     and array $metadata members
-   */
-  public function getStatus() {
-    $status_event = $this->completion_queue->pluck(FINISHED,
-                                                   Timeval::inf_future());
-    return $status_event->data;
-  }
-}
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index fde055a..fc83dac 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -32,7 +32,6 @@
  *
  */
 namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
 
 /**
  * Base class for generated client stubs. Stub methods are expected to call
@@ -69,11 +68,9 @@
                                  $argument,
                                  callable $deserialize,
                                  $metadata = array()) {
-    return new SimpleSurfaceActiveCall($this->channel,
-                                       $method,
-                                       $deserialize,
-                                       $argument,
-                                       $metadata);
+    $call = new UnaryCall($this->channel, $method, $deserialize);
+    $call->start($argument, $metadata);
+    return $call;
   }
 
   /**
@@ -91,11 +88,9 @@
                                        $arguments,
                                        callable $deserialize,
                                        $metadata = array()) {
-    return new ClientStreamingSurfaceActiveCall($this->channel,
-                                                $method,
-                                                $deserialize,
-                                                $arguments,
-                                                $metadata);
+    $call = new ClientStreamingCall($this->channel, $method, $deserialize);
+    $call->start($arguments, $metadata);
+    return $call;
   }
 
   /**
@@ -112,11 +107,9 @@
                                        $argument,
                                        callable $deserialize,
                                        $metadata = array()) {
-    return new ServerStreamingSurfaceActiveCall($this->channel,
-                                                $method,
-                                                $deserialize,
-                                                $argument,
-                                                $metadata);
+    $call = new ServerStreamingCall($this->channel, $method, $deserialize);
+    $call->start($argument, $metadata);
+    return $call;
   }
 
   /**
@@ -130,9 +123,8 @@
   public function _bidiRequest($method,
                                callable $deserialize,
                                $metadata = array()) {
-    return new BidiStreamingSurfaceActiveCall($this->channel,
-                                              $method,
-                                              $deserialize,
-                                              $metadata);
+    $call = new BidiStreamingCall($this->channel, $method, $deserialize);
+    $call->start($metadata);
+    return $call;
   }
 }
diff --git a/src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
old mode 100755
new mode 100644
similarity index 62%
copy from src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php
copy to src/php/lib/Grpc/BidiStreamingCall.php
index 0459f21..76c642b
--- a/src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -32,44 +32,61 @@
  *
  */
 namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
 
 /**
  * Represents an active call that allows for sending and recieving messages in
  * streams in any order.
  */
-class BidiStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
+class BidiStreamingCall extends AbstractCall {
+  /**
+   * Start the call
+   * @param array $metadata Metadata to send with the call, if applicable
+   */
+  public function start($metadata) {
+    $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]);
+  }
 
   /**
    * Reads the next value from the server.
    * @return The next value from the server, or null if there is none
    */
   public function read() {
-    return $this->_read();
+    $batch = [OP_RECV_MESSAGE => true];
+    if ($this->metadata === null) {
+      $batch[OP_RECV_INITIAL_METADATA] = true;
+    }
+    $read_event = $this->call->startBatch($batch);
+    if ($this->metadata === null) {
+      $this->metadata = $read_event->metadata;
+    }
+    return $this->deserializeResponse($read_event->message);
   }
 
   /**
-   * Writes a single message to the server. This cannot be called after
+   * Write a single message to the server. This cannot be called after
    * writesDone is called.
-   * @param $value The message to send
+   * @param ByteBuffer $data The data to write
    */
-  public function write($value) {
-    $this->_write($value);
+  public function write($data) {
+    $this->call->startBatch([OP_SEND_MESSAGE => $data->serialize()]);
   }
 
   /**
-   * Indicate that no more writes will be sent
+   * Indicate that no more writes will be sent.
    */
   public function writesDone() {
-    $this->_writesDone();
+    $this->call->startBatch([OP_SEND_CLOSE_FROM_CLIENT => true]);
   }
 
   /**
    * Wait for the server to send the status, and return it.
-   * @return object The status object, with integer $code and string $details
-   *     members
+   * @return object The status object, with integer $code, string $details,
+   *     and array $metadata members
    */
   public function getStatus() {
-    return $this->_getStatus();
+    $status_event = $this->call->startBatch([
+        OP_RECV_STATUS_ON_CLIENT => true
+                                              ]);
+    return $status_event->status;
   }
-}
+}
\ No newline at end of file
diff --git a/src/php/lib/Grpc/ClientStreamingSurfaceActiveCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
old mode 100755
new mode 100644
similarity index 69%
rename from src/php/lib/Grpc/ClientStreamingSurfaceActiveCall.php
rename to src/php/lib/Grpc/ClientStreamingCall.php
index d33f09f..61439d3
--- a/src/php/lib/Grpc/ClientStreamingSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -32,31 +32,23 @@
  *
  */
 namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
 
 /**
  * Represents an active call that sends a stream of messages and then gets a
  * single response.
  */
-class ClientStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
+class ClientStreamingCall extends AbstractCall {
   /**
-   * Create a new simple (single request/single response) active call.
-   * @param Channel $channel The channel to communicate on
-   * @param string $method The method to call on the remote server
-   * @param callable $deserialize The function to deserialize a value
+   * Start the call.
    * @param Traversable $arg_iter The iterator of arguments to send
    * @param array $metadata Metadata to send with the call, if applicable
    */
-  public function __construct(Channel $channel,
-                              $method,
-                              callable $deserialize,
-                              $arg_iter,
-                              $metadata = array()) {
-    parent::__construct($channel, $method, $deserialize, $metadata, 0);
+  public function start($arg_iter, $metadata = array()) {
+    $event = $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]);
     foreach($arg_iter as $arg) {
-      $this->_write($arg);
+      $this->call->startBatch([OP_SEND_MESSAGE => $arg->serialize()]);
     }
-    $this->_writesDone();
+    $this->call->startBatch([OP_SEND_CLOSE_FROM_CLIENT => true]);
   }
 
   /**
@@ -64,8 +56,11 @@
    * @return [response data, status]
    */
   public function wait() {
-    $response = $this->_read();
-    $status = $this->_getStatus();
-    return array($response, $status);
+    $event = $this->call->startBatch([
+        OP_RECV_INITIAL_METADATA => true,
+        OP_RECV_MESSAGE => true,
+        OP_RECV_STATUS_ON_CLIENT => true]);
+    $this->metadata = $event->metadata;
+    return array($this->deserializeResponse($event->message), $event->status);
   }
-}
+}
\ No newline at end of file
diff --git a/src/php/lib/Grpc/ServerStreamingSurfaceActiveCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
old mode 100755
new mode 100644
similarity index 66%
rename from src/php/lib/Grpc/ServerStreamingSurfaceActiveCall.php
rename to src/php/lib/Grpc/ServerStreamingCall.php
index fd08e86..631c863
--- a/src/php/lib/Grpc/ServerStreamingSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -33,42 +33,45 @@
  */
 namespace Grpc;
 
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-
 /**
  * Represents an active call that sends a single message and then gets a stream
  * of reponses
  */
-class ServerStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
+class ServerStreamingCall extends AbstractCall {
   /**
-   * Create a new simple (single request/single response) active call.
-   * @param Channel $channel The channel to communicate on
-   * @param string $method The method to call on the remote server
-   * @param callable $deserialize The function to deserialize a value
+   * Start the call
    * @param $arg The argument to send
    * @param array $metadata Metadata to send with the call, if applicable
    */
-  public function __construct(Channel $channel,
-                              $method,
-                              callable $deserialize,
-                              $arg,
-                              $metadata = array()) {
-    parent::__construct($channel, $method, $deserialize, $metadata,
-                        \Grpc\WRITE_BUFFER_HINT);
-    $this->_write($arg);
-    $this->_writesDone();
+  public function start($arg, $metadata = array()) {
+    $event = $this->call->startBatch([
+        OP_SEND_INITIAL_METADATA => $metadata,
+        OP_RECV_INITIAL_METADATA => true,
+        OP_SEND_MESSAGE => $arg->serialize(),
+        OP_SEND_CLOSE_FROM_CLIENT => true]);
+    $this->metadata = $event->metadata;
   }
 
   /**
    * @return An iterator of response values
    */
   public function responses() {
-    while(($response = $this->_read()) !== null) {
-      yield $response;
+    $response = $this->call->startBatch([OP_RECV_MESSAGE => true])->message;
+    while($response !== null) {
+      yield $this->deserializeResponse($response);
+      $response = $this->call->startBatch([OP_RECV_MESSAGE => true])->message;
     }
   }
 
+  /**
+   * Wait for the server to send the status, and return it.
+   * @return object The status object, with integer $code, string $details,
+   *     and array $metadata members
+   */
   public function getStatus() {
-    return $this->_getStatus();
+    $status_event = $this->call->startBatch([
+        OP_RECV_STATUS_ON_CLIENT => true
+                                              ]);
+    return $status_event->status;
   }
-}
+}
\ No newline at end of file
diff --git a/src/php/lib/Grpc/SimpleSurfaceActiveCall.php b/src/php/lib/Grpc/UnaryCall.php
old mode 100755
new mode 100644
similarity index 68%
rename from src/php/lib/Grpc/SimpleSurfaceActiveCall.php
rename to src/php/lib/Grpc/UnaryCall.php
index ba82f57..97a10a4
--- a/src/php/lib/Grpc/SimpleSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -33,30 +33,23 @@
  */
 namespace Grpc;
 
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-
 /**
  * Represents an active call that sends a single message and then gets a single
  * response.
  */
-class SimpleSurfaceActiveCall extends AbstractSurfaceActiveCall {
+class UnaryCall extends AbstractCall {
   /**
-   * Create a new simple (single request/single response) active call.
-   * @param Channel $channel The channel to communicate on
-   * @param string $method The method to call on the remote server
-   * @param callable $deserialize The function to deserialize a value
+   * Start the call
    * @param $arg The argument to send
    * @param array $metadata Metadata to send with the call, if applicable
    */
-  public function __construct(Channel $channel,
-                              $method,
-                              callable $deserialize,
-                              $arg,
-                              $metadata = array()) {
-    parent::__construct($channel, $method, $deserialize, $metadata,
-                        \Grpc\WRITE_BUFFER_HINT);
-    $this->_write($arg);
-    $this->_writesDone();
+  public function start($arg, $metadata = array()) {
+    $event = $this->call->startBatch([
+        OP_SEND_INITIAL_METADATA => $metadata,
+        OP_RECV_INITIAL_METADATA => true,
+        OP_SEND_MESSAGE => $arg->serialize(),
+        OP_SEND_CLOSE_FROM_CLIENT => true]);
+    $this->metadata = $event->metadata;
   }
 
   /**
@@ -64,8 +57,9 @@
    * @return [response data, status]
    */
   public function wait() {
-    $response = $this->_read();
-    $status = $this->_getStatus();
-    return array($response, $status);
+    $event = $this->call->startBatch([
+        OP_RECV_MESSAGE => true,
+        OP_RECV_STATUS_ON_CLIENT => true]);
+    return array($this->deserializeResponse($event->message), $event->status);
   }
-}
+}
\ No newline at end of file
diff --git a/src/php/tests/generated_code/GeneratedCodeTest.php b/src/php/tests/generated_code/GeneratedCodeTest.php
index cb2c0e6..927d24c 100755
--- a/src/php/tests/generated_code/GeneratedCodeTest.php
+++ b/src/php/tests/generated_code/GeneratedCodeTest.php
@@ -31,7 +31,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-require_once realpath(dirname(__FILE__) . '/../../lib/autoload.php');
+require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php');
 require 'DrSlump/Protobuf.php';
 \DrSlump\Protobuf::autoload();
 require 'math.php';
@@ -41,7 +41,8 @@
   protected static $client;
   protected static $timeout;
   public static function setUpBeforeClass() {
-    self::$client = new math\MathClient(getenv('GRPC_TEST_HOST'));
+    self::$client = new math\MathClient(new Grpc\BaseStub(
+        getenv('GRPC_TEST_HOST'), []));
   }
 
   public function testSimpleRequest() {
diff --git a/src/php/tests/generated_code/math.php b/src/php/tests/generated_code/math.php
deleted file mode 100755
index e97a5cf..0000000
--- a/src/php/tests/generated_code/math.php
+++ /dev/null
@@ -1,479 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: math.proto
-//   Date: 2014-11-14 00:00:41
-
-namespace math {
-
-  class DivArgs extends \DrSlump\Protobuf\Message {
-
-    /**  @var int */
-    public $dividend = null;
-
-    /**  @var int */
-    public $divisor = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.DivArgs');
-
-      // REQUIRED INT64 dividend = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "dividend";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT64;
-      $f->rule      = \DrSlump\Protobuf::RULE_REQUIRED;
-      $descriptor->addField($f);
-
-      // REQUIRED INT64 divisor = 2
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 2;
-      $f->name      = "divisor";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT64;
-      $f->rule      = \DrSlump\Protobuf::RULE_REQUIRED;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <dividend> has a value
-     *
-     * @return boolean
-     */
-    public function hasDividend(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <dividend> value
-     *
-     * @return \math\DivArgs
-     */
-    public function clearDividend(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <dividend> value
-     *
-     * @return int
-     */
-    public function getDividend(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <dividend> value
-     *
-     * @param int $value
-     * @return \math\DivArgs
-     */
-    public function setDividend( $value){
-      return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <divisor> has a value
-     *
-     * @return boolean
-     */
-    public function hasDivisor(){
-      return $this->_has(2);
-    }
-
-    /**
-     * Clear <divisor> value
-     *
-     * @return \math\DivArgs
-     */
-    public function clearDivisor(){
-      return $this->_clear(2);
-    }
-
-    /**
-     * Get <divisor> value
-     *
-     * @return int
-     */
-    public function getDivisor(){
-      return $this->_get(2);
-    }
-
-    /**
-     * Set <divisor> value
-     *
-     * @param int $value
-     * @return \math\DivArgs
-     */
-    public function setDivisor( $value){
-      return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace math {
-
-  class DivReply extends \DrSlump\Protobuf\Message {
-
-    /**  @var int */
-    public $quotient = null;
-
-    /**  @var int */
-    public $remainder = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.DivReply');
-
-      // REQUIRED INT64 quotient = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "quotient";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT64;
-      $f->rule      = \DrSlump\Protobuf::RULE_REQUIRED;
-      $descriptor->addField($f);
-
-      // REQUIRED INT64 remainder = 2
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 2;
-      $f->name      = "remainder";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT64;
-      $f->rule      = \DrSlump\Protobuf::RULE_REQUIRED;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <quotient> has a value
-     *
-     * @return boolean
-     */
-    public function hasQuotient(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <quotient> value
-     *
-     * @return \math\DivReply
-     */
-    public function clearQuotient(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <quotient> value
-     *
-     * @return int
-     */
-    public function getQuotient(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <quotient> value
-     *
-     * @param int $value
-     * @return \math\DivReply
-     */
-    public function setQuotient( $value){
-      return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <remainder> has a value
-     *
-     * @return boolean
-     */
-    public function hasRemainder(){
-      return $this->_has(2);
-    }
-
-    /**
-     * Clear <remainder> value
-     *
-     * @return \math\DivReply
-     */
-    public function clearRemainder(){
-      return $this->_clear(2);
-    }
-
-    /**
-     * Get <remainder> value
-     *
-     * @return int
-     */
-    public function getRemainder(){
-      return $this->_get(2);
-    }
-
-    /**
-     * Set <remainder> value
-     *
-     * @param int $value
-     * @return \math\DivReply
-     */
-    public function setRemainder( $value){
-      return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace math {
-
-  class FibArgs extends \DrSlump\Protobuf\Message {
-
-    /**  @var int */
-    public $limit = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.FibArgs');
-
-      // OPTIONAL INT64 limit = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "limit";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT64;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <limit> has a value
-     *
-     * @return boolean
-     */
-    public function hasLimit(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <limit> value
-     *
-     * @return \math\FibArgs
-     */
-    public function clearLimit(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <limit> value
-     *
-     * @return int
-     */
-    public function getLimit(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <limit> value
-     *
-     * @param int $value
-     * @return \math\FibArgs
-     */
-    public function setLimit( $value){
-      return $this->_set(1, $value);
-    }
-  }
-}
-
-namespace math {
-
-  class Num extends \DrSlump\Protobuf\Message {
-
-    /**  @var int */
-    public $num = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.Num');
-
-      // REQUIRED INT64 num = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "num";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT64;
-      $f->rule      = \DrSlump\Protobuf::RULE_REQUIRED;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <num> has a value
-     *
-     * @return boolean
-     */
-    public function hasNum(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <num> value
-     *
-     * @return \math\Num
-     */
-    public function clearNum(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <num> value
-     *
-     * @return int
-     */
-    public function getNum(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <num> value
-     *
-     * @param int $value
-     * @return \math\Num
-     */
-    public function setNum( $value){
-      return $this->_set(1, $value);
-    }
-  }
-}
-
-namespace math {
-
-  class FibReply extends \DrSlump\Protobuf\Message {
-
-    /**  @var int */
-    public $count = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.FibReply');
-
-      // REQUIRED INT64 count = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "count";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT64;
-      $f->rule      = \DrSlump\Protobuf::RULE_REQUIRED;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <count> has a value
-     *
-     * @return boolean
-     */
-    public function hasCount(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <count> value
-     *
-     * @return \math\FibReply
-     */
-    public function clearCount(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <count> value
-     *
-     * @return int
-     */
-    public function getCount(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <count> value
-     *
-     * @param int $value
-     * @return \math\FibReply
-     */
-    public function setCount( $value){
-      return $this->_set(1, $value);
-    }
-  }
-}
-
-namespace math {
-
-  class MathClient extends \Grpc\BaseStub {
-    /**
-     * @param math\DivArgs $input
-     * @return math\DivReply
-     */
-    public function Div(\math\DivArgs $argument, $metadata = array()) {
-      return $this->_simpleRequest('/Math/Div', $argument, '\math\DivReply::deserialize', $metadata);
-    }
-    /**
-     * @param math\DivArgs $input
-     * @return math\DivReply
-     */
-    public function DivMany($metadata = array()) {
-      return $this->_bidiRequest('/Math/DivMany', '\math\DivReply::deserialize', $metadata);
-    }
-    /**
-     * @param math\FibArgs $input
-     * @return math\Num
-     */
-    public function Fib($argument, $metadata = array()) {
-      return $this->_serverStreamRequest('/Math/Fib', $argument, '\math\Num::deserialize', $metadata);
-    }
-    /**
-     * @param math\Num $input
-     * @return math\Num
-     */
-    public function Sum($arguments, $metadata = array()) {
-      return $this->_clientStreamRequest('/Math/Sum', $arguments, '\math\Num::deserialize', $metadata);
-    }
-  }
-}
diff --git a/src/php/tests/generated_code/math.proto b/src/php/tests/generated_code/math.proto
new file mode 100644
index 0000000..e34ad5e
--- /dev/null
+++ b/src/php/tests/generated_code/math.proto
@@ -0,0 +1,80 @@
+
+// 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.
+
+syntax = "proto3";
+
+package math;
+
+message DivArgs {
+  optional int64 dividend = 1;
+  optional int64 divisor = 2;
+}
+
+message DivReply {
+  optional int64 quotient = 1;
+  optional int64 remainder = 2;
+}
+
+message FibArgs {
+  optional int64 limit = 1;
+}
+
+message Num {
+  optional int64 num = 1;
+}
+
+message FibReply {
+  optional int64 count = 1;
+}
+
+service Math {
+  // Div divides args.dividend by args.divisor and returns the quotient and
+  // remainder.
+  rpc Div (DivArgs) returns (DivReply) {
+  }
+
+  // DivMany accepts an arbitrary number of division args from the client stream
+  // and sends back the results in the reply stream.  The stream continues until
+  // the client closes its end; the server does the same after sending all the
+  // replies.  The stream ends immediately if either end aborts.
+  rpc DivMany (stream DivArgs) returns (stream DivReply) {
+  }
+
+  // Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+  // generates up to limit numbers; otherwise it continues until the call is
+  // canceled.  Unlike Fib above, Fib has no final FibReply.
+  rpc Fib (FibArgs) returns (stream Num) {
+  }
+
+  // Sum sums a stream of numbers, returning the final result once the stream
+  // is closed.
+  rpc Sum (stream Num) returns (Num) {
+  }
+}
diff --git a/src/php/tests/interop/empty.php b/src/php/tests/interop/empty.php
deleted file mode 100755
index 22b1180..0000000
--- a/src/php/tests/interop/empty.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: test/cpp/interop/empty.proto
-//   Date: 2015-01-30 23:30:46
-
-namespace grpc\testing {
-
-  class EmptyMessage extends \DrSlump\Protobuf\Message {
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.EmptyMessage');
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-  }
-}
diff --git a/src/php/tests/interop/empty.proto b/src/php/tests/interop/empty.proto
new file mode 100644
index 0000000..4200d7b
--- /dev/null
+++ b/src/php/tests/interop/empty.proto
@@ -0,0 +1,43 @@
+
+// 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.
+
+syntax = "proto2";
+
+package grpc.testing;
+
+// An empty message that you can re-use to avoid defining duplicated empty
+// messages in your project. A typical example is to use it as argument or the
+// return value of a service API. For instance:
+//
+//   service Foo {
+//     rpc Bar (grpc.testing.EmptyMessage) returns (grpc.testing.EmptyMessage) { };
+//   };
+//
+message EmptyMessage {}
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 82ca438..6f81bfa 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -31,7 +31,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-require_once realpath(dirname(__FILE__) . '/../../lib/autoload.php');
+require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php');
 require 'DrSlump/Protobuf.php';
 \DrSlump\Protobuf::autoload();
 require 'empty.php';
@@ -132,8 +132,6 @@
   }
 
   $call = $stub->StreamingOutputCall($request);
-  hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
-              'Call did not complete successfully');
   $i = 0;
   foreach($call->responses() as $value) {
     hardAssert($i < 4, 'Too many responses');
@@ -142,7 +140,10 @@
                 'Payload ' . $i . ' had the wrong type');
     hardAssert(strlen($payload->getBody()) === $sizes[$i],
                 'Response ' . $i . ' had the wrong length');
+    $i += 1;
   }
+  hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
+             'Call did not complete successfully');
 }
 
 /**
@@ -240,4 +241,7 @@
     break;
   case 'cancel_after_first_response':
     cancelAfterFirstResponse($stub);
+    break;
+  default:
+    exit(1);
 }
diff --git a/src/php/tests/interop/messages.php b/src/php/tests/interop/messages.php
deleted file mode 100755
index a626a17..0000000
--- a/src/php/tests/interop/messages.php
+++ /dev/null
@@ -1,1074 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: test/cpp/interop/messages.proto
-//   Date: 2015-01-30 23:30:46
-
-namespace grpc\testing {
-
-  class PayloadType extends \DrSlump\Protobuf\Enum {
-    const COMPRESSABLE = 0;
-    const UNCOMPRESSABLE = 1;
-    const RANDOM = 2;
-  }
-}
-namespace grpc\testing {
-
-  class Payload extends \DrSlump\Protobuf\Message {
-
-    /**  @var int - \grpc\testing\PayloadType */
-    public $type = null;
-
-    /**  @var string */
-    public $body = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.Payload');
-
-      // OPTIONAL ENUM type = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "type";
-      $f->type      = \DrSlump\Protobuf::TYPE_ENUM;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\PayloadType';
-      $descriptor->addField($f);
-
-      // OPTIONAL BYTES body = 2
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 2;
-      $f->name      = "body";
-      $f->type      = \DrSlump\Protobuf::TYPE_BYTES;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <type> has a value
-     *
-     * @return boolean
-     */
-    public function hasType(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <type> value
-     *
-     * @return \grpc\testing\Payload
-     */
-    public function clearType(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <type> value
-     *
-     * @return int - \grpc\testing\PayloadType
-     */
-    public function getType(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <type> value
-     *
-     * @param int - \grpc\testing\PayloadType $value
-     * @return \grpc\testing\Payload
-     */
-    public function setType( $value){
-      return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <body> has a value
-     *
-     * @return boolean
-     */
-    public function hasBody(){
-      return $this->_has(2);
-    }
-
-    /**
-     * Clear <body> value
-     *
-     * @return \grpc\testing\Payload
-     */
-    public function clearBody(){
-      return $this->_clear(2);
-    }
-
-    /**
-     * Get <body> value
-     *
-     * @return string
-     */
-    public function getBody(){
-      return $this->_get(2);
-    }
-
-    /**
-     * Set <body> value
-     *
-     * @param string $value
-     * @return \grpc\testing\Payload
-     */
-    public function setBody( $value){
-      return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace grpc\testing {
-
-  class SimpleRequest extends \DrSlump\Protobuf\Message {
-
-    /**  @var int - \grpc\testing\PayloadType */
-    public $response_type = null;
-
-    /**  @var int */
-    public $response_size = null;
-
-    /**  @var \grpc\testing\Payload */
-    public $payload = null;
-
-    /**  @var boolean */
-    public $fill_username = null;
-
-    /**  @var boolean */
-    public $fill_oauth_scope = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.SimpleRequest');
-
-      // OPTIONAL ENUM response_type = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "response_type";
-      $f->type      = \DrSlump\Protobuf::TYPE_ENUM;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\PayloadType';
-      $descriptor->addField($f);
-
-      // OPTIONAL INT32 response_size = 2
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 2;
-      $f->name      = "response_size";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT32;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      // OPTIONAL MESSAGE payload = 3
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 3;
-      $f->name      = "payload";
-      $f->type      = \DrSlump\Protobuf::TYPE_MESSAGE;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\Payload';
-      $descriptor->addField($f);
-
-      // OPTIONAL BOOL fill_username = 4
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 4;
-      $f->name      = "fill_username";
-      $f->type      = \DrSlump\Protobuf::TYPE_BOOL;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      // OPTIONAL BOOL fill_oauth_scope = 5
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 5;
-      $f->name      = "fill_oauth_scope";
-      $f->type      = \DrSlump\Protobuf::TYPE_BOOL;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <response_type> has a value
-     *
-     * @return boolean
-     */
-    public function hasResponseType(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <response_type> value
-     *
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function clearResponseType(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <response_type> value
-     *
-     * @return int - \grpc\testing\PayloadType
-     */
-    public function getResponseType(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <response_type> value
-     *
-     * @param int - \grpc\testing\PayloadType $value
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function setResponseType( $value){
-      return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <response_size> has a value
-     *
-     * @return boolean
-     */
-    public function hasResponseSize(){
-      return $this->_has(2);
-    }
-
-    /**
-     * Clear <response_size> value
-     *
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function clearResponseSize(){
-      return $this->_clear(2);
-    }
-
-    /**
-     * Get <response_size> value
-     *
-     * @return int
-     */
-    public function getResponseSize(){
-      return $this->_get(2);
-    }
-
-    /**
-     * Set <response_size> value
-     *
-     * @param int $value
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function setResponseSize( $value){
-      return $this->_set(2, $value);
-    }
-
-    /**
-     * Check if <payload> has a value
-     *
-     * @return boolean
-     */
-    public function hasPayload(){
-      return $this->_has(3);
-    }
-
-    /**
-     * Clear <payload> value
-     *
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function clearPayload(){
-      return $this->_clear(3);
-    }
-
-    /**
-     * Get <payload> value
-     *
-     * @return \grpc\testing\Payload
-     */
-    public function getPayload(){
-      return $this->_get(3);
-    }
-
-    /**
-     * Set <payload> value
-     *
-     * @param \grpc\testing\Payload $value
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function setPayload(\grpc\testing\Payload $value){
-      return $this->_set(3, $value);
-    }
-
-    /**
-     * Check if <fill_username> has a value
-     *
-     * @return boolean
-     */
-    public function hasFillUsername(){
-      return $this->_has(4);
-    }
-
-    /**
-     * Clear <fill_username> value
-     *
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function clearFillUsername(){
-      return $this->_clear(4);
-    }
-
-    /**
-     * Get <fill_username> value
-     *
-     * @return boolean
-     */
-    public function getFillUsername(){
-      return $this->_get(4);
-    }
-
-    /**
-     * Set <fill_username> value
-     *
-     * @param boolean $value
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function setFillUsername( $value){
-      return $this->_set(4, $value);
-    }
-
-    /**
-     * Check if <fill_oauth_scope> has a value
-     *
-     * @return boolean
-     */
-    public function hasFillOauthScope(){
-      return $this->_has(5);
-    }
-
-    /**
-     * Clear <fill_oauth_scope> value
-     *
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function clearFillOauthScope(){
-      return $this->_clear(5);
-    }
-
-    /**
-     * Get <fill_oauth_scope> value
-     *
-     * @return boolean
-     */
-    public function getFillOauthScope(){
-      return $this->_get(5);
-    }
-
-    /**
-     * Set <fill_oauth_scope> value
-     *
-     * @param boolean $value
-     * @return \grpc\testing\SimpleRequest
-     */
-    public function setFillOauthScope( $value){
-      return $this->_set(5, $value);
-    }
-  }
-}
-
-namespace grpc\testing {
-
-  class SimpleResponse extends \DrSlump\Protobuf\Message {
-
-    /**  @var \grpc\testing\Payload */
-    public $payload = null;
-
-    /**  @var string */
-    public $username = null;
-
-    /**  @var string */
-    public $oauth_scope = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.SimpleResponse');
-
-      // OPTIONAL MESSAGE payload = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "payload";
-      $f->type      = \DrSlump\Protobuf::TYPE_MESSAGE;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\Payload';
-      $descriptor->addField($f);
-
-      // OPTIONAL STRING username = 2
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 2;
-      $f->name      = "username";
-      $f->type      = \DrSlump\Protobuf::TYPE_STRING;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      // OPTIONAL STRING oauth_scope = 3
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 3;
-      $f->name      = "oauth_scope";
-      $f->type      = \DrSlump\Protobuf::TYPE_STRING;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <payload> has a value
-     *
-     * @return boolean
-     */
-    public function hasPayload(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <payload> value
-     *
-     * @return \grpc\testing\SimpleResponse
-     */
-    public function clearPayload(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <payload> value
-     *
-     * @return \grpc\testing\Payload
-     */
-    public function getPayload(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <payload> value
-     *
-     * @param \grpc\testing\Payload $value
-     * @return \grpc\testing\SimpleResponse
-     */
-    public function setPayload(\grpc\testing\Payload $value){
-      return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <username> has a value
-     *
-     * @return boolean
-     */
-    public function hasUsername(){
-      return $this->_has(2);
-    }
-
-    /**
-     * Clear <username> value
-     *
-     * @return \grpc\testing\SimpleResponse
-     */
-    public function clearUsername(){
-      return $this->_clear(2);
-    }
-
-    /**
-     * Get <username> value
-     *
-     * @return string
-     */
-    public function getUsername(){
-      return $this->_get(2);
-    }
-
-    /**
-     * Set <username> value
-     *
-     * @param string $value
-     * @return \grpc\testing\SimpleResponse
-     */
-    public function setUsername( $value){
-      return $this->_set(2, $value);
-    }
-
-    /**
-     * Check if <oauth_scope> has a value
-     *
-     * @return boolean
-     */
-    public function hasOauthScope(){
-      return $this->_has(3);
-    }
-
-    /**
-     * Clear <oauth_scope> value
-     *
-     * @return \grpc\testing\SimpleResponse
-     */
-    public function clearOauthScope(){
-      return $this->_clear(3);
-    }
-
-    /**
-     * Get <oauth_scope> value
-     *
-     * @return string
-     */
-    public function getOauthScope(){
-      return $this->_get(3);
-    }
-
-    /**
-     * Set <oauth_scope> value
-     *
-     * @param string $value
-     * @return \grpc\testing\SimpleResponse
-     */
-    public function setOauthScope( $value){
-      return $this->_set(3, $value);
-    }
-  }
-}
-
-namespace grpc\testing {
-
-  class StreamingInputCallRequest extends \DrSlump\Protobuf\Message {
-
-    /**  @var \grpc\testing\Payload */
-    public $payload = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingInputCallRequest');
-
-      // OPTIONAL MESSAGE payload = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "payload";
-      $f->type      = \DrSlump\Protobuf::TYPE_MESSAGE;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\Payload';
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <payload> has a value
-     *
-     * @return boolean
-     */
-    public function hasPayload(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <payload> value
-     *
-     * @return \grpc\testing\StreamingInputCallRequest
-     */
-    public function clearPayload(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <payload> value
-     *
-     * @return \grpc\testing\Payload
-     */
-    public function getPayload(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <payload> value
-     *
-     * @param \grpc\testing\Payload $value
-     * @return \grpc\testing\StreamingInputCallRequest
-     */
-    public function setPayload(\grpc\testing\Payload $value){
-      return $this->_set(1, $value);
-    }
-  }
-}
-
-namespace grpc\testing {
-
-  class StreamingInputCallResponse extends \DrSlump\Protobuf\Message {
-
-    /**  @var int */
-    public $aggregated_payload_size = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingInputCallResponse');
-
-      // OPTIONAL INT32 aggregated_payload_size = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "aggregated_payload_size";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT32;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <aggregated_payload_size> has a value
-     *
-     * @return boolean
-     */
-    public function hasAggregatedPayloadSize(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <aggregated_payload_size> value
-     *
-     * @return \grpc\testing\StreamingInputCallResponse
-     */
-    public function clearAggregatedPayloadSize(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <aggregated_payload_size> value
-     *
-     * @return int
-     */
-    public function getAggregatedPayloadSize(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <aggregated_payload_size> value
-     *
-     * @param int $value
-     * @return \grpc\testing\StreamingInputCallResponse
-     */
-    public function setAggregatedPayloadSize( $value){
-      return $this->_set(1, $value);
-    }
-  }
-}
-
-namespace grpc\testing {
-
-  class ResponseParameters extends \DrSlump\Protobuf\Message {
-
-    /**  @var int */
-    public $size = null;
-
-    /**  @var int */
-    public $interval_us = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.ResponseParameters');
-
-      // OPTIONAL INT32 size = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "size";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT32;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      // OPTIONAL INT32 interval_us = 2
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 2;
-      $f->name      = "interval_us";
-      $f->type      = \DrSlump\Protobuf::TYPE_INT32;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <size> has a value
-     *
-     * @return boolean
-     */
-    public function hasSize(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <size> value
-     *
-     * @return \grpc\testing\ResponseParameters
-     */
-    public function clearSize(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <size> value
-     *
-     * @return int
-     */
-    public function getSize(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <size> value
-     *
-     * @param int $value
-     * @return \grpc\testing\ResponseParameters
-     */
-    public function setSize( $value){
-      return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <interval_us> has a value
-     *
-     * @return boolean
-     */
-    public function hasIntervalUs(){
-      return $this->_has(2);
-    }
-
-    /**
-     * Clear <interval_us> value
-     *
-     * @return \grpc\testing\ResponseParameters
-     */
-    public function clearIntervalUs(){
-      return $this->_clear(2);
-    }
-
-    /**
-     * Get <interval_us> value
-     *
-     * @return int
-     */
-    public function getIntervalUs(){
-      return $this->_get(2);
-    }
-
-    /**
-     * Set <interval_us> value
-     *
-     * @param int $value
-     * @return \grpc\testing\ResponseParameters
-     */
-    public function setIntervalUs( $value){
-      return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace grpc\testing {
-
-  class StreamingOutputCallRequest extends \DrSlump\Protobuf\Message {
-
-    /**  @var int - \grpc\testing\PayloadType */
-    public $response_type = null;
-
-    /**  @var \grpc\testing\ResponseParameters[]  */
-    public $response_parameters = array();
-
-    /**  @var \grpc\testing\Payload */
-    public $payload = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingOutputCallRequest');
-
-      // OPTIONAL ENUM response_type = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "response_type";
-      $f->type      = \DrSlump\Protobuf::TYPE_ENUM;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\PayloadType';
-      $descriptor->addField($f);
-
-      // REPEATED MESSAGE response_parameters = 2
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 2;
-      $f->name      = "response_parameters";
-      $f->type      = \DrSlump\Protobuf::TYPE_MESSAGE;
-      $f->rule      = \DrSlump\Protobuf::RULE_REPEATED;
-      $f->reference = '\grpc\testing\ResponseParameters';
-      $descriptor->addField($f);
-
-      // OPTIONAL MESSAGE payload = 3
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 3;
-      $f->name      = "payload";
-      $f->type      = \DrSlump\Protobuf::TYPE_MESSAGE;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\Payload';
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <response_type> has a value
-     *
-     * @return boolean
-     */
-    public function hasResponseType(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <response_type> value
-     *
-     * @return \grpc\testing\StreamingOutputCallRequest
-     */
-    public function clearResponseType(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <response_type> value
-     *
-     * @return int - \grpc\testing\PayloadType
-     */
-    public function getResponseType(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <response_type> value
-     *
-     * @param int - \grpc\testing\PayloadType $value
-     * @return \grpc\testing\StreamingOutputCallRequest
-     */
-    public function setResponseType( $value){
-      return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <response_parameters> has a value
-     *
-     * @return boolean
-     */
-    public function hasResponseParameters(){
-      return $this->_has(2);
-    }
-
-    /**
-     * Clear <response_parameters> value
-     *
-     * @return \grpc\testing\StreamingOutputCallRequest
-     */
-    public function clearResponseParameters(){
-      return $this->_clear(2);
-    }
-
-    /**
-     * Get <response_parameters> value
-     *
-     * @param int $idx
-     * @return \grpc\testing\ResponseParameters
-     */
-    public function getResponseParameters($idx = NULL){
-      return $this->_get(2, $idx);
-    }
-
-    /**
-     * Set <response_parameters> value
-     *
-     * @param \grpc\testing\ResponseParameters $value
-     * @return \grpc\testing\StreamingOutputCallRequest
-     */
-    public function setResponseParameters(\grpc\testing\ResponseParameters $value, $idx = NULL){
-      return $this->_set(2, $value, $idx);
-    }
-
-    /**
-     * Get all elements of <response_parameters>
-     *
-     * @return \grpc\testing\ResponseParameters[]
-     */
-    public function getResponseParametersList(){
-     return $this->_get(2);
-    }
-
-    /**
-     * Add a new element to <response_parameters>
-     *
-     * @param \grpc\testing\ResponseParameters $value
-     * @return \grpc\testing\StreamingOutputCallRequest
-     */
-    public function addResponseParameters(\grpc\testing\ResponseParameters $value){
-     return $this->_add(2, $value);
-    }
-
-    /**
-     * Check if <payload> has a value
-     *
-     * @return boolean
-     */
-    public function hasPayload(){
-      return $this->_has(3);
-    }
-
-    /**
-     * Clear <payload> value
-     *
-     * @return \grpc\testing\StreamingOutputCallRequest
-     */
-    public function clearPayload(){
-      return $this->_clear(3);
-    }
-
-    /**
-     * Get <payload> value
-     *
-     * @return \grpc\testing\Payload
-     */
-    public function getPayload(){
-      return $this->_get(3);
-    }
-
-    /**
-     * Set <payload> value
-     *
-     * @param \grpc\testing\Payload $value
-     * @return \grpc\testing\StreamingOutputCallRequest
-     */
-    public function setPayload(\grpc\testing\Payload $value){
-      return $this->_set(3, $value);
-    }
-  }
-}
-
-namespace grpc\testing {
-
-  class StreamingOutputCallResponse extends \DrSlump\Protobuf\Message {
-
-    /**  @var \grpc\testing\Payload */
-    public $payload = null;
-
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-    public static function descriptor()
-    {
-      $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingOutputCallResponse');
-
-      // OPTIONAL MESSAGE payload = 1
-      $f = new \DrSlump\Protobuf\Field();
-      $f->number    = 1;
-      $f->name      = "payload";
-      $f->type      = \DrSlump\Protobuf::TYPE_MESSAGE;
-      $f->rule      = \DrSlump\Protobuf::RULE_OPTIONAL;
-      $f->reference = '\grpc\testing\Payload';
-      $descriptor->addField($f);
-
-      foreach (self::$__extensions as $cb) {
-        $descriptor->addField($cb(), true);
-      }
-
-      return $descriptor;
-    }
-
-    /**
-     * Check if <payload> has a value
-     *
-     * @return boolean
-     */
-    public function hasPayload(){
-      return $this->_has(1);
-    }
-
-    /**
-     * Clear <payload> value
-     *
-     * @return \grpc\testing\StreamingOutputCallResponse
-     */
-    public function clearPayload(){
-      return $this->_clear(1);
-    }
-
-    /**
-     * Get <payload> value
-     *
-     * @return \grpc\testing\Payload
-     */
-    public function getPayload(){
-      return $this->_get(1);
-    }
-
-    /**
-     * Set <payload> value
-     *
-     * @param \grpc\testing\Payload $value
-     * @return \grpc\testing\StreamingOutputCallResponse
-     */
-    public function setPayload(\grpc\testing\Payload $value){
-      return $this->_set(1, $value);
-    }
-  }
-}
-
diff --git a/src/php/tests/interop/messages.proto b/src/php/tests/interop/messages.proto
new file mode 100644
index 0000000..de0b1a2
--- /dev/null
+++ b/src/php/tests/interop/messages.proto
@@ -0,0 +1,132 @@
+
+// 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.
+
+// Message definitions to be used by integration test service definitions.
+
+syntax = "proto2";
+
+package grpc.testing;
+
+// The type of payload that should be returned.
+enum PayloadType {
+  // Compressable text format.
+  COMPRESSABLE = 0;
+
+  // Uncompressable binary format.
+  UNCOMPRESSABLE = 1;
+
+  // Randomly chosen from all other formats defined in this enum.
+  RANDOM = 2;
+}
+
+// A block of data, to simply increase gRPC message size.
+message Payload {
+  // The type of data in body.
+  optional PayloadType type = 1 [default = COMPRESSABLE];
+  // Primary contents of payload.
+  optional bytes body = 2;
+}
+
+// Unary request.
+message SimpleRequest {
+  // Desired payload type in the response from the server.
+  // If response_type is RANDOM, server randomly chooses one from other formats.
+  optional PayloadType response_type = 1 [default = COMPRESSABLE];
+
+  // Desired payload size in the response from the server.
+  // If response_type is COMPRESSABLE, this denotes the size before compression.
+  optional int32 response_size = 2;
+
+  // Optional input payload sent along with the request.
+  optional Payload payload = 3;
+
+  // Whether SimpleResponse should include username.
+  optional bool fill_username = 4;
+
+  // Whether SimpleResponse should include OAuth scope.
+  optional bool fill_oauth_scope = 5;
+}
+
+// Unary response, as configured by the request.
+message SimpleResponse {
+  // Payload to increase message size.
+  optional Payload payload = 1;
+  // The user the request came from, for verifying authentication was
+  // successful when the client expected it.
+  optional string username = 2;
+  // OAuth scope.
+  optional string oauth_scope = 3;
+}
+
+// Client-streaming request.
+message StreamingInputCallRequest {
+  // Optional input payload sent along with the request.
+  optional Payload payload = 1;
+
+  // Not expecting any payload from the response.
+}
+
+// Client-streaming response.
+message StreamingInputCallResponse {
+  // Aggregated size of payloads received from the client.
+  optional int32 aggregated_payload_size = 1;
+}
+
+// Configuration for a particular response.
+message ResponseParameters {
+  // Desired payload sizes in responses from the server.
+  // If response_type is COMPRESSABLE, this denotes the size before compression.
+  optional int32 size = 1;
+
+  // Desired interval between consecutive responses in the response stream in
+  // microseconds.
+  optional int32 interval_us = 2;
+}
+
+// Server-streaming request.
+message StreamingOutputCallRequest {
+  // Desired payload type in the response from the server.
+  // If response_type is RANDOM, the payload from each response in the stream
+  // might be of different types. This is to simulate a mixed type of payload
+  // stream.
+  optional PayloadType response_type = 1 [default = COMPRESSABLE];
+
+  // Configuration for each expected response message.
+  repeated ResponseParameters response_parameters = 2;
+
+  // Optional input payload sent along with the request.
+  optional Payload payload = 3;
+}
+
+// Server-streaming response, as configured by the request and parameters.
+message StreamingOutputCallResponse {
+  // Payload to increase response size.
+  optional Payload payload = 1;
+}
diff --git a/src/php/tests/interop/test.php b/src/php/tests/interop/test.php
deleted file mode 100755
index 014bbc9..0000000
--- a/src/php/tests/interop/test.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: test/cpp/interop/test.proto
-//   Date: 2015-01-30 23:30:46
-
-namespace grpc\testing {
-
-  class TestServiceClient{
-
-    private $rpc_impl;
-
-    public function __construct($rpc_impl) {
-      $this->rpc_impl = $rpc_impl;
-    }
-    /**
-     * @param grpc\testing\EmptyMessage $input
-     */
-    public function EmptyCall(\grpc\testing\EmptyMessage $argument, $metadata = array()) {
-      return $this->rpc_impl->_simpleRequest('/grpc.testing.TestService/EmptyCall', $argument, '\grpc\testing\EmptyMessage::deserialize', $metadata);
-    }
-    /**
-     * @param grpc\testing\SimpleRequest $input
-     */
-    public function UnaryCall(\grpc\testing\SimpleRequest $argument, $metadata = array()) {
-      return $this->rpc_impl->_simpleRequest('/grpc.testing.TestService/UnaryCall', $argument, '\grpc\testing\SimpleResponse::deserialize', $metadata);
-    }
-    /**
-     * @param grpc\testing\StreamingOutputCallRequest $input
-     */
-    public function StreamingOutputCall($argument, $metadata = array()) {
-      return $this->rpc_impl->_serverStreamRequest('/grpc.testing.TestService/StreamingOutputCall', $argument, '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
-    }
-    /**
-     * @param grpc\testing\StreamingInputCallRequest $input
-     */
-    public function StreamingInputCall($arguments, $metadata = array()) {
-      return $this->rpc_impl->_clientStreamRequest('/grpc.testing.TestService/StreamingInputCall', $arguments, '\grpc\testing\StreamingInputCallResponse::deserialize', $metadata);
-    }
-    /**
-     * @param grpc\testing\StreamingOutputCallRequest $input
-     */
-    public function FullDuplexCall($metadata = array()) {
-      return $this->rpc_impl->_bidiRequest('/grpc.testing.TestService/FullDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
-    }
-    /**
-     * @param grpc\testing\StreamingOutputCallRequest $input
-     */
-    public function HalfDuplexCall($metadata = array()) {
-      return $this->rpc_impl->_bidiRequest('/grpc.testing.TestService/HalfDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
-    }
-  }
-}
diff --git a/src/php/tests/interop/test.proto b/src/php/tests/interop/test.proto
new file mode 100644
index 0000000..39c08f3
--- /dev/null
+++ b/src/php/tests/interop/test.proto
@@ -0,0 +1,72 @@
+
+// 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.
+
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+syntax = "proto2";
+
+import "empty.proto";
+import "messages.proto";
+
+package grpc.testing;
+
+// A simple service to test the various types of RPCs and experiment with
+// performance with various types of payload.
+service TestService {
+  // One empty request followed by one empty response.
+  rpc EmptyCall(grpc.testing.EmptyMessage) returns (grpc.testing.EmptyMessage);
+
+  // One request followed by one response.
+  // TODO(Issue 527): Describe required server behavior.
+  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
+
+  // One request followed by a sequence of responses (streamed download).
+  // The server returns the payload with client desired type and sizes.
+  rpc StreamingOutputCall(StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+
+  // A sequence of requests followed by one response (streamed upload).
+  // The server returns the aggregated size of client payload as the result.
+  rpc StreamingInputCall(stream StreamingInputCallRequest)
+      returns (StreamingInputCallResponse);
+
+  // A sequence of requests with each request served by the server immediately.
+  // As one request could lead to multiple responses, this interface
+  // demonstrates the idea of full duplexing.
+  rpc FullDuplexCall(stream StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+
+  // A sequence of requests followed by a sequence of responses.
+  // The server buffers all the client requests and then serves them in order. A
+  // stream of responses are returned to the client when the server starts with
+  // first request.
+  rpc HalfDuplexCall(stream StreamingOutputCallRequest)
+      returns (stream StreamingOutputCallResponse);
+}
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index 8bb0927..77a2d86 100755
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -36,65 +36,47 @@
   static $port;
 
   public static function setUpBeforeClass() {
-    $cq = new Grpc\CompletionQueue();
-    self::$server = new Grpc\Server($cq, []);
-    self::$port = self::$server->add_http2_port('0.0.0.0:0');
+    self::$server = new Grpc\Server([]);
+    self::$port = self::$server->addHttp2Port('0.0.0.0:0');
   }
 
   public function setUp() {
-    $this->cq = new Grpc\CompletionQueue();
     $this->channel = new Grpc\Channel('localhost:' . self::$port, []);
     $this->call = new Grpc\Call($this->channel,
                                 '/foo',
-                                Grpc\Timeval::inf_future());
+                                Grpc\Timeval::infFuture());
   }
 
-  /**
-   * @expectedException LogicException
-   * @expectedExceptionCode Grpc\CALL_ERROR_INVALID_FLAGS
-   * @expectedExceptionMessage invoke
-   */
-  public function testInvokeRejectsBadFlags() {
-    $this->call->invoke($this->cq, 0, 0, 0xDEADBEEF);
-  }
-
-  /**
-   * @expectedException LogicException
-   * @expectedExceptionCode Grpc\CALL_ERROR_NOT_ON_CLIENT
-   * @expectedExceptionMessage server_accept
-   */
-  public function testServerAcceptFailsCorrectly() {
-    $this->call->server_accept($this->cq, 0);
-  }
-
-  /* These test methods with assertTrue(true) at the end just check that the
-     method calls completed without errors. PHPUnit warns for tests with no
-     asserts, and this avoids that warning without changing the meaning of the
-     tests */
-
   public function testAddEmptyMetadata() {
-    $this->call->add_metadata([], 0);
-    /* Dummy assert: Checks that the previous call completed without error */
-    $this->assertTrue(true);
+    $batch = [
+        Grpc\OP_SEND_INITIAL_METADATA => []
+              ];
+    $result = $this->call->startBatch($batch);
+    $this->assertTrue($result->send_metadata);
   }
 
   public function testAddSingleMetadata() {
-    $this->call->add_metadata(['key' => ['value']], 0);
-    /* Dummy assert: Checks that the previous call completed without error */
-    $this->assertTrue(true);
+    $batch = [
+        Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value']]
+              ];
+    $result = $this->call->startBatch($batch);
+    $this->assertTrue($result->send_metadata);
   }
 
   public function testAddMultiValueMetadata() {
-    $this->call->add_metadata(['key' => ['value1', 'value2']], 0);
-    /* Dummy assert: Checks that the previous call completed without error */
-    $this->assertTrue(true);
+    $batch = [
+        Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value1', 'value2']]
+              ];
+    $result = $this->call->startBatch($batch);
+    $this->assertTrue($result->send_metadata);
   }
 
   public function testAddSingleAndMultiValueMetadata() {
-    $this->call->add_metadata(
-        ['key1' => ['value1'],
-         'key2' => ['value2', 'value3']], 0);
-    /* Dummy assert: Checks that the previous call completed without error */
-    $this->assertTrue(true);
+    $batch = [
+        Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'],
+                                          'key2' => ['value2', 'value3']]
+              ];
+    $result = $this->call->startBatch($batch);
+    $this->assertTrue($result->send_metadata);
   }
 }
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 0cbc506..296873f 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -33,81 +33,68 @@
  */
 class EndToEndTest extends PHPUnit_Framework_TestCase{
   public function setUp() {
-    $this->client_queue = new Grpc\CompletionQueue();
-    $this->server_queue = new Grpc\CompletionQueue();
-    $this->server = new Grpc\Server($this->server_queue, []);
-    $port = $this->server->add_http2_port('0.0.0.0:0');
+    $this->server = new Grpc\Server([]);
+    $port = $this->server->addHttp2Port('0.0.0.0:0');
     $this->channel = new Grpc\Channel('localhost:' . $port, []);
+    $this->server->start();
   }
 
   public function tearDown() {
     unset($this->channel);
     unset($this->server);
-    unset($this->client_queue);
-    unset($this->server_queue);
   }
 
   public function testSimpleRequestBody() {
-    $deadline = Grpc\Timeval::inf_future();
+    $deadline = Grpc\Timeval::infFuture();
     $status_text = 'xyz';
     $call = new Grpc\Call($this->channel,
                           'dummy_method',
                           $deadline);
-    $tag = 1;
-    $call->invoke($this->client_queue, $tag, $tag);
-    $server_tag = 2;
 
-    $call->writes_done($tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
+    $event = $call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
+                                       ]);
 
-    // check that a server rpc new was received
-    $this->server->start();
-    $this->server->request_call($server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_close);
+
+    $event = $this->server->requestCall();
+    $this->assertSame('dummy_method', $event->method);
+    $this->assertSame([], $event->metadata);
     $server_call = $event->call;
-    $this->assertNotNull($server_call);
-    $server_call->server_accept($this->server_queue, $server_tag);
 
-    $server_call->server_end_initial_metadata();
+    $event = $server_call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_STATUS_FROM_SERVER => [
+            'metadata' => [],
+            'code' => Grpc\STATUS_OK,
+            'details' => $status_text
+                                            ],
+        Grpc\OP_RECV_CLOSE_ON_SERVER => true
+                                        ]);
 
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_status);
+    $this->assertFalse($event->cancelled);
 
-    // the server sends the status
-    $server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
+    $event = $call->startBatch([
+        Grpc\OP_RECV_INITIAL_METADATA => true,
+        Grpc\OP_RECV_STATUS_ON_CLIENT => true
+                                 ]);
 
-    // the client gets CLIENT_METADATA_READ
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
-
-    // the client gets FINISHED
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-    $status = $event->data;
+    $this->assertSame([], $event->metadata);
+    $status = $event->status;
+    $this->assertSame([], $status->metadata);
     $this->assertSame(Grpc\STATUS_OK, $status->code);
     $this->assertSame($status_text, $status->details);
 
-    // and the server gets FINISHED
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-    $status = $event->data;
-
     unset($call);
     unset($server_call);
   }
 
   public function testClientServerFullRequestResponse() {
-    $deadline = Grpc\Timeval::inf_future();
+    $deadline = Grpc\Timeval::infFuture();
     $req_text = 'client_server_full_request_response';
     $reply_text = 'reply:client_server_full_request_response';
     $status_text = 'status:client_server_full_response_text';
@@ -115,79 +102,52 @@
     $call = new Grpc\Call($this->channel,
                           'dummy_method',
                           $deadline);
-    $tag = 1;
-    $call->invoke($this->client_queue, $tag, $tag);
 
-    $server_tag = 2;
+    $event = $call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
+        Grpc\OP_SEND_MESSAGE => $req_text
+                                       ]);
 
-    // the client writes
-    $call->start_write($req_text, $tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_close);
+    $this->assertTrue($event->send_message);
 
-    // check that a server rpc new was received
-    $this->server->start();
-    $this->server->request_call($server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
+    $event = $this->server->requestCall();
+    $this->assertSame('dummy_method', $event->method);
     $server_call = $event->call;
-    $this->assertNotNull($server_call);
-    $server_call->server_accept($this->server_queue, $server_tag);
 
-    $server_call->server_end_initial_metadata();
+    $event = $server_call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_MESSAGE => $reply_text,
+        Grpc\OP_SEND_STATUS_FROM_SERVER => [
+            'metadata' => [],
+            'code' => Grpc\STATUS_OK,
+            'details' => $status_text
+                                            ],
+        Grpc\OP_RECV_MESSAGE => true,
+        Grpc\OP_RECV_CLOSE_ON_SERVER => true,
+                                        ]);
 
-    // start the server read
-    $server_call->start_read($server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\READ, $event->type);
-    $this->assertSame($req_text, $event->data);
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_status);
+    $this->assertTrue($event->send_message);
+    $this->assertFalse($event->cancelled);
+    $this->assertSame($req_text, $event->message);
 
-    // the server replies
-    $server_call->start_write($reply_text, $server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
+    $event = $call->startBatch([
+        Grpc\OP_RECV_INITIAL_METADATA => true,
+        Grpc\OP_RECV_MESSAGE => true,
+        Grpc\OP_RECV_STATUS_ON_CLIENT => true,
+                                       ]);
 
-    // the client reads the metadata
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
-
-    // the client reads the reply
-    $call->start_read($tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\READ, $event->type);
-    $this->assertSame($reply_text, $event->data);
-
-    // the client sends writes done
-    $call->writes_done($tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
-
-    // the server sends the status
-    $server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
-
-    // the client gets FINISHED
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-    $status = $event->data;
+    $this->assertSame([], $event->metadata);
+    $this->assertSame($reply_text, $event->message);
+    $status = $event->status;
+    $this->assertSame([], $status->metadata);
     $this->assertSame(Grpc\STATUS_OK, $status->code);
     $this->assertSame($status_text, $status->details);
 
-    // and the server gets FINISHED
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-
     unset($call);
     unset($server_call);
   }
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index 896afea..0c18cd3 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -33,17 +33,16 @@
  */
 class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
   public function setUp() {
-    $this->client_queue = new Grpc\CompletionQueue();
-    $this->server_queue = new Grpc\CompletionQueue();
     $credentials = Grpc\Credentials::createSsl(
         file_get_contents(dirname(__FILE__) . '/../data/ca.pem'));
     $server_credentials = Grpc\ServerCredentials::createSsl(
         null,
         file_get_contents(dirname(__FILE__) . '/../data/server1.key'),
         file_get_contents(dirname(__FILE__) . '/../data/server1.pem'));
-    $this->server = new Grpc\Server($this->server_queue);
-    $port = $this->server->add_secure_http2_port('0.0.0.0:0',
-                                                 $server_credentials);
+    $this->server = new Grpc\Server();
+    $port = $this->server->addSecureHttp2Port('0.0.0.0:0',
+                                              $server_credentials);
+    $this->server->start();
     $this->channel = new Grpc\Channel(
         'localhost:' . $port,
         [
@@ -55,71 +54,59 @@
   public function tearDown() {
     unset($this->channel);
     unset($this->server);
-    unset($this->client_queue);
-    unset($this->server_queue);
   }
 
   public function testSimpleRequestBody() {
-    $this->server->start();
-    $deadline = Grpc\Timeval::inf_future();
+    $deadline = Grpc\Timeval::infFuture();
     $status_text = 'xyz';
     $call = new Grpc\Call($this->channel,
                           'dummy_method',
                           $deadline);
-    $tag = 1;
-    $call->invoke($this->client_queue, $tag, $tag);
-    $server_tag = 2;
 
-    $call->writes_done($tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
+    $event = $call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
+                                       ]);
 
-    // check that a server rpc new was received
-    $this->server->request_call($server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_close);
+
+    $event = $this->server->requestCall();
+    $this->assertSame('dummy_method', $event->method);
+    $this->assertSame([], $event->metadata);
     $server_call = $event->call;
-    $this->assertNotNull($server_call);
-    $server_call->server_accept($this->server_queue, $server_tag);
 
-    $server_call->server_end_initial_metadata();
+    $event = $server_call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_STATUS_FROM_SERVER => [
+            'metadata' => [],
+            'code' => Grpc\STATUS_OK,
+            'details' => $status_text
+                                            ],
+        Grpc\OP_RECV_CLOSE_ON_SERVER => true
+                                        ]);
 
-    // the server sends the status
-    $server_call->start_write_status(Grpc\STATUS_OK, $status_text, $server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_status);
+    $this->assertFalse($event->cancelled);
 
-    // the client gets CLIENT_METADATA_READ
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
+    $event = $call->startBatch([
+        Grpc\OP_RECV_INITIAL_METADATA => true,
+        Grpc\OP_RECV_STATUS_ON_CLIENT => true
+                                 ]);
 
-    // the client gets FINISHED
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-    $status = $event->data;
+    $this->assertSame([], $event->metadata);
+    $status = $event->status;
+    $this->assertSame([], $status->metadata);
     $this->assertSame(Grpc\STATUS_OK, $status->code);
     $this->assertSame($status_text, $status->details);
 
-    // and the server gets FINISHED
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-    $status = $event->data;
-
     unset($call);
     unset($server_call);
   }
 
   public function testClientServerFullRequestResponse() {
-    $this->server->start();
-    $deadline = Grpc\Timeval::inf_future();
+    $deadline = Grpc\Timeval::infFuture();
     $req_text = 'client_server_full_request_response';
     $reply_text = 'reply:client_server_full_request_response';
     $status_text = 'status:client_server_full_response_text';
@@ -127,78 +114,52 @@
     $call = new Grpc\Call($this->channel,
                           'dummy_method',
                           $deadline);
-    $tag = 1;
-    $call->invoke($this->client_queue, $tag, $tag);
 
-    $server_tag = 2;
+    $event = $call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
+        Grpc\OP_SEND_MESSAGE => $req_text
+                                       ]);
 
-    // the client writes
-    $call->start_write($req_text, $tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_close);
+    $this->assertTrue($event->send_message);
 
-    // check that a server rpc new was received
-    $this->server->request_call($server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\SERVER_RPC_NEW, $event->type);
+    $event = $this->server->requestCall();
+    $this->assertSame('dummy_method', $event->method);
     $server_call = $event->call;
-    $this->assertNotNull($server_call);
-    $server_call->server_accept($this->server_queue, $server_tag);
 
-    $server_call->server_end_initial_metadata();
+    $event = $server_call->startBatch([
+        Grpc\OP_SEND_INITIAL_METADATA => [],
+        Grpc\OP_SEND_MESSAGE => $reply_text,
+        Grpc\OP_SEND_STATUS_FROM_SERVER => [
+            'metadata' => [],
+            'code' => Grpc\STATUS_OK,
+            'details' => $status_text
+                                            ],
+        Grpc\OP_RECV_MESSAGE => true,
+        Grpc\OP_RECV_CLOSE_ON_SERVER => true,
+                                        ]);
 
-    // start the server read
-    $server_call->start_read($server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\READ, $event->type);
-    $this->assertSame($req_text, $event->data);
+    $this->assertTrue($event->send_metadata);
+    $this->assertTrue($event->send_status);
+    $this->assertTrue($event->send_message);
+    $this->assertFalse($event->cancelled);
+    $this->assertSame($req_text, $event->message);
 
-    // the server replies
-    $server_call->start_write($reply_text, $server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\WRITE_ACCEPTED, $event->type);
+    $event = $call->startBatch([
+        Grpc\OP_RECV_INITIAL_METADATA => true,
+        Grpc\OP_RECV_MESSAGE => true,
+        Grpc\OP_RECV_STATUS_ON_CLIENT => true,
+                                       ]);
 
-    // the client reads the metadata
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\CLIENT_METADATA_READ, $event->type);
-
-    // the client reads the reply
-    $call->start_read($tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\READ, $event->type);
-    $this->assertSame($reply_text, $event->data);
-
-    // the client sends writes done
-    $call->writes_done($tag);
-    $event = $this->client_queue->next($deadline);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
-
-    // the server sends the status
-    $server_call->start_write_status(GRPC\STATUS_OK, $status_text, $server_tag);
-    $event = $this->server_queue->next($deadline);
-    $this->assertSame(Grpc\FINISH_ACCEPTED, $event->type);
-    $this->assertSame(Grpc\OP_OK, $event->data);
-
-    // the client gets FINISHED
-    $event = $this->client_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-    $status = $event->data;
+    $this->assertSame([], $event->metadata);
+    $this->assertSame($reply_text, $event->message);
+    $status = $event->status;
+    $this->assertSame([], $status->metadata);
     $this->assertSame(Grpc\STATUS_OK, $status->code);
     $this->assertSame($status_text, $status->details);
 
-    // and the server gets FINISHED
-    $event = $this->server_queue->next($deadline);
-    $this->assertNotNull($event);
-    $this->assertSame(Grpc\FINISHED, $event->type);
-
     unset($call);
     unset($server_call);
   }
diff --git a/src/php/tests/unit_tests/TimevalTest.php b/src/php/tests/unit_tests/TimevalTest.php
index d20069a..a8bfcf0 100755
--- a/src/php/tests/unit_tests/TimevalTest.php
+++ b/src/php/tests/unit_tests/TimevalTest.php
@@ -39,14 +39,14 @@
 
   public function testPastIsLessThanZero() {
     $zero = Grpc\Timeval::zero();
-    $past = Grpc\Timeval::inf_past();
+    $past = Grpc\Timeval::infPast();
     $this->assertLessThan(0, Grpc\Timeval::compare($past, $zero));
     $this->assertGreaterThan(0, Grpc\Timeval::compare($zero, $past));
   }
 
   public function testFutureIsGreaterThanZero() {
     $zero = Grpc\Timeval::zero();
-    $future = Grpc\Timeval::inf_future();
+    $future = Grpc\Timeval::infFuture();
     $this->assertLessThan(0, Grpc\Timeval::compare($zero, $future));
     $this->assertGreaterThan(0, Grpc\Timeval::compare($future, $zero));
   }
@@ -56,7 +56,7 @@
    */
   public function testNowIsBetweenZeroAndFuture() {
     $zero = Grpc\Timeval::zero();
-    $future = Grpc\Timeval::inf_future();
+    $future = Grpc\Timeval::infFuture();
     $now = Grpc\Timeval::now();
     $this->assertLessThan(0, Grpc\Timeval::compare($zero, $now));
     $this->assertLessThan(0, Grpc\Timeval::compare($now, $future));
diff --git a/src/python/README.md b/src/python/README.md
index c8057be..82bc776 100644
--- a/src/python/README.md
+++ b/src/python/README.md
@@ -42,7 +42,14 @@
 Installing
 -----------------------
 
-- [Install the gRPC core](https://github.com/grpc/grpc/blob/master/INSTALL)
+- Install the gRPC core
+  - [Debian package](https://github.com/grpc/grpc/releases)
+    ```
+    $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc_0.5.0_amd64.deb
+    $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc-dev_0.5.0_amd64.deb
+    $ sudo dpkg -i libgrpc_0.5.0_amd64.deb libgrpc-dev_0.5.0_amd64.deb
+    ```
+  - [From source](https://github.com/grpc/grpc/blob/master/INSTALL)
 
 - Install gRPC Python's dependencies
 ```
@@ -53,3 +60,16 @@
 ```
 $ pip install src/python/src
 ```
+
+Packaging to PyPI
+-----------------------
+
+- Install packaging dependencies
+```
+$ pip install setuptools twine
+```
+
+- Push to PyPI
+```
+$ ../../tools/distrib/python/submit.py
+```
diff --git a/src/python/interop/interop/_insecure_interop_test.py b/src/python/interop/interop/_insecure_interop_test.py
index e4ddff1..42e7a4d 100644
--- a/src/python/interop/interop/_insecure_interop_test.py
+++ b/src/python/interop/interop/_insecure_interop_test.py
@@ -42,11 +42,11 @@
     unittest.TestCase):
 
   def setUp(self):
-    self.server = implementations.insecure_server(
+    self.server = implementations.server(
         methods.SERVICE_NAME, methods.SERVER_METHODS, 0)
     self.server.start()
     port = self.server.port()
-    self.stub = implementations.insecure_stub(
+    self.stub = implementations.stub(
         methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port)
 
   def tearDown(self):
diff --git a/src/python/interop/interop/_interop_test_case.py b/src/python/interop/interop/_interop_test_case.py
index fec8f19..cd6a574 100644
--- a/src/python/interop/interop/_interop_test_case.py
+++ b/src/python/interop/interop/_interop_test_case.py
@@ -40,16 +40,16 @@
   """
 
   def testEmptyUnary(self):
-    methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub)
+    methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub, None)
 
   def testLargeUnary(self):
-    methods.TestCase.LARGE_UNARY.test_interoperability(self.stub)
+    methods.TestCase.LARGE_UNARY.test_interoperability(self.stub, None)
 
   def testServerStreaming(self):
-    methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub)
+    methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub, None)
 
   def testClientStreaming(self):
-    methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub)
+    methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub, None)
 
   def testPingPong(self):
-    methods.TestCase.PING_PONG.test_interoperability(self.stub)
+    methods.TestCase.PING_PONG.test_interoperability(self.stub, None)
diff --git a/src/python/interop/interop/_secure_interop_test.py b/src/python/interop/interop/_secure_interop_test.py
index 214212d..27e7631 100644
--- a/src/python/interop/interop/_secure_interop_test.py
+++ b/src/python/interop/interop/_secure_interop_test.py
@@ -45,14 +45,15 @@
     unittest.TestCase):
 
   def setUp(self):
-    self.server = implementations.secure_server(
+    self.server = implementations.server(
         methods.SERVICE_NAME, methods.SERVER_METHODS, 0,
-        resources.private_key(), resources.certificate_chain())
+        private_key=resources.private_key(),
+        certificate_chain=resources.certificate_chain())
     self.server.start()
     port = self.server.port()
-    self.stub = implementations.secure_stub(
+    self.stub = implementations.stub(
         methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port,
-        resources.test_root_certificates(), None, None,
+        secure=True, root_certificates=resources.test_root_certificates(),
         server_host_override=_SERVER_HOST_OVERRIDE)
 
   def tearDown(self):
diff --git a/src/python/interop/interop/client.py b/src/python/interop/interop/client.py
index fb7dfb5..bae5e17 100644
--- a/src/python/interop/interop/client.py
+++ b/src/python/interop/interop/client.py
@@ -30,6 +30,7 @@
 """The Python implementation of the GRPC interoperability test client."""
 
 import argparse
+from oauth2client import client as oauth2client_client
 
 from grpc.early_adopter import implementations
 
@@ -44,9 +45,6 @@
   parser.add_argument(
       '--server_host', help='the host to which to connect', type=str)
   parser.add_argument(
-      '--server_host_override',
-      help='the server host to which to claim to connect', type=str)
-  parser.add_argument(
       '--server_port', help='the port to which to connect', type=int)
   parser.add_argument(
       '--test_case', help='the test case to execute', type=str)
@@ -56,24 +54,40 @@
   parser.add_argument(
       '--use_test_ca', help='replace platform root CAs with ca.pem',
       action='store_true')
+  parser.add_argument(
+      '--server_host_override',
+      help='the server host to which to claim to connect', type=str)
+  parser.add_argument('--oauth_scope', help='scope for OAuth tokens', type=str)
+  parser.add_argument(
+      '--default_service_account',
+      help='email address of the default service account', type=str)
   return parser.parse_args()
 
+def _oauth_access_token(args):
+  credentials = client.GoogleCredentials.get_application_default()
+  scoped_credentials = credentials.create_scoped([args.oauth_scope])
+  return scoped_credentials.get_access_token().access_token
 
 def _stub(args):
+  if args.oauth_scope:
+    metadata_transformer = lambda x: [('Authorization', 'Bearer %s' % _oauth_access_token(args))]
+  else:
+    metadata_transformer = lambda x: []
   if args.use_tls:
     if args.use_test_ca:
       root_certificates = resources.test_root_certificates()
     else:
       root_certificates = resources.prod_root_certificates()
 
-    stub = implementations.secure_stub(
+    stub = implementations.stub(
         methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
-        args.server_port, root_certificates, None, None,
+        args.server_port, metadata_transformer=metadata_transformer,
+        secure=True, root_certificates=root_certificates,
         server_host_override=args.server_host_override)
   else:
-    stub = implementations.insecure_stub(
+    stub = implementations.stub(
         methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
-        args.server_port)
+        args.server_port, secure=False)
   return stub
 
 
@@ -89,7 +103,7 @@
   args = _args()
   stub = _stub(args)
   test_case = _test_case_from_arg(args.test_case)
-  test_case.test_interoperability(stub)
+  test_case.test_interoperability(stub, args)
 
 
 if __name__ == '__main__':
diff --git a/src/python/interop/interop/empty_pb2.py b/src/python/interop/interop/empty_pb2.py
index 732a358..8c1ce2f 100644
--- a/src/python/interop/interop/empty_pb2.py
+++ b/src/python/interop/interop/empty_pb2.py
@@ -57,6 +57,7 @@
 _sym_db.RegisterMessage(Empty)
 
 
-from grpc.framework.face import demonstration as _face_testing
-from grpc.framework.face import interfaces as _face_interfaces
+import abc
+from grpc.early_adopter import implementations
+from grpc.framework.alpha import utilities
 # @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/messages_pb2.py b/src/python/interop/interop/messages_pb2.py
index d449a99..0bf3d86 100644
--- a/src/python/interop/interop/messages_pb2.py
+++ b/src/python/interop/interop/messages_pb2.py
@@ -441,6 +441,7 @@
 _sym_db.RegisterMessage(StreamingOutputCallResponse)
 
 
-from grpc.framework.face import demonstration as _face_testing
-from grpc.framework.face import interfaces as _face_interfaces
+import abc
+from grpc.early_adopter import implementations
+from grpc.framework.alpha import utilities
 # @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/methods.py b/src/python/interop/interop/methods.py
index 79550a3..c69771d 100644
--- a/src/python/interop/interop/methods.py
+++ b/src/python/interop/interop/methods.py
@@ -30,8 +30,12 @@
 """Implementations of interoperability test methods."""
 
 import enum
+import json
+import os
 import threading
 
+from oauth2client import client as oauth2client_client
+
 from grpc.framework.alpha import utilities
 
 from interop import empty_pb2
@@ -150,6 +154,23 @@
 }
 
 
+def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope):
+  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.async(request, _TIMEOUT)
+    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))
+    return response
+
+
 def _empty_unary(stub):
   with stub:
     response = stub.EmptyCall(empty_pb2.Empty(), _TIMEOUT)
@@ -159,18 +180,7 @@
 
 
 def _large_unary(stub):
-  with stub:
-    request = messages_pb2.SimpleRequest(
-        response_type=messages_pb2.COMPRESSABLE, response_size=314159,
-        payload=messages_pb2.Payload(body=b'\x00' * 271828))
-    response_future = stub.UnaryCall.async(request, _TIMEOUT)
-    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))
+  _large_unary_common_behavior(stub, False, False)
 
 
 def _client_streaming(stub):
@@ -266,6 +276,28 @@
     pipe.close()
 
 
+def _compute_engine_creds(stub, args):
+  response = _large_unary_common_behavior(stub, True, True)
+  if args.default_service_account != response.username:
+    raise ValueError(
+        'expected username %s, got %s' % (args.default_service_account,
+                                          response.username))
+
+
+def _service_account_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, True)
+  if wanted_email != response.username:
+    raise ValueError(
+        'expected username %s, got %s' % (wanted_email, response.username))
+  if response.oauth_scope in args.oauth_scope:
+    raise ValueError(
+        'expected to find oauth scope "%s" in received "%s"' %
+            (response.oauth_scope, args.oauth_scope))
+
+
 @enum.unique
 class TestCase(enum.Enum):
   EMPTY_UNARY = 'empty_unary'
@@ -273,8 +305,10 @@
   SERVER_STREAMING = 'server_streaming'
   CLIENT_STREAMING = 'client_streaming'
   PING_PONG = 'ping_pong'
+  COMPUTE_ENGINE_CREDS = 'compute_engine_creds'
+  SERVICE_ACCOUNT_CREDS = 'service_account_creds'
 
-  def test_interoperability(self, stub):
+  def test_interoperability(self, stub, args):
     if self is TestCase.EMPTY_UNARY:
       _empty_unary(stub)
     elif self is TestCase.LARGE_UNARY:
@@ -285,5 +319,9 @@
       _client_streaming(stub)
     elif self is TestCase.PING_PONG:
       _ping_pong(stub)
+    elif self is TestCase.COMPUTE_ENGINE_CREDS:
+      _compute_engine_creds(stub, args)
+    elif self is TestCase.SERVICE_ACCOUNT_CREDS:
+      _service_account_creds(stub, args)
     else:
       raise NotImplementedError('Test case "%s" not implemented!' % self.name)
diff --git a/src/python/interop/interop/server.py b/src/python/interop/interop/server.py
index 5791203..a67d412 100644
--- a/src/python/interop/interop/server.py
+++ b/src/python/interop/interop/server.py
@@ -53,11 +53,11 @@
   if args.use_tls:
     private_key = resources.private_key()
     certificate_chain = resources.certificate_chain()
-    server = implementations.secure_server(
-        methods.SERVICE_NAME, methods.SERVER_METHODS, args.port, private_key,
-        certificate_chain)
+    server = implementations.server(
+        methods.SERVICE_NAME, methods.SERVER_METHODS, args.port,
+        private_key=private_key, certificate_chain=certificate_chain)
   else:
-    server = implementations.insecure_server(
+    server = implementations.server(
         methods.SERVICE_NAME, methods.SERVER_METHODS, args.port)
 
   server.start()
diff --git a/src/python/interop/interop/test_pb2.py b/src/python/interop/interop/test_pb2.py
index e860946..71325d5 100644
--- a/src/python/interop/interop/test_pb2.py
+++ b/src/python/interop/interop/test_pb2.py
@@ -29,121 +29,150 @@
 
 
 
-from grpc.framework.face import demonstration as _face_testing
-from grpc.framework.face import interfaces as _face_interfaces
-class TestServiceService(object):
+import abc
+from grpc.early_adopter import implementations
+from grpc.framework.alpha import utilities
+class EarlyAdopterTestServiceServicer(object):
   """<fill me in later!>"""
-  def __init__(self):
-    pass
-class TestServiceServicer(object):
+  __metaclass__ = abc.ABCMeta
+  @abc.abstractmethod
+  def EmptyCall(self, request, context):
+    raise NotImplementedError()
+  @abc.abstractmethod
+  def UnaryCall(self, request, context):
+    raise NotImplementedError()
+  @abc.abstractmethod
+  def StreamingOutputCall(self, request, context):
+    raise NotImplementedError()
+  @abc.abstractmethod
+  def StreamingInputCall(self, request_iterator, context):
+    raise NotImplementedError()
+  @abc.abstractmethod
+  def FullDuplexCall(self, request_iterator, context):
+    raise NotImplementedError()
+  @abc.abstractmethod
+  def HalfDuplexCall(self, request_iterator, context):
+    raise NotImplementedError()
+class EarlyAdopterTestServiceServer(object):
   """<fill me in later!>"""
-  def EmptyCall(self, arg):
+  __metaclass__ = abc.ABCMeta
+  @abc.abstractmethod
+  def start(self):
     raise NotImplementedError()
-  def UnaryCall(self, arg):
+  @abc.abstractmethod
+  def stop(self):
     raise NotImplementedError()
-  def StreamingOutputCall(self, arg):
-    raise NotImplementedError()
-  def StreamingInputCall(self, arg):
-    raise NotImplementedError()
-  def FullDuplexCall(self, arg):
-    raise NotImplementedError()
-  def HalfDuplexCall(self, arg):
-    raise NotImplementedError()
-class TestServiceStub(object):
+class EarlyAdopterTestServiceStub(object):
   """<fill me in later!>"""
-  def EmptyCall(self, arg):
+  __metaclass__ = abc.ABCMeta
+  @abc.abstractmethod
+  def EmptyCall(self, request):
     raise NotImplementedError()
   EmptyCall.async = None
-  def UnaryCall(self, arg):
+  @abc.abstractmethod
+  def UnaryCall(self, request):
     raise NotImplementedError()
   UnaryCall.async = None
-  def StreamingOutputCall(self, arg):
+  @abc.abstractmethod
+  def StreamingOutputCall(self, request):
     raise NotImplementedError()
   StreamingOutputCall.async = None
-  def StreamingInputCall(self, arg):
+  @abc.abstractmethod
+  def StreamingInputCall(self, request_iterator):
     raise NotImplementedError()
   StreamingInputCall.async = None
-  def FullDuplexCall(self, arg):
+  @abc.abstractmethod
+  def FullDuplexCall(self, request_iterator):
     raise NotImplementedError()
   FullDuplexCall.async = None
-  def HalfDuplexCall(self, arg):
+  @abc.abstractmethod
+  def HalfDuplexCall(self, request_iterator):
     raise NotImplementedError()
   HalfDuplexCall.async = None
-class _TestServiceStub(TestServiceStub):
-  def __init__(self, face_stub, default_timeout):
-    self._face_stub = face_stub
-    self._default_timeout = default_timeout
-    stub_self = self
-    class EmptyCall(object):
-      def __call__(self, arg):
-        return stub_self._face_stub.blocking_value_in_value_out("EmptyCall", arg, stub_self._default_timeout)
-      def async(self, arg):
-        return stub_self._face_stub.future_value_in_value_out("EmptyCall", arg, stub_self._default_timeout)
-    self.EmptyCall = EmptyCall()
-    class UnaryCall(object):
-      def __call__(self, arg):
-        return stub_self._face_stub.blocking_value_in_value_out("UnaryCall", arg, stub_self._default_timeout)
-      def async(self, arg):
-        return stub_self._face_stub.future_value_in_value_out("UnaryCall", arg, stub_self._default_timeout)
-    self.UnaryCall = UnaryCall()
-    class StreamingOutputCall(object):
-      def __call__(self, arg):
-        return stub_self._face_stub.inline_value_in_stream_out("StreamingOutputCall", arg, stub_self._default_timeout)
-      def async(self, arg):
-        return stub_self._face_stub.inline_value_in_stream_out("StreamingOutputCall", arg, stub_self._default_timeout)
-    self.StreamingOutputCall = StreamingOutputCall()
-    class StreamingInputCall(object):
-      def __call__(self, arg):
-        return stub_self._face_stub.blocking_stream_in_value_out("StreamingInputCall", arg, stub_self._default_timeout)
-      def async(self, arg):
-        return stub_self._face_stub.future_stream_in_value_out("StreamingInputCall", arg, stub_self._default_timeout)
-    self.StreamingInputCall = StreamingInputCall()
-    class FullDuplexCall(object):
-      def __call__(self, arg):
-        return stub_self._face_stub.inline_stream_in_stream_out("FullDuplexCall", arg, stub_self._default_timeout)
-      def async(self, arg):
-        return stub_self._face_stub.inline_stream_in_stream_out("FullDuplexCall", arg, stub_self._default_timeout)
-    self.FullDuplexCall = FullDuplexCall()
-    class HalfDuplexCall(object):
-      def __call__(self, arg):
-        return stub_self._face_stub.inline_stream_in_stream_out("HalfDuplexCall", arg, stub_self._default_timeout)
-      def async(self, arg):
-        return stub_self._face_stub.inline_stream_in_stream_out("HalfDuplexCall", arg, stub_self._default_timeout)
-    self.HalfDuplexCall = HalfDuplexCall()
-def mock_TestService(servicer, default_timeout):
-  value_in_value_out = {}
-  value_in_stream_out = {}
-  stream_in_value_out = {}
-  stream_in_stream_out = {}
-  class EmptyCall(_face_interfaces.InlineValueInValueOutMethod):
-    def service(self, request, context):
-      return servicer.EmptyCall(request)
-  value_in_value_out['EmptyCall'] = EmptyCall()
-  class UnaryCall(_face_interfaces.InlineValueInValueOutMethod):
-    def service(self, request, context):
-      return servicer.UnaryCall(request)
-  value_in_value_out['UnaryCall'] = UnaryCall()
-  class StreamingOutputCall(_face_interfaces.InlineValueInStreamOutMethod):
-    def service(self, request, context):
-      return servicer.StreamingOutputCall(request)
-  value_in_stream_out['StreamingOutputCall'] = StreamingOutputCall()
-  class StreamingInputCall(_face_interfaces.InlineStreamInValueOutMethod):
-    def service(self, request, context):
-      return servicer.StreamingInputCall(request)
-  stream_in_value_out['StreamingInputCall'] = StreamingInputCall()
-  class FullDuplexCall(_face_interfaces.InlineStreamInStreamOutMethod):
-    def service(self, request, context):
-      return servicer.FullDuplexCall(request)
-  stream_in_stream_out['FullDuplexCall'] = FullDuplexCall()
-  class HalfDuplexCall(_face_interfaces.InlineStreamInStreamOutMethod):
-    def service(self, request, context):
-      return servicer.HalfDuplexCall(request)
-  stream_in_stream_out['HalfDuplexCall'] = HalfDuplexCall()
-  face_linked_pair = _face_testing.server_and_stub(default_timeout,inline_value_in_value_out_methods=value_in_value_out,inline_value_in_stream_out_methods=value_in_stream_out,inline_stream_in_value_out_methods=stream_in_value_out,inline_stream_in_stream_out_methods=stream_in_stream_out)
-  class LinkedPair(object):
-    def __init__(self, server, stub):
-      self.server = server
-      self.stub = stub
-  stub = _TestServiceStub(face_linked_pair.stub, default_timeout)
-  return LinkedPair(None, stub)
+def early_adopter_create_TestService_server(servicer, port, private_key=None, certificate_chain=None):
+  import test.cpp.interop.empty_pb2
+  import test.cpp.interop.empty_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  method_service_descriptions = {
+    "EmptyCall": utilities.unary_unary_service_description(
+      servicer.EmptyCall,
+      test.cpp.interop.empty_pb2.Empty.FromString,
+      test.cpp.interop.empty_pb2.Empty.SerializeToString,
+    ),
+    "FullDuplexCall": utilities.stream_stream_service_description(
+      servicer.FullDuplexCall,
+      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
+      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
+    ),
+    "HalfDuplexCall": utilities.stream_stream_service_description(
+      servicer.HalfDuplexCall,
+      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
+      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
+    ),
+    "StreamingInputCall": utilities.stream_unary_service_description(
+      servicer.StreamingInputCall,
+      test.cpp.interop.messages_pb2.StreamingInputCallRequest.FromString,
+      test.cpp.interop.messages_pb2.StreamingInputCallResponse.SerializeToString,
+    ),
+    "StreamingOutputCall": utilities.unary_stream_service_description(
+      servicer.StreamingOutputCall,
+      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
+      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
+    ),
+    "UnaryCall": utilities.unary_unary_service_description(
+      servicer.UnaryCall,
+      test.cpp.interop.messages_pb2.SimpleRequest.FromString,
+      test.cpp.interop.messages_pb2.SimpleResponse.SerializeToString,
+    ),
+  }
+  return implementations.server("grpc.testing.TestService", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain)
+def early_adopter_create_TestService_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None):
+  import test.cpp.interop.empty_pb2
+  import test.cpp.interop.empty_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  import test.cpp.interop.messages_pb2
+  method_invocation_descriptions = {
+    "EmptyCall": utilities.unary_unary_invocation_description(
+      test.cpp.interop.empty_pb2.Empty.SerializeToString,
+      test.cpp.interop.empty_pb2.Empty.FromString,
+    ),
+    "FullDuplexCall": utilities.stream_stream_invocation_description(
+      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
+      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
+    ),
+    "HalfDuplexCall": utilities.stream_stream_invocation_description(
+      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
+      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
+    ),
+    "StreamingInputCall": utilities.stream_unary_invocation_description(
+      test.cpp.interop.messages_pb2.StreamingInputCallRequest.SerializeToString,
+      test.cpp.interop.messages_pb2.StreamingInputCallResponse.FromString,
+    ),
+    "StreamingOutputCall": utilities.unary_stream_invocation_description(
+      test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
+      test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
+    ),
+    "UnaryCall": utilities.unary_unary_invocation_description(
+      test.cpp.interop.messages_pb2.SimpleRequest.SerializeToString,
+      test.cpp.interop.messages_pb2.SimpleResponse.FromString,
+    ),
+  }
+  return implementations.stub("grpc.testing.TestService", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override)
 # @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/setup.py b/src/python/interop/setup.py
index 6db5435..502fcbe 100644
--- a/src/python/interop/setup.py
+++ b/src/python/interop/setup.py
@@ -29,7 +29,7 @@
 
 """A setup module for the GRPC Python interop testing package."""
 
-from distutils import core as _core
+import setuptools
 
 _PACKAGES = (
     'interop',
@@ -45,9 +45,13 @@
         'credentials/server1.pem',]
 }
 
-_INSTALL_REQUIRES = ['grpc-2015>=0.0.1']
+_INSTALL_REQUIRES = ['oauth2client>=1.4.7', 'grpcio>=0.4.0a4']
 
-_core.setup(
-    name='interop', version='0.0.1', packages=_PACKAGES,
-    package_dir=_PACKAGE_DIRECTORIES, package_data=_PACKAGE_DATA,
-    install_requires=_INSTALL_REQUIRES)
+setuptools.setup(
+    name='interop',
+    version='0.0.1',
+    packages=_PACKAGES,
+    package_dir=_PACKAGE_DIRECTORIES,
+    package_data=_PACKAGE_DATA,
+    install_requires=_INSTALL_REQUIRES
+)
diff --git a/src/python/src/.gitignore b/src/python/src/.gitignore
new file mode 100644
index 0000000..bc15a52
--- /dev/null
+++ b/src/python/src/.gitignore
@@ -0,0 +1,3 @@
+MANIFEST
+grpcio.egg-info/
+dist/
diff --git a/src/python/src/MANIFEST.in b/src/python/src/MANIFEST.in
new file mode 100644
index 0000000..6f32db0
--- /dev/null
+++ b/src/python/src/MANIFEST.in
@@ -0,0 +1 @@
+graft grpc
diff --git a/src/python/src/README.rst b/src/python/src/README.rst
new file mode 100644
index 0000000..bc1815f
--- /dev/null
+++ b/src/python/src/README.rst
@@ -0,0 +1,27 @@
+gRPC Python
+===========
+
+Package for GRPC Python.
+
+Dependencies
+------------
+
+Ensure that you have installed GRPC core.
+
+On debian linux systems, install from our released deb package:
+
+::
+
+  $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc_0.5.0_amd64.deb
+  $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc-dev_0.5.0_amd64.deb
+  $ sudo dpkg -i libgrpc_0.5.0_amd64.deb libgrpc-dev_0.5.0_amd64.deb
+
+Otherwise, install from source:
+
+::
+
+  git clone https://github.com/grpc/grpc.git
+  cd grpc
+  ./configure
+  make && make install
+
diff --git a/src/python/src/grpc/_adapter/_call.c b/src/python/src/grpc/_adapter/_call.c
index d8806e5..bf96c1a 100644
--- a/src/python/src/grpc/_adapter/_call.c
+++ b/src/python/src/grpc/_adapter/_call.c
@@ -160,8 +160,22 @@
   return result;
 }
 
+static const PyObject *pygrpc_call_add_metadata(Call *self, PyObject *args) {
+  const char* key = NULL;
+  const char* value = NULL;
+  int value_length = 0;
+  grpc_metadata metadata;
+  if (!PyArg_ParseTuple(args, "ss#", &key, &value, &value_length)) {
+    return NULL;
+  }
+  metadata.key = key;
+  metadata.value = value;
+  metadata.value_length = value_length;
+  return pygrpc_translate_call_error(
+      grpc_call_add_metadata_old(self->c_call, &metadata, 0));
+}
+
 static const PyObject *pygrpc_call_premetadata(Call *self) {
-  /* TODO(nathaniel): Metadata support. */
   return pygrpc_translate_call_error(
       grpc_call_server_end_initial_metadata_old(self->c_call, 0));
 }
@@ -236,6 +250,11 @@
     {"complete", (PyCFunction)pygrpc_call_complete, METH_O,
      "Complete writes to this call."},
     {"accept", (PyCFunction)pygrpc_call_accept, METH_VARARGS, "Accept an RPC."},
+    {"add_metadata", (PyCFunction)pygrpc_call_add_metadata, METH_VARARGS,
+     "Add metadata to the call. May not be called after invoke on the client "
+     "side. On the server side: when called before premetadata it provides "
+     "'leading' metadata, when called after premetadata but before status it "
+     "provides 'trailing metadata'; may not be called after status."},
     {"premetadata", (PyCFunction)pygrpc_call_premetadata, METH_VARARGS,
      "Indicate the end of leading metadata in the response."},
     {"read", (PyCFunction)pygrpc_call_read, METH_O,
diff --git a/src/python/src/grpc/_adapter/_call.h b/src/python/src/grpc/_adapter/_call.h
index a936e23..c04a228 100644
--- a/src/python/src/grpc/_adapter/_call.h
+++ b/src/python/src/grpc/_adapter/_call.h
@@ -37,7 +37,10 @@
 #include <Python.h>
 #include <grpc/grpc.h>
 
-typedef struct { PyObject_HEAD grpc_call *c_call; } Call;
+typedef struct {
+  PyObject_HEAD
+  grpc_call *c_call;
+} Call;
 
 PyTypeObject pygrpc_CallType;
 
diff --git a/src/python/src/grpc/_adapter/_channel.h b/src/python/src/grpc/_adapter/_channel.h
index 6241ccd..afc0f80 100644
--- a/src/python/src/grpc/_adapter/_channel.h
+++ b/src/python/src/grpc/_adapter/_channel.h
@@ -37,7 +37,10 @@
 #include <Python.h>
 #include <grpc/grpc.h>
 
-typedef struct { PyObject_HEAD grpc_channel *c_channel; } Channel;
+typedef struct {
+  PyObject_HEAD
+  grpc_channel *c_channel;
+} Channel;
 
 PyTypeObject pygrpc_ChannelType;
 
diff --git a/src/python/src/grpc/_adapter/_client_credentials.h b/src/python/src/grpc/_adapter/_client_credentials.h
index 664dc80..bb9f7f0 100644
--- a/src/python/src/grpc/_adapter/_client_credentials.h
+++ b/src/python/src/grpc/_adapter/_client_credentials.h
@@ -38,7 +38,8 @@
 #include <grpc/grpc_security.h>
 
 typedef struct {
-  PyObject_HEAD grpc_credentials *c_client_credentials;
+  PyObject_HEAD
+  grpc_credentials *c_client_credentials;
 } ClientCredentials;
 
 PyTypeObject pygrpc_ClientCredentialsType;
diff --git a/src/python/src/grpc/_adapter/_completion_queue.c b/src/python/src/grpc/_adapter/_completion_queue.c
index b56ca19..a639eff 100644
--- a/src/python/src/grpc/_adapter/_completion_queue.c
+++ b/src/python/src/grpc/_adapter/_completion_queue.c
@@ -115,35 +115,56 @@
   }
 }
 
+static PyObject *pygrpc_metadata_collection_get(
+    grpc_metadata *metadata_elements, size_t count) {
+  PyObject *metadata = PyList_New(count);
+  size_t i;
+  for (i = 0; i < count; ++i) {
+    grpc_metadata elem = metadata_elements[i];
+    PyObject *key = PyString_FromString(elem.key);
+    PyObject *value = PyString_FromStringAndSize(elem.value, elem.value_length);
+    PyObject* kvp = PyTuple_Pack(2, key, value);
+    /* n.b. PyList_SetItem *steals* a reference to the set element. */
+    PyList_SetItem(metadata, i, kvp);
+    Py_DECREF(key);
+    Py_DECREF(value);
+  }
+  return metadata;
+}
+
 static PyObject *pygrpc_stop_event_args(grpc_event *c_event) {
-  return PyTuple_Pack(7, stop_event_kind, Py_None, Py_None, Py_None,
-                      Py_None, Py_None, Py_None);
+  return PyTuple_Pack(8, stop_event_kind, Py_None, Py_None, Py_None,
+                      Py_None, Py_None, Py_None, Py_None);
 }
 
 static PyObject *pygrpc_write_event_args(grpc_event *c_event) {
   PyObject *write_accepted =
       c_event->data.write_accepted == GRPC_OP_OK ? Py_True : Py_False;
-  return PyTuple_Pack(7, write_event_kind, (PyObject *)c_event->tag,
-                      write_accepted, Py_None, Py_None, Py_None, Py_None);
+  return PyTuple_Pack(8, write_event_kind, (PyObject *)c_event->tag,
+                      write_accepted, Py_None, Py_None, Py_None, Py_None,
+                      Py_None);
 }
 
 static PyObject *pygrpc_complete_event_args(grpc_event *c_event) {
   PyObject *complete_accepted =
       c_event->data.finish_accepted == GRPC_OP_OK ? Py_True : Py_False;
-  return PyTuple_Pack(7, complete_event_kind, (PyObject *)c_event->tag,
-                      Py_None, complete_accepted, Py_None, Py_None, Py_None);
+  return PyTuple_Pack(8, complete_event_kind, (PyObject *)c_event->tag,
+                      Py_None, complete_accepted, Py_None, Py_None, Py_None,
+                      Py_None);
 }
 
 static PyObject *pygrpc_service_event_args(grpc_event *c_event) {
   if (c_event->data.server_rpc_new.method == NULL) {
-    return PyTuple_Pack(7, service_event_kind, c_event->tag,
-                        Py_None, Py_None, Py_None, Py_None, Py_None);
+    return PyTuple_Pack(
+        8, service_event_kind, c_event->tag, Py_None, Py_None, Py_None, Py_None,
+        Py_None, Py_None);
   } else {
     PyObject *method = NULL;
     PyObject *host = NULL;
     PyObject *service_deadline = NULL;
     Call *call = NULL;
     PyObject *service_acceptance = NULL;
+    PyObject *metadata = NULL;
     PyObject *event_args = NULL;
 
     method = PyBytes_FromString(c_event->data.server_rpc_new.method);
@@ -173,11 +194,16 @@
       goto error;
     }
 
-    event_args = PyTuple_Pack(7, service_event_kind,
+    metadata = pygrpc_metadata_collection_get(
+        c_event->data.server_rpc_new.metadata_elements,
+        c_event->data.server_rpc_new.metadata_count);
+    event_args = PyTuple_Pack(8, service_event_kind,
                               (PyObject *)c_event->tag, Py_None, Py_None,
-                              service_acceptance, Py_None, Py_None);
+                              service_acceptance, Py_None, Py_None,
+                              metadata);
 
     Py_DECREF(service_acceptance);
+    Py_DECREF(metadata);
 error:
     Py_XDECREF(call);
     Py_XDECREF(method);
@@ -190,8 +216,8 @@
 
 static PyObject *pygrpc_read_event_args(grpc_event *c_event) {
   if (c_event->data.read == NULL) {
-    return PyTuple_Pack(7, read_event_kind, (PyObject *)c_event->tag,
-                        Py_None, Py_None, Py_None, Py_None, Py_None);
+    return PyTuple_Pack(8, read_event_kind, (PyObject *)c_event->tag,
+                        Py_None, Py_None, Py_None, Py_None, Py_None, Py_None);
   } else {
     size_t length;
     size_t offset;
@@ -216,17 +242,23 @@
     if (bytes == NULL) {
       return NULL;
     }
-    event_args = PyTuple_Pack(7, read_event_kind, (PyObject *)c_event->tag,
-                              Py_None, Py_None, Py_None, bytes, Py_None);
+    event_args = PyTuple_Pack(8, read_event_kind, (PyObject *)c_event->tag,
+                              Py_None, Py_None, Py_None, bytes, Py_None,
+                              Py_None);
     Py_DECREF(bytes);
     return event_args;
   }
 }
 
 static PyObject *pygrpc_metadata_event_args(grpc_event *c_event) {
-  /* TODO(nathaniel): Actual transmission of metadata. */
-  return PyTuple_Pack(7, metadata_event_kind, (PyObject *)c_event->tag,
-                      Py_None, Py_None, Py_None, Py_None, Py_None);
+  PyObject *metadata = pygrpc_metadata_collection_get(
+      c_event->data.client_metadata_read.elements,
+      c_event->data.client_metadata_read.count);
+  PyObject* result = PyTuple_Pack(
+      8, metadata_event_kind, (PyObject *)c_event->tag, Py_None, Py_None,
+      Py_None, Py_None, Py_None, metadata);
+  Py_DECREF(metadata);
+  return result;
 }
 
 static PyObject *pygrpc_finished_event_args(grpc_event *c_event) {
@@ -234,6 +266,7 @@
   PyObject *details;
   PyObject *status;
   PyObject *event_args;
+  PyObject *metadata;
 
   code = pygrpc_status_code(c_event->data.finished.status);
   if (code == NULL) {
@@ -253,9 +286,14 @@
   if (status == NULL) {
     return NULL;
   }
-  event_args = PyTuple_Pack(7, finish_event_kind, (PyObject *)c_event->tag,
-                            Py_None, Py_None, Py_None, Py_None, status);
+  metadata = pygrpc_metadata_collection_get(
+      c_event->data.finished.metadata_elements,
+      c_event->data.finished.metadata_count);
+  event_args = PyTuple_Pack(8, finish_event_kind, (PyObject *)c_event->tag,
+                            Py_None, Py_None, Py_None, Py_None, status,
+                            metadata);
   Py_DECREF(status);
+  Py_DECREF(metadata);
   return event_args;
 }
 
diff --git a/src/python/src/grpc/_adapter/_completion_queue.h b/src/python/src/grpc/_adapter/_completion_queue.h
index 8e5ee9f..9b377d1 100644
--- a/src/python/src/grpc/_adapter/_completion_queue.h
+++ b/src/python/src/grpc/_adapter/_completion_queue.h
@@ -38,7 +38,8 @@
 #include <grpc/grpc.h>
 
 typedef struct {
-  PyObject_HEAD grpc_completion_queue *c_completion_queue;
+  PyObject_HEAD
+  grpc_completion_queue *c_completion_queue;
 } CompletionQueue;
 
 PyTypeObject pygrpc_CompletionQueueType;
diff --git a/src/python/src/grpc/_adapter/_datatypes.py b/src/python/src/grpc/_adapter/_datatypes.py
index e271ec8..3b22784 100644
--- a/src/python/src/grpc/_adapter/_datatypes.py
+++ b/src/python/src/grpc/_adapter/_datatypes.py
@@ -70,7 +70,7 @@
     collections.namedtuple(
         'Event',
         ['kind', 'tag', 'write_accepted', 'complete_accepted',
-         'service_acceptance', 'bytes', 'status'])):
+         'service_acceptance', 'bytes', 'status', 'metadata'])):
   """Describes an event emitted from a completion queue."""
 
   @enum.unique
diff --git a/src/python/src/grpc/_adapter/_links_test.py b/src/python/src/grpc/_adapter/_links_test.py
index cfdcc2c..4987be3 100644
--- a/src/python/src/grpc/_adapter/_links_test.py
+++ b/src/python/src/grpc/_adapter/_links_test.py
@@ -43,6 +43,14 @@
 _TIMEOUT = 2
 
 
+# TODO(nathaniel): End-to-end metadata testing.
+def _transform_metadata(unused_metadata):
+  return (
+      ('one unused key', 'one unused value'),
+      ('another unused key', 'another unused value'),
+)
+
+
 class RoundTripTest(unittest.TestCase):
 
   def setUp(self):
@@ -76,7 +84,8 @@
 
     rear_link = rear.RearLink(
         'localhost', port, self.rear_link_pool, {test_method: None},
-        {test_method: None}, False, None, None, None)
+        {test_method: None}, False, None, None, None,
+        metadata_transformer=_transform_metadata)
     rear_link.join_fore_link(test_fore_link)
     test_fore_link.join_rear_link(rear_link)
     rear_link.start()
diff --git a/src/python/src/grpc/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py
index b04ac1c..e88b709 100644
--- a/src/python/src/grpc/_adapter/_low_test.py
+++ b/src/python/src/grpc/_adapter/_low_test.py
@@ -115,6 +115,18 @@
   def _perform_echo_test(self, test_data):
     method = 'test method'
     details = 'test details'
+    server_leading_metadata_key = 'my_server_leading_key'
+    server_leading_metadata_value = 'my_server_leading_value'
+    server_trailing_metadata_key = 'my_server_trailing_key'
+    server_trailing_metadata_value = 'my_server_trailing_value'
+    client_metadata_key = 'my_client_key'
+    client_metadata_value = 'my_client_value'
+    server_leading_binary_metadata_key = 'my_server_leading_key-bin'
+    server_leading_binary_metadata_value = b'\0'*2047
+    server_trailing_binary_metadata_key = 'my_server_trailing_key-bin'
+    server_trailing_binary_metadata_value = b'\0'*2047
+    client_binary_metadata_key = 'my_client_key-bin'
+    client_binary_metadata_value = b'\0'*2047
     deadline = _FUTURE
     metadata_tag = object()
     finish_tag = object()
@@ -128,6 +140,9 @@
     client_data = []
 
     client_call = _low.Call(self.channel, method, self.host, deadline)
+    client_call.add_metadata(client_metadata_key, client_metadata_value)
+    client_call.add_metadata(client_binary_metadata_key,
+                             client_binary_metadata_value)
 
     client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
 
@@ -139,15 +154,31 @@
     self.assertEqual(method, service_accepted.service_acceptance.method)
     self.assertEqual(self.host, service_accepted.service_acceptance.host)
     self.assertIsNotNone(service_accepted.service_acceptance.call)
+    metadata = dict(service_accepted.metadata)
+    self.assertIn(client_metadata_key, metadata)
+    self.assertEqual(client_metadata_value, metadata[client_metadata_key])
+    self.assertIn(client_binary_metadata_key, metadata)
+    self.assertEqual(client_binary_metadata_value,
+                     metadata[client_binary_metadata_key])
     server_call = service_accepted.service_acceptance.call
     server_call.accept(self.server_completion_queue, finish_tag)
+    server_call.add_metadata(server_leading_metadata_key,
+                             server_leading_metadata_value)
+    server_call.add_metadata(server_leading_binary_metadata_key,
+                             server_leading_binary_metadata_value)
     server_call.premetadata()
 
     metadata_accepted = self.client_completion_queue.get(_FUTURE)
     self.assertIsNotNone(metadata_accepted)
     self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind)
     self.assertEqual(metadata_tag, metadata_accepted.tag)
-    # TODO(nathaniel): Test transmission and reception of metadata.
+    metadata = dict(metadata_accepted.metadata)
+    self.assertIn(server_leading_metadata_key, metadata)
+    self.assertEqual(server_leading_metadata_value,
+                     metadata[server_leading_metadata_key])
+    self.assertIn(server_leading_binary_metadata_key, metadata)
+    self.assertEqual(server_leading_binary_metadata_value,
+                     metadata[server_leading_binary_metadata_key])
 
     for datum in test_data:
       client_call.write(datum, write_tag)
@@ -194,6 +225,11 @@
     self.assertEqual(read_tag, read_accepted.tag)
     self.assertIsNone(read_accepted.bytes)
 
+    server_call.add_metadata(server_trailing_metadata_key,
+                             server_trailing_metadata_value)
+    server_call.add_metadata(server_trailing_binary_metadata_key,
+                             server_trailing_binary_metadata_value)
+
     server_call.status(_low.Status(_low.Code.OK, details), status_tag)
     server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
     server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
@@ -229,6 +265,13 @@
     self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind)
     self.assertEqual(finish_tag, finish_accepted.tag)
     self.assertEqual(_low.Status(_low.Code.OK, details), finish_accepted.status)
+    metadata = dict(finish_accepted.metadata)
+    self.assertIn(server_trailing_metadata_key, metadata)
+    self.assertEqual(server_trailing_metadata_value,
+                     metadata[server_trailing_metadata_key])
+    self.assertIn(server_trailing_binary_metadata_key, metadata)
+    self.assertEqual(server_trailing_binary_metadata_value,
+                     metadata[server_trailing_binary_metadata_key])
 
     server_timeout_none_event = self.server_completion_queue.get(0)
     self.assertIsNone(server_timeout_none_event)
diff --git a/src/python/src/grpc/_adapter/_server.h b/src/python/src/grpc/_adapter/_server.h
index 0c517e3..4836bb6 100644
--- a/src/python/src/grpc/_adapter/_server.h
+++ b/src/python/src/grpc/_adapter/_server.h
@@ -37,7 +37,10 @@
 #include <Python.h>
 #include <grpc/grpc.h>
 
-typedef struct { PyObject_HEAD grpc_server *c_server; } Server;
+typedef struct {
+  PyObject_HEAD
+  grpc_server *c_server;
+} Server;
 
 int pygrpc_add_server(PyObject *module);
 
diff --git a/src/python/src/grpc/_adapter/_server_credentials.h b/src/python/src/grpc/_adapter/_server_credentials.h
index 2e56efd..6090404 100644
--- a/src/python/src/grpc/_adapter/_server_credentials.h
+++ b/src/python/src/grpc/_adapter/_server_credentials.h
@@ -38,7 +38,8 @@
 #include <grpc/grpc_security.h>
 
 typedef struct {
-  PyObject_HEAD grpc_server_credentials *c_server_credentials;
+  PyObject_HEAD
+  grpc_server_credentials *c_server_credentials;
 } ServerCredentials;
 
 PyTypeObject pygrpc_ServerCredentialsType;
diff --git a/src/python/src/grpc/_adapter/rear.py b/src/python/src/grpc/_adapter/rear.py
index f19321c..2b93aa6 100644
--- a/src/python/src/grpc/_adapter/rear.py
+++ b/src/python/src/grpc/_adapter/rear.py
@@ -93,7 +93,7 @@
   def __init__(
       self, host, port, pool, request_serializers, response_deserializers,
       secure, root_certificates, private_key, certificate_chain,
-      server_host_override=None):
+      metadata_transformer=None, server_host_override=None):
     """Constructor.
 
     Args:
@@ -111,6 +111,9 @@
         key should be used.
       certificate_chain: The PEM-encoded certificate chain to use or None if
         no certificate chain should be used.
+      metadata_transformer: A function that given a metadata object produces
+        another metadata to be used in the underlying communication on the
+        wire.
       server_host_override: (For testing only) the target name used for SSL
         host name checking.
     """
@@ -134,6 +137,7 @@
     self._root_certificates = root_certificates
     self._private_key = private_key
     self._certificate_chain = certificate_chain
+    self._metadata_transformer = metadata_transformer
     self._server_host_override = server_host_override
 
   def _on_write_event(self, operation_id, event, rpc_state):
@@ -243,6 +247,10 @@
     """
     request_serializer = self._request_serializers[name]
     call = _low.Call(self._channel, name, self._host, time.time() + timeout)
+    if self._metadata_transformer is not None:
+      metadata = self._metadata_transformer([])
+      for metadata_key, metadata_value in metadata:
+        call.add_metadata(metadata_key, metadata_value)
     call.invoke(self._completion_queue, operation_id, operation_id)
     outstanding = set(_INVOCATION_EVENT_KINDS)
 
diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py
index cc0b8ec..35456d3 100644
--- a/src/python/src/grpc/early_adopter/implementations.py
+++ b/src/python/src/grpc/early_adopter/implementations.py
@@ -114,7 +114,7 @@
 
   def __init__(
       self, breakdown, host, port, secure, root_certificates, private_key,
-      certificate_chain, server_host_override=None):
+      certificate_chain, metadata_transformer=None, server_host_override=None):
     self._lock = threading.Lock()
     self._breakdown = breakdown
     self._host = host
@@ -123,6 +123,7 @@
     self._root_certificates = root_certificates
     self._private_key = private_key
     self._certificate_chain = certificate_chain
+    self._metadata_transformer = metadata_transformer
     self._server_host_override = server_host_override
 
     self._pool = None
@@ -141,6 +142,7 @@
             self._breakdown.request_serializers,
             self._breakdown.response_deserializers, self._secure,
             self._root_certificates, self._private_key, self._certificate_chain,
+            metadata_transformer=self._metadata_transformer,
             server_host_override=self._server_host_override)
         self._front.join_rear_link(self._rear_link)
         self._rear_link.join_fore_link(self._front)
@@ -188,22 +190,11 @@
           raise AttributeError(attr)
 
 
-def _build_stub(
-    service_name, methods, host, port, secure, root_certificates, private_key,
-    certificate_chain, server_host_override=None):
-  breakdown = _face_utilities.break_down_invocation(service_name, methods)
-  return _Stub(
-      breakdown, host, port, secure, root_certificates, private_key,
-      certificate_chain, server_host_override=server_host_override)
-
-
-def _build_server(service_name, methods, port, private_key, certificate_chain):
-  breakdown = _face_utilities.break_down_service(service_name, methods)
-  return _Server(breakdown, port, private_key, certificate_chain)
-
-
-def insecure_stub(service_name, methods, host, port):
-  """Constructs an insecure interfaces.Stub.
+def stub(
+    service_name, methods, host, port, metadata_transformer=None, secure=False,
+    root_certificates=None, private_key=None, certificate_chain=None,
+    server_host_override=None):
+  """Constructs an interfaces.Stub.
 
   Args:
     service_name: The package-qualified full name of the service.
@@ -213,27 +204,10 @@
       not qualified by the service name or decorated in any other way.
     host: The host to which to connect for RPC service.
     port: The port to which to connect for RPC service.
-
-  Returns:
-    An interfaces.Stub affording RPC invocation.
-  """
-  return _build_stub(
-      service_name, methods, host, port, False, None, None, None)
-
-
-def secure_stub(
-    service_name, methods, host, port, root_certificates, private_key,
-    certificate_chain, server_host_override=None):
-  """Constructs an insecure interfaces.Stub.
-
-  Args:
-    service_name: The package-qualified full name of the service.
-    methods: A dictionary from RPC method name to
-      interfaces.RpcMethodInvocationDescription describing the RPCs to be
-      supported by the created stub. The RPC method names in the dictionary are
-      not qualified by the service name or decorated in any other way.
-    host: The host to which to connect for RPC service.
-    port: The port to which to connect for RPC service.
+    metadata_transformer: A callable that given a metadata object produces
+      another metadata object to be used in the underlying communication on the
+      wire.
+    secure: Whether or not to construct the stub with a secure connection.
     root_certificates: The PEM-encoded root certificates or None to ask for
       them to be retrieved from a default location.
     private_key: The PEM-encoded private key to use or None if no private key
@@ -246,32 +220,15 @@
   Returns:
     An interfaces.Stub affording RPC invocation.
   """
-  return _build_stub(
-      service_name, methods, host, port, True, root_certificates, private_key,
+  breakdown = _face_utilities.break_down_invocation(service_name, methods)
+  return _Stub(
+      breakdown, host, port, secure, root_certificates, private_key,
       certificate_chain, server_host_override=server_host_override)
 
 
-def insecure_server(service_name, methods, port):
-  """Constructs an insecure interfaces.Server.
-
-  Args:
-    service_name: The package-qualified full name of the service.
-    methods: A dictionary from RPC method name to
-      interfaces.RpcMethodServiceDescription describing the RPCs to
-      be serviced by the created server. The RPC method names in the dictionary
-      are not qualified by the service name or decorated in any other way.
-    port: The desired port on which to serve or zero to ask for a port to
-      be automatically selected.
-
-  Returns:
-    An interfaces.Server that will run with no security and
-      service unsecured raw requests.
-  """
-  return _build_server(service_name, methods, port, None, None)
-
-
-def secure_server(service_name, methods, port, private_key, certificate_chain):
-  """Constructs a secure interfaces.Server.
+def server(
+    service_name, methods, port, private_key=None, certificate_chain=None):
+  """Constructs an interfaces.Server.
 
   Args:
     service_name: The package-qualified full name of the service.
@@ -281,11 +238,12 @@
       are not qualified by the service name or decorated in any other way.
     port: The port on which to serve or zero to ask for a port to be
       automatically selected.
-    private_key: A pem-encoded private key.
-    certificate_chain: A pem-encoded certificate chain.
+    private_key: A pem-encoded private key, or None for an insecure server.
+    certificate_chain: A pem-encoded certificate chain, or None for an insecure
+      server.
 
   Returns:
     An interfaces.Server that will serve secure traffic.
   """
-  return _build_server(
-      service_name, methods, port, private_key, certificate_chain)
+  breakdown = _face_utilities.break_down_service(service_name, methods)
+  return _Server(breakdown, port, private_key, certificate_chain)
diff --git a/src/python/src/grpc/early_adopter/implementations_test.py b/src/python/src/grpc/early_adopter/implementations_test.py
index ae4adad..32b9747 100644
--- a/src/python/src/grpc/early_adopter/implementations_test.py
+++ b/src/python/src/grpc/early_adopter/implementations_test.py
@@ -106,11 +106,11 @@
 class EarlyAdopterImplementationsTest(unittest.TestCase):
 
   def setUp(self):
-    self.server = implementations.insecure_server(
+    self.server = implementations.server(
         SERVICE_NAME, _SERVICE_DESCRIPTIONS, 0)
     self.server.start()
     port = self.server.port()
-    self.stub = implementations.insecure_stub(
+    self.stub = implementations.stub(
         SERVICE_NAME, _INVOCATION_DESCRIPTIONS, 'localhost', port)
 
   def tearDown(self):
diff --git a/src/python/src/setup.py b/src/python/src/setup.py
index bd70634..32ac41e 100644
--- a/src/python/src/setup.py
+++ b/src/python/src/setup.py
@@ -30,6 +30,8 @@
 """A setup module for the GRPC Python package."""
 
 from distutils import core as _core
+import setuptools
+import sys
 
 _EXTENSION_SOURCES = (
     'grpc/_adapter/_c.c',
@@ -49,8 +51,9 @@
 _EXTENSION_LIBRARIES = (
     'grpc',
     'gpr',
-    'rt',
 )
+if not "darwin" in sys.platform:
+    _EXTENSION_LIBRARIES += ('rt',)
 
 _EXTENSION_MODULE = _core.Extension(
     'grpc._adapter._c', sources=list(_EXTENSION_SOURCES),
@@ -80,7 +83,15 @@
     'grpc.framework': 'grpc/framework',
 }
 
-_core.setup(
-    name='grpc-2015', version='0.4.0',
-    ext_modules=[_EXTENSION_MODULE], packages=list(_PACKAGES),
-    package_dir=_PACKAGE_DIRECTORIES)
+setuptools.setup(
+    name='grpcio',
+    version='0.5.0a0',
+    ext_modules=[_EXTENSION_MODULE],
+    packages=list(_PACKAGES),
+    package_dir=_PACKAGE_DIRECTORIES,
+    install_requires=[
+        'enum34==1.0.4',
+        'futures==2.2.0',
+        'protobuf==3.0.0-alpha-1'
+    ]
+)
diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile
index b27305d..afb354e 100755
--- a/src/ruby/Rakefile
+++ b/src/ruby/Rakefile
@@ -2,14 +2,17 @@
 require 'rake/extensiontask'
 require 'rspec/core/rake_task'
 require 'rubocop/rake_task'
+require 'bundler/gem_tasks'
 
-desc 'Run Rubocop to check for style violations'
+# Add rubocop style checking tasks
 RuboCop::RakeTask.new
 
+# Add the extension compiler task
 Rake::ExtensionTask.new 'grpc' do |ext|
   ext.lib_dir = File.join('lib', 'grpc')
 end
 
+# Define the test suites
 SPEC_SUITES = [
   { id: :wrapper, title: 'wrapper layer', files: %w(spec/*.rb) },
   { id: :idiomatic, title: 'idiomatic layer', dir: %w(spec/generic),
@@ -19,36 +22,34 @@
   { id: :server, title: 'rpc server thread tests', dir: %w(spec/generic),
     tag: 'server' }
 ]
+namespace :suite do
+  SPEC_SUITES.each do |suite|
+    desc "Run all specs in the #{suite[:title]} spec suite"
+    RSpec::Core::RakeTask.new(suite[:id]) do |t|
+      spec_files = []
+      suite[:files].each { |f| spec_files += Dir[f] } if suite[:files]
 
-desc 'Run all RSpec tests'
-namespace :spec do
-  namespace :suite do
-    SPEC_SUITES.each do |suite|
-      desc "Run all specs in #{suite[:title]} spec suite"
-      RSpec::Core::RakeTask.new(suite[:id]) do |t|
-        spec_files = []
-        suite[:files].each { |f| spec_files += Dir[f] } if suite[:files]
+      if suite[:dir]
+        suite[:dir].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] }
+      end
+      helper = 'spec/spec_helper.rb'
+      spec_files << helper unless spec_files.include?(helper)
 
-        if suite[:dirs]
-          suite[:dirs].each { |f| spec_files += Dir["#{f}/**/*_spec.rb"] }
-        end
-
-        t.pattern = spec_files
-        t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag]
-        if suite[:tags]
-          t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ')
-        end
+      t.pattern = spec_files
+      t.rspec_opts = "--tag #{suite[:tag]}" if suite[:tag]
+      if suite[:tags]
+        t.rspec_opts = suite[:tags].map { |x| "--tag #{x}" }.join(' ')
       end
     end
   end
 end
 
-desc 'Compiles the extension then runs all the tests'
-task :all
+# Define dependencies between the suites.
+task 'suite:wrapper' => [:compile, :rubocop]
+task 'suite:idiomatic' => 'suite:wrapper'
+task 'suite:bidi' => 'suite:wrapper'
+task 'suite:server' => 'suite:wrapper'
 
+desc 'Compiles the gRPC extension then runs all the tests'
+task all: ['suite:idiomatic', 'suite:bidi', 'suite:server']
 task default: :all
-task 'spec:suite:wrapper' => [:compile, :rubocop]
-task 'spec:suite:idiomatic' => 'spec:suite:wrapper'
-task 'spec:suite:bidi' => 'spec:suite:wrapper'
-task 'spec:suite:server' => 'spec:suite:wrapper'
-task all: ['spec:suite:idiomatic', 'spec:suite:bidi', 'spec:suite:server']
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 6ea0831..69076b4 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -176,25 +176,26 @@
             unmarshal = desc.unmarshal_proc(:output)
             route = "/#{route_prefix}/#{name}"
             if desc.request_response?
-              define_method(mth_name) do |req, deadline = nil|
+              define_method(mth_name) do |req, deadline = nil, **kw|
                 logger.debug("calling #{@host}:#{route}")
-                request_response(route, req, marshal, unmarshal, deadline)
+                request_response(route, req, marshal, unmarshal, deadline, **kw)
               end
             elsif desc.client_streamer?
-              define_method(mth_name) do |reqs, deadline = nil|
+              define_method(mth_name) do |reqs, deadline = nil, **kw|
                 logger.debug("calling #{@host}:#{route}")
-                client_streamer(route, reqs, marshal, unmarshal, deadline)
+                client_streamer(route, reqs, marshal, unmarshal, deadline, **kw)
               end
             elsif desc.server_streamer?
-              define_method(mth_name) do |req, deadline = nil, &blk|
+              define_method(mth_name) do |req, deadline = nil, **kw, &blk|
                 logger.debug("calling #{@host}:#{route}")
-                server_streamer(route, req, marshal, unmarshal, deadline,
+                server_streamer(route, req, marshal, unmarshal, deadline, **kw,
                                 &blk)
               end
             else  # is a bidi_stream
-              define_method(mth_name) do |reqs, deadline = nil, &blk|
+              define_method(mth_name) do |reqs, deadline = nil, **kw, &blk|
                 logger.debug("calling #{@host}:#{route}")
-                bidi_streamer(route, reqs, marshal, unmarshal, deadline, &blk)
+                bidi_streamer(route, reqs, marshal, unmarshal, deadline, **kw,
+                              &blk)
               end
             end
           end
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 513a537..bfd0cbb 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '0.5.0'
+  VERSION = '0.6.0'
 end
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 8914225..96e07ca 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -67,7 +67,7 @@
     end
 
     describe '#multi_req_view' do
-      xit 'exposes a fixed subset of the ActiveCall methods' do
+      it 'exposes a fixed subset of the ActiveCall methods' do
         want = %w(cancelled, deadline, each_remote_read, metadata, shutdown)
         v = @client_call.multi_req_view
         want.each do |w|
@@ -77,7 +77,7 @@
     end
 
     describe '#single_req_view' do
-      xit 'exposes a fixed subset of the ActiveCall methods' do
+      it 'exposes a fixed subset of the ActiveCall methods' do
         want = %w(cancelled, deadline, metadata, shutdown)
         v = @client_call.single_req_view
         want.each do |w|
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 73f2d37..0c98fc4 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -384,13 +384,7 @@
         th.join
       end
 
-      # disabled because an unresolved wire-protocol implementation feature
-      #
-      # - servers should be able initiate messaging, however, as it stand
-      # servers don't know if all the client metadata has been sent until
-      # they receive a message from the client.  Without receiving all the
-      # metadata, the server does not accept the call, so this test hangs.
-      xit 'supports a server-initiated ping pong', bidi: true do
+      it 'supports a server-initiated ping pong', bidi: true do
         server_port = create_test_server
         host = "localhost:#{server_port}"
         th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index f3b89b5..34e5cdc 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -81,14 +81,17 @@
 class SlowService
   include GRPC::GenericService
   rpc :an_rpc, EchoMsg, EchoMsg
+  attr_reader :received_md, :delay
 
   def initialize(_default_var = 'ignored')
+    @delay = 0.25
+    @received_md = []
   end
 
-  def an_rpc(req, _call)
-    delay = 0.25
-    logger.info("starting a slow #{delay} rpc")
-    sleep delay
+  def an_rpc(req, call)
+    logger.info("starting a slow #{@delay} rpc")
+    sleep @delay
+    @received_md << call.metadata unless call.metadata.nil?
     req  # send back the req as the response
   end
 end
@@ -354,6 +357,37 @@
         t.join
       end
 
+      it 'should receive metadata when a deadline is specified', server: true do
+        service = SlowService.new
+        @srv.handle(service)
+        t = Thread.new { @srv.run }
+        @srv.wait_till_running
+        req = EchoMsg.new
+        stub = SlowStub.new(@host, **@client_opts)
+        deadline = service.delay + 0.5 # wait for long enough
+        expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
+        wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
+        expect(service.received_md).to eq(wanted_md)
+        @srv.stop
+        t.join
+      end
+
+      it 'should not receive metadata if the client times out', server: true do
+        service = SlowService.new
+        @srv.handle(service)
+        t = Thread.new { @srv.run }
+        @srv.wait_till_running
+        req = EchoMsg.new
+        stub = SlowStub.new(@host, **@client_opts)
+        deadline = 0.1  # too short for SlowService to respond
+        blk = proc { stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2') }
+        expect(&blk).to raise_error GRPC::BadStatus
+        wanted_md = []
+        expect(service.received_md).to eq(wanted_md)
+        @srv.stop
+        t.join
+      end
+
       it 'should receive updated metadata', server: true do
         service = EchoService.new
         @srv.handle(service)
diff --git a/templates/BUILD.template b/templates/BUILD.template
new file mode 100644
index 0000000..8303b9f
--- /dev/null
+++ b/templates/BUILD.template
@@ -0,0 +1,110 @@
+# GRPC Bazel BUILD file.
+# This currently builds C and C++ code.
+
+# 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.
+
+licenses(["notice"])  # 3-clause BSD
+
+package(default_visibility = ["//visibility:public"])
+
+<%!
+def get_deps(target_dict):
+  deps = []
+  if target_dict.get('secure', 'no') == 'yes':
+    deps = [
+      "//external:libssl",
+    ]
+  if target_dict.get('build', None) == 'protoc':
+    deps.append("//external:protobuf_compiler")
+  if target_dict['name'] == 'grpc++_unsecure' or target_dict['name'] == 'grpc++':
+    deps.append("//external:protobuf_clib")
+  for d in target_dict.get('deps', []):
+    if d.find('//') == 0 or d[0] == ':':
+      deps.append(d)
+    else:
+      deps.append(':%s' % (d))
+  return deps
+%>
+
+% for lib in libs:
+% if lib.build != "private":
+${cc_library(lib)}
+% endif
+% endfor
+
+% for tgt in targets:
+% if tgt.build == 'protoc':
+${cc_binary(tgt)}
+% endif
+% endfor
+
+<%def name="cc_library(lib)">
+cc_library(
+  name = "${lib.name}",
+  srcs = [
+% for hdr in lib.get("headers", []):
+    "${hdr}",
+% endfor
+% for src in lib.src:
+    "${src}",
+% endfor
+  ],
+  hdrs = [
+% for hdr in lib.get("public_headers", []):
+    "${hdr}",
+% endfor
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+% for dep in get_deps(lib):
+    "${dep}",
+% endfor
+  ],
+)
+</%def>
+
+<%def name="cc_binary(tgt)">
+cc_binary(
+  name = "${tgt.name}",
+  srcs = [
+% for src in tgt.src:
+    "${src}",
+% endfor
+  ],
+  deps = [
+% for dep in get_deps(tgt):
+    "${dep}",
+% endfor
+  ],
+)
+</%def>
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 36d1142..2cfbfa3 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -35,17 +35,11 @@
 
   proto_re = re.compile('(.*)\\.proto')
 
-  def excluded(filename, exclude_res):
-    for r in exclude_res:
-      if r.match(filename):
-        return True
-    return False
-
   def proto_to_cc(filename):
     m = proto_re.match(filename)
     if not m:
       return filename
-    return '$(GENDIR)/' + m.group(1) + '.pb.cc'
+    return '$(GENDIR)/' + m.group(1) + '.pb.cc $(GENDIR)/' + m.group(1) + '.grpc.pb.cc'
 %>
 
 
@@ -111,6 +105,15 @@
 LDFLAGS_dbg =
 DEFINES_dbg = _DEBUG DEBUG
 
+VALID_CONFIG_mutrace = 1
+CC_mutrace = $(DEFAULT_CC)
+CXX_mutrace = $(DEFAULT_CXX)
+LD_mutrace = $(DEFAULT_CC)
+LDXX_mutrace = $(DEFAULT_CXX)
+CPPFLAGS_mutrace = -O0
+LDFLAGS_mutrace = -rdynamic
+DEFINES_mutrace = _DEBUG DEBUG
+
 VALID_CONFIG_valgrind = 1
 REQUIRE_CUSTOM_LIBRARIES_valgrind = 1
 CC_valgrind = $(DEFAULT_CC)
@@ -235,7 +238,6 @@
 CXXFLAGS += -std=c++11
 else
 CXXFLAGS += -std=c++0x
-DEFINES += GRPC_OLD_CXX
 endif
 CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
 LDFLAGS += -g
@@ -832,11 +834,17 @@
 % for p in protos:
 ifeq ($(NO_PROTOC),true)
 $(GENDIR)/${p}.pb.cc: protoc_dep_error
+$(GENDIR)/${p}.grpc.pb.cc: protoc_dep_error
 else
 $(GENDIR)/${p}.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) --cpp_out=$(GENDIR) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) --cpp_out=$(GENDIR) $<
+
+$(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
+	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
 endif
 
 % endfor
@@ -918,10 +926,11 @@
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT) $(prefix)/lib/${lib.name}.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
 else
-ifneq ($(SYSTEM),Darwin)
 	$(E) "[INSTALL] Installing lib${lib.name}.$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.$(SHARED_EXT)
+ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major}
 	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
 endif
 endif
@@ -1158,7 +1167,7 @@
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
+	$(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name lib${lib.name}.$(SHARED_EXT) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
 else
 	$(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.version.major} -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
 	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) ${out_libbase}.so.${settings.version.major}
diff --git a/templates/vsprojects/vs2010/Grpc.mak.template b/templates/vsprojects/vs2010/Grpc.mak.template
new file mode 100644
index 0000000..8e1b33b
--- /dev/null
+++ b/templates/vsprojects/vs2010/Grpc.mak.template
@@ -0,0 +1,107 @@
+# 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.
+<%!
+  import re
+%>\
+<%def name="to_windows_path(path)">${path.replace('/','\\')}</%def>\
+<%
+  allowed_dependencies = set(['gpr', 'grpc', 'gpr_test_util', 'grpc_test_util'])
+  buildable_targets = [ target for target in targets if set(target.deps).issubset(allowed_dependencies) and all([src.endswith('.c') for src in target.src])]
+  test_targets = [ target for target in buildable_targets if target.name.endswith('_test') ]
+%>\
+# NMake file to build secondary gRPC targets on Windows.
+# Use grpc.sln to solution to build the gRPC libraries.
+
+OUT_DIR=test_bin
+
+CC=cl.exe
+LINK=link.exe
+
+INCLUDES=/I..\.. /I..\..\include /I..\..\third_party\zlib /I..\third_party /I..\..\third_party\openssl\inc32
+DEFINES=/D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /D _CRT_SECURE_NO_WARNINGS
+CFLAGS=/c $(INCLUDES) /nologo /Z7 /W3 /WX- /sdl $(DEFINES) /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze-
+LFLAGS=/DEBUG /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86
+
+OPENSSL_LIBS=..\..\third_party\openssl\out32\ssleay32.lib ..\..\third_party\openssl\out32\libeay32.lib
+WINSOCK_LIBS=ws2_32.lib
+ZLIB_LIBS=Debug\zlibwapi.lib
+LIBS=$(OPENSSL_LIBS) $(WINSOCK_LIBS) $(ZLIB_LIBS)
+
+gpr_test_util:
+	MSBuild.exe gpr_test_util.vcxproj /p:Configuration=Debug
+
+grpc_test_util:
+	MSBuild.exe grpc_test_util.vcxproj /p:Configuration=Debug
+
+$(OUT_DIR):
+	mkdir $(OUT_DIR)
+
+buildtests: \
+% for target in test_targets:
+${target.name}.exe \
+% endfor
+
+	echo All tests built.
+
+test: \
+% for target in test_targets:
+${target.name} \
+% endfor
+
+	echo All tests ran.
+
+test_gpr: \
+% for target in [ tgt for tgt in test_targets if tgt.name.startswith('gpr_')]:
+${target.name} \
+% endfor
+
+	echo All tests ran.
+
+% for target in buildable_targets:
+${target.name}.exe: grpc_test_util
+	echo Building ${target.name}
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ \
+%for source in target.src:
+..\..\${to_windows_path(source)} \
+%endfor
+
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\${target.name}.exe" \
+%for dep in target.deps:
+Debug\${dep}.lib \
+%endfor
+$(LIBS) \
+%for source in target.src:
+$(OUT_DIR)\${re.search('([^/]+)\.c$', source).group(1)}.obj \
+%endfor
+
+${target.name}: ${target.name}.exe
+	echo Running ${target.name}
+	$(OUT_DIR)\${target.name}.exe
+
+% endfor
diff --git a/templates/vsprojects/vs2013/gpr_shared.vcxproj.filters.template b/templates/vsprojects/vs2010/gpr.vcxproj.filters.template
similarity index 100%
rename from templates/vsprojects/vs2013/gpr_shared.vcxproj.filters.template
rename to templates/vsprojects/vs2010/gpr.vcxproj.filters.template
diff --git a/templates/vsprojects/vs2010/gpr.vcxproj.template b/templates/vsprojects/vs2010/gpr.vcxproj.template
new file mode 100644
index 0000000..c478aad
--- /dev/null
+++ b/templates/vsprojects/vs2010/gpr.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('gpr', libs, targets)}
diff --git a/templates/vsprojects/vs2010/gpr_test_util.vcxproj.template b/templates/vsprojects/vs2010/gpr_test_util.vcxproj.template
new file mode 100644
index 0000000..1f1bc0a
--- /dev/null
+++ b/templates/vsprojects/vs2010/gpr_test_util.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('gpr_test_util', libs, targets)}
\ No newline at end of file
diff --git a/templates/vsprojects/vs2010/grpc++.vcxproj.filters.template b/templates/vsprojects/vs2010/grpc++.vcxproj.filters.template
new file mode 100644
index 0000000..d74cce8
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc++.vcxproj.filters.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj.filters_defs.include" import="gen_filters"/>\
+${gen_filters('grpc++', libs, targets)}
diff --git a/templates/vsprojects/vs2010/grpc++.vcxproj.template b/templates/vsprojects/vs2010/grpc++.vcxproj.template
new file mode 100644
index 0000000..93994bb
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc++.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('grpc++', libs, targets)}
\ No newline at end of file
diff --git a/templates/vsprojects/vs2010/grpc.sln.template b/templates/vsprojects/vs2010/grpc.sln.template
new file mode 100644
index 0000000..47aa03c
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc.sln.template
@@ -0,0 +1,59 @@
+## Template for Visual Studio solution
+## based on http://msdn.microsoft.com/en-us/library/bb165951(v=vs.90).aspx
+## NOTE: tabs in this file are needed by Visual Studio to correctly interpret
+## the file.
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+<%
+## Visual Studio uses GUIDs for project types
+## http://msdn.microsoft.com/en-us/library/hb23x61k%28v=vs.80%29.aspx
+cpp_proj_type = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
+%>\
+% for project in vsprojects:
+Project("${cpp_proj_type}") = "${project.name}", "${project.name}.vcxproj", "${project.vs_project_guid}"
+  % if project.get('deps', None):
+	ProjectSection(ProjectDependencies) = postProject
+    % for dep in project.get('deps', []):
+		${vsproject_dict[dep].vs_project_guid} = ${vsproject_dict[dep].vs_project_guid}
+    % endfor
+	EndProjectSection
+  % endif
+EndProject
+% endfor
+Project("${cpp_proj_type}") = "grpc_csharp_ext_shared", "grpc_csharp_ext_shared.vcxproj", "{C26D04A8-37C6-44C7-B458-906C9FCE928C}"
+EndProject
+Project("${cpp_proj_type}") = "zlibvc", "third_party\zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+% for project in vsprojects:
+		${project.vs_project_guid}.Debug|Win32.ActiveCfg = Debug|Win32
+		${project.vs_project_guid}.Debug|Win32.Build.0 = Debug|Win32
+		${project.vs_project_guid}.Release|Win32.ActiveCfg = Release|Win32
+		${project.vs_project_guid}.Release|Win32.Build.0 = Release|Win32
+% endfor
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Debug|Win32.Build.0 = Debug|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Release|Win32.ActiveCfg = Release|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Release|Win32.Build.0 = Release|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Debug|Win32.Build.0 = Debug|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Release|Win32.ActiveCfg = Release|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Release|Win32.Build.0 = Release|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Debug|Win32.Build.0 = Debug|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Release|Win32.ActiveCfg = Release|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/templates/vsprojects/vs2013/grpc_shared.vcxproj.filters.template b/templates/vsprojects/vs2010/grpc.vcxproj.filters.template
similarity index 100%
rename from templates/vsprojects/vs2013/grpc_shared.vcxproj.filters.template
rename to templates/vsprojects/vs2010/grpc.vcxproj.filters.template
diff --git a/templates/vsprojects/vs2010/grpc.vcxproj.template b/templates/vsprojects/vs2010/grpc.vcxproj.template
new file mode 100644
index 0000000..3de6453
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('grpc', libs, targets)}
\ No newline at end of file
diff --git a/templates/vsprojects/vs2010/grpc_csharp_ext.vcxproj.template b/templates/vsprojects/vs2010/grpc_csharp_ext.vcxproj.template
new file mode 100644
index 0000000..84aa502
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc_csharp_ext.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('grpc_csharp_ext', libs, targets)}
diff --git a/templates/vsprojects/vs2010/grpc_csharp_ext_shared.vcxproj.template b/templates/vsprojects/vs2010/grpc_csharp_ext_shared.vcxproj.template
new file mode 100644
index 0000000..193a2cd
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc_csharp_ext_shared.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('grpc_csharp_ext', libs, targets, configuration_type = 'DynamicLibrary', project_guid = '{C26D04A8-37C6-44C7-B458-906C9FCE928C}', additional_props = ['winsock', 'ssl'])}
diff --git a/templates/vsprojects/vs2010/grpc_test_util.vcxproj.template b/templates/vsprojects/vs2010/grpc_test_util.vcxproj.template
new file mode 100644
index 0000000..72e625d
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc_test_util.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('grpc_test_util', libs, targets)}
\ No newline at end of file
diff --git a/templates/vsprojects/vs2010/grpc_unsecure.vcxproj.filters.template b/templates/vsprojects/vs2010/grpc_unsecure.vcxproj.filters.template
new file mode 100644
index 0000000..ef91892
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc_unsecure.vcxproj.filters.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj.filters_defs.include" import="gen_filters"/>\
+${gen_filters('grpc_unsecure', libs, targets)}
diff --git a/templates/vsprojects/vs2010/grpc_unsecure.vcxproj.template b/templates/vsprojects/vs2010/grpc_unsecure.vcxproj.template
new file mode 100644
index 0000000..4f62b85
--- /dev/null
+++ b/templates/vsprojects/vs2010/grpc_unsecure.vcxproj.template
@@ -0,0 +1,2 @@
+<%namespace file="vcxproj_defs.include" import="gen_project"/>\
+${gen_project('grpc_unsecure', libs, targets)}
\ No newline at end of file
diff --git a/templates/vsprojects/vs2010/vcxproj.filters_defs.include b/templates/vsprojects/vs2010/vcxproj.filters_defs.include
new file mode 100644
index 0000000..539ae93
--- /dev/null
+++ b/templates/vsprojects/vs2010/vcxproj.filters_defs.include
@@ -0,0 +1,64 @@
+<%!
+  import re
+  import hashlib
+
+  def calc_to_filter(path):
+    return '\\'.join(path.split('/')[:-1])
+%>\
+<%def name="to_windows_path(path)">${path.replace('/','\\')}</%def>\
+<%def name="to_filter(path)">${calc_to_filter(path)}</%def>\
+<%def name="filter_to_guid(proj, filter)">${re.sub('(........)(....)(....)(....)', r'\1-\2-\3-\4-', hashlib.md5(''.join([filter, proj])).hexdigest())}</%def>\
+<%def name="gen_filters(name, libs, targets)">\
+% for project in vsprojects:
+  % if project.name == name:
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  % if project.get('src',[]):
+  <ItemGroup>
+    % for src_name in project.src:
+    <ClCompile Include="..\..\${to_windows_path(src_name)}">
+      <Filter>${to_filter(src_name)}</Filter>
+    </ClCompile>
+    % endfor
+  </ItemGroup>
+  % endif
+  % if project.get('public_headers',[]):
+  <ItemGroup>
+    % for public_header in project.public_headers:
+    <ClInclude Include="..\..\${to_windows_path(public_header)}">
+      <Filter>${to_filter(public_header)}</Filter>
+    </ClInclude>
+    % endfor
+  </ItemGroup>
+  % endif
+  % if project.get('headers',[]):
+  <ItemGroup>
+    % for header in project.headers:
+    <ClInclude Include="..\..\${to_windows_path(header)}">
+      <Filter>${to_filter(header)}</Filter>
+    </ClInclude>
+    % endfor
+  </ItemGroup>
+  % endif
+<%
+  filters = set()
+  files = project.get('src', []) + project.get('public_headers', []) + project.get('headers', [])
+  for file in files:
+    filter = calc_to_filter(file)
+    paths = filter.split('\\')
+    for i in range(len(paths)):
+      filters.add('\\'.join(paths[:i + 1]))
+
+  filters = sorted(filters)
+%>
+  <ItemGroup>
+  % for filter in filters:
+    <Filter Include="${filter}">
+      <UniqueIdentifier>{${filter_to_guid(project.name, filter)}}</UniqueIdentifier>
+    </Filter>
+  % endfor
+  </ItemGroup>
+</Project>
+  % endif
+% endfor
+</%def>\
\ No newline at end of file
diff --git a/templates/vsprojects/vs2010/vcxproj_defs.include b/templates/vsprojects/vs2010/vcxproj_defs.include
new file mode 100644
index 0000000..8fd78a3
--- /dev/null
+++ b/templates/vsprojects/vs2010/vcxproj_defs.include
@@ -0,0 +1,131 @@
+<%def name="to_windows_path(path)">${path.replace('/','\\')}</%def>\
+<%def name="get_subsystem(is_library)">${'Windows' if is_library else 'Console'}</%def>\
+<%def name="gen_project(name, libs, targets, configuration_type = 'StaticLibrary', project_guid = None, additional_props = [], depends_on_zlib = False)">\
+% for project in vsprojects:
+  % if project.name == name:
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>${project_guid if project_guid else project.vs_project_guid}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>${configuration_type}</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>${configuration_type}</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+    % for prop in additional_props:
+    <Import Project="${prop}.props" />
+    % endfor
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+    % for prop in additional_props:
+    <Import Project="${prop}.props" />
+    % endfor
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <TargetName>${name}</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <TargetName>${name}</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>${get_subsystem(project.is_library)}</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>${get_subsystem(project.is_library)}</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  % if project.get('public_headers',[]):
+  <ItemGroup>
+    % for public_header in project.public_headers:
+    <ClInclude Include="..\..\${to_windows_path(public_header)}" />
+    % endfor
+  </ItemGroup>
+  % endif
+  % if project.get('headers',[]):
+  <ItemGroup>
+    % for header in project.headers:
+    <ClInclude Include="..\..\${to_windows_path(header)}" />
+    % endfor
+  </ItemGroup>
+  % endif
+  % if project.get('src',[]):
+  <ItemGroup>
+    % for src_name in project.src:
+    <ClCompile Include="..\..\${to_windows_path(src_name)}">
+    </ClCompile>
+    % endfor
+  </ItemGroup>
+  % endif
+  % if project.get('deps',[]):
+  <ItemGroup>
+    % for dep in project.deps:
+    <ProjectReference Include="${dep}.vcxproj">
+      <Project>${vsproject_dict[dep].vs_project_guid}</Project>
+    </ProjectReference>
+    % endfor
+    % if depends_on_zlib:
+    <ProjectReference Include="third_party\zlibvc.vcxproj">
+      <Project>{8fd826f8-3739-44e6-8cc8-997122e53b8d}</Project>
+    </ProjectReference>
+    % endif
+  </ItemGroup>
+  % endif
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+  % endif
+% endfor
+</%def>\
\ No newline at end of file
diff --git a/templates/vsprojects/vs2013/gpr_shared.vcxproj.template b/templates/vsprojects/vs2013/gpr_shared.vcxproj.template
deleted file mode 100644
index d1b1dd3..0000000
--- a/templates/vsprojects/vs2013/gpr_shared.vcxproj.template
+++ /dev/null
@@ -1,2 +0,0 @@
-<%namespace file="vcxproj_defs.include" import="gen_project"/>\
-${gen_project('gpr', libs, targets, configuration_type = 'DynamicLibrary', project_guid = '{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}')}
diff --git a/templates/vsprojects/vs2013/grpc.sln.template b/templates/vsprojects/vs2013/grpc.sln.template
index d17f4a3..2b0f76b 100644
--- a/templates/vsprojects/vs2013/grpc.sln.template
+++ b/templates/vsprojects/vs2013/grpc.sln.template
@@ -23,10 +23,6 @@
   % endif
 EndProject
 % endfor
-Project("${cpp_proj_type}") = "gpr_shared", "gpr_shared.vcxproj", "{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}"
-EndProject
-Project("${cpp_proj_type}") = "grpc_shared", "grpc_shared.vcxproj", "{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}"
-EndProject
 Project("${cpp_proj_type}") = "grpc_csharp_ext_shared", "grpc_csharp_ext_shared.vcxproj", "{C26D04A8-37C6-44C7-B458-906C9FCE928C}"
 EndProject
 Project("${cpp_proj_type}") = "zlibvc", "third_party\zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
diff --git a/templates/vsprojects/vs2013/grpc_shared.vcxproj.template b/templates/vsprojects/vs2013/grpc_shared.vcxproj.template
deleted file mode 100644
index 890189c..0000000
--- a/templates/vsprojects/vs2013/grpc_shared.vcxproj.template
+++ /dev/null
@@ -1,2 +0,0 @@
-<%namespace file="vcxproj_defs.include" import="gen_project"/>\
-${gen_project('grpc', libs, targets, configuration_type = 'DynamicLibrary', project_guid = '{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}', additional_props = ['ssl', 'winsock'], depends_on_zlib = True)}
diff --git a/test/compiler/python_plugin_test.py b/test/compiler/python_plugin_test.py
index 3d2f117..ad3beba 100644
--- a/test/compiler/python_plugin_test.py
+++ b/test/compiler/python_plugin_test.py
@@ -177,7 +177,7 @@
 
   servicer = Servicer()
   server = getattr(
-      test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer, 0, None, None)
+      test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer, 0)
   with server:
     port = server.port()
     stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)('localhost', port)
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index e15fa7f..592dfd4 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -51,10 +51,11 @@
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
                                             const char *test_name,
+                                            cancellation_mode mode,
                                             grpc_channel_args *client_args,
                                             grpc_channel_args *server_args) {
   grpc_end2end_test_fixture f;
-  gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+  gpr_log(GPR_INFO, "%s/%s/%s", test_name, config.name, mode.name);
   f = config.create_fixture(client_args, server_args);
   config.init_client(&f, client_args);
   config.init_server(&f, server_args);
@@ -109,7 +110,8 @@
   grpc_op ops[6];
   grpc_op *op;
   grpc_call *c;
-  grpc_end2end_test_fixture f = begin_test(config, __FUNCTION__, NULL, NULL);
+  grpc_end2end_test_fixture f =
+      begin_test(config, __FUNCTION__, mode, NULL, NULL);
   gpr_timespec deadline = five_seconds_time();
   cq_verifier *v_client = cq_verifier_create(f.client_cq);
   grpc_metadata_array initial_metadata_recv;
diff --git a/test/core/end2end/tests/cancel_test_helpers.h b/test/core/end2end/tests/cancel_test_helpers.h
index f2581dc..0d680fc 100644
--- a/test/core/end2end/tests/cancel_test_helpers.h
+++ b/test/core/end2end/tests/cancel_test_helpers.h
@@ -35,6 +35,7 @@
 #define GRPC_TEST_CORE_END2END_TESTS_CANCEL_TEST_HELPERS_H
 
 typedef struct {
+  const char *name;
   grpc_call_error (*initiate_cancel)(grpc_call *call);
   grpc_status_code expect_status;
   const char *expect_details;
@@ -45,7 +46,9 @@
 }
 
 static const cancellation_mode cancellation_modes[] = {
-    {grpc_call_cancel, GRPC_STATUS_CANCELLED, ""},
-    {wait_for_deadline, GRPC_STATUS_DEADLINE_EXCEEDED, "Deadline Exceeded"}, };
+    {"cancel", grpc_call_cancel, GRPC_STATUS_CANCELLED, ""},
+    {"deadline", wait_for_deadline, GRPC_STATUS_DEADLINE_EXCEEDED,
+     "Deadline Exceeded"},
+};
 
-#endif  /* GRPC_TEST_CORE_END2END_TESTS_CANCEL_TEST_HELPERS_H */
+#endif /* GRPC_TEST_CORE_END2END_TESTS_CANCEL_TEST_HELPERS_H */
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index 708444a..1c02c4b 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -61,14 +61,14 @@
 
 static void test_no_op(void) {
   grpc_tcp_server *s = grpc_tcp_server_create();
-  grpc_tcp_server_destroy(s);
+  grpc_tcp_server_destroy(s, NULL, NULL);
 }
 
 static void test_no_op_with_start(void) {
   grpc_tcp_server *s = grpc_tcp_server_create();
   LOG_TEST();
   grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
-  grpc_tcp_server_destroy(s);
+  grpc_tcp_server_destroy(s, NULL, NULL);
 }
 
 static void test_no_op_with_port(void) {
@@ -81,7 +81,7 @@
   GPR_ASSERT(
       grpc_tcp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr)));
 
-  grpc_tcp_server_destroy(s);
+  grpc_tcp_server_destroy(s, NULL, NULL);
 }
 
 static void test_no_op_with_port_and_start(void) {
@@ -96,7 +96,7 @@
 
   grpc_tcp_server_start(s, NULL, 0, on_connect, NULL);
 
-  grpc_tcp_server_destroy(s);
+  grpc_tcp_server_destroy(s, NULL, NULL);
 }
 
 static void test_connect(int n) {
@@ -145,7 +145,7 @@
 
   gpr_mu_unlock(&mu);
 
-  grpc_tcp_server_destroy(s);
+  grpc_tcp_server_destroy(s, NULL, NULL);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/support/thd_test.c b/test/core/support/thd_test.c
index c03a905..bb3d54a 100644
--- a/test/core/support/thd_test.c
+++ b/test/core/support/thd_test.c
@@ -60,12 +60,16 @@
   gpr_mu_unlock(&t->mu);
 }
 
+static void thd_body_joinable(void *v) { }
+
 /* Test that we can create a number of threads and wait for them. */
 static void test(void) {
   int i;
   gpr_thd_id thd;
+  gpr_thd_id thds[1000];
   struct test t;
   int n = 1000;
+  gpr_thd_options options = gpr_thd_options_default();
   gpr_mu_init(&t.mu);
   gpr_cv_init(&t.done_cv);
   t.n = n;
@@ -79,6 +83,13 @@
   }
   gpr_mu_unlock(&t.mu);
   GPR_ASSERT(t.n == 0);
+  gpr_thd_options_set_joinable(&options);
+  for (i = 0; i < n; i++) {
+    GPR_ASSERT(gpr_thd_new(&thds[i], &thd_body_joinable, NULL, &options));
+  }
+  for (i = 0; i < n; i++) {
+    gpr_thd_join(thds[i]);
+  }
 }
 
 /* ------------------------------------------------- */
diff --git a/test/core/tsi/transport_security_test.c b/test/core/tsi/transport_security_test.c
index c5882af..d591e43 100644
--- a/test/core/tsi/transport_security_test.c
+++ b/test/core/tsi/transport_security_test.c
@@ -39,10 +39,15 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
+#include <openssl/crypto.h>
+
 #include "src/core/support/string.h"
 #include "src/core/tsi/ssl_transport_security.h"
 #include "test/core/util/test_config.h"
 
+/* Currently points to 1.0.2a. */
+#define GRPC_MIN_OPENSSL_VERSION_NUMBER 0x1000201fL
+
 typedef struct {
   /* 1 if success, 0 if failure. */
   int expected;
@@ -296,8 +301,13 @@
   }
 }
 
+static void test_openssl_version(void) {
+  GPR_ASSERT(OPENSSL_VERSION_NUMBER >= GRPC_MIN_OPENSSL_VERSION_NUMBER);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_peer_matches_name();
+  test_openssl_version();
   return 0;
 }
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
index 36f13e1..7467c2f 100644
--- a/test/core/util/port_posix.c
+++ b/test/core/util/port_posix.c
@@ -32,7 +32,8 @@
  */
 
 #include <grpc/support/port_platform.h>
-#ifdef GPR_POSIX_SOCKET
+#include "test/core/util/test_config.h"
+#if defined(GPR_POSIX_SOCKET) && defined(GRPC_TEST_PICK_PORT)
 
 #include "test/core/util/port.h"
 
@@ -125,7 +126,7 @@
     } else {
       port = 0;
     }
-    
+
     if (!is_port_available(&port, is_tcp)) {
       continue;
     }
@@ -155,4 +156,4 @@
   return port;
 }
 
-#endif /* GPR_POSIX_SOCKET */
+#endif /* GPR_POSIX_SOCKET && GRPC_TEST_PICK_PORT */
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 668a069..0b3c543 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -59,6 +59,10 @@
   gpr_time_add(gpr_now(),                  \
                gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)))
 
+#ifndef GRPC_TEST_CUSTOM_PICK_PORT
+#define GRPC_TEST_PICK_PORT
+#endif
+
 void grpc_test_init(int argc, char **argv);
 
 #ifdef __cplusplus
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 4c71831..dd294d9 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -35,8 +35,8 @@
 #include <memory>
 
 #include "test/core/util/test_config.h"
-#include "test/cpp/util/echo_duplicate.pb.h"
-#include "test/cpp/util/echo.pb.h"
+#include "test/cpp/util/echo_duplicate.grpc.pb.h"
+#include "test/cpp/util/echo.grpc.pb.h"
 #include "src/cpp/util/time.h"
 #include <grpc++/async_unary_call.h>
 #include <grpc++/channel_arguments.h>
@@ -532,15 +532,19 @@
   send_request.set_message("Hello");
   std::pair<grpc::string, grpc::string> meta1("key1", "val1");
   std::pair<grpc::string, grpc::string> meta2(
-      "key2-bin", {"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc", 13});
+      "key2-bin",
+      grpc::string("\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc",
+		   13));
   std::pair<grpc::string, grpc::string> meta3("key3", "val3");
   std::pair<grpc::string, grpc::string> meta6(
       "key4-bin",
-      {"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d", 14});
+      grpc::string("\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d",
+		   14));
   std::pair<grpc::string, grpc::string> meta5("key5", "val5");
   std::pair<grpc::string, grpc::string> meta4(
       "key6-bin",
-      {"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee", 15});
+      grpc::string("\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee",
+		   15));
 
   cli_ctx.AddMetadata(meta1.first, meta1.second);
   cli_ctx.AddMetadata(meta2.first, meta2.second);
@@ -595,6 +599,5 @@
   ::testing::InitGoogleTest(&argc, argv);
   int result = RUN_ALL_TESTS();
   grpc_shutdown();
-  google::protobuf::ShutdownProtobufLibrary();
   return result;
 }
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 41c2669..f96051c 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -35,8 +35,8 @@
 #include <thread>
 
 #include "test/core/util/test_config.h"
-#include "test/cpp/util/echo_duplicate.pb.h"
-#include "test/cpp/util/echo.pb.h"
+#include "test/cpp/util/echo_duplicate.grpc.pb.h"
+#include "test/cpp/util/echo.grpc.pb.h"
 #include "src/cpp/util/time.h"
 #include "src/cpp/server/thread_pool.h"
 #include <grpc++/channel_arguments.h>
@@ -83,10 +83,30 @@
 
 class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service {
  public:
+  TestServiceImpl() : signal_client_(false) {}
+
   Status Echo(ServerContext* context, const EchoRequest* request,
               EchoResponse* response) GRPC_OVERRIDE {
     response->set_message(request->message());
     MaybeEchoDeadline(context, request, response);
+    if (request->has_param() && request->param().client_cancel_after_us()) {
+      {
+        std::unique_lock<std::mutex> lock(mu_);
+        signal_client_ = true;
+      }
+      while (!context->IsCancelled()) {
+        std::this_thread::sleep_for(std::chrono::microseconds(
+            request->param().client_cancel_after_us()));
+      }
+      return Status::Cancelled;
+    } else if (request->has_param() &&
+               request->param().server_cancel_after_us()) {
+      std::this_thread::sleep_for(
+          std::chrono::microseconds(request->param().server_cancel_after_us()));
+      return Status::Cancelled;
+    } else {
+      EXPECT_FALSE(context->IsCancelled());
+    }
     return Status::OK;
   }
 
@@ -130,6 +150,15 @@
     }
     return Status::OK;
   }
+
+  bool signal_client() {
+    std::unique_lock<std::mutex> lock(mu_);
+    return signal_client_;
+  }
+
+ private:
+  bool signal_client_;
+  std::mutex mu_;
 };
 
 class TestServiceImplDupPkg
@@ -151,7 +180,8 @@
     server_address_ << "localhost:" << port;
     // Setup server
     ServerBuilder builder;
-    builder.AddListeningPort(server_address_.str(), InsecureServerCredentials());
+    builder.AddListeningPort(server_address_.str(),
+                             InsecureServerCredentials());
     builder.RegisterService(&service_);
     builder.RegisterService(&dup_pkg_service_);
     builder.SetThreadPool(&thread_pool_);
@@ -423,6 +453,44 @@
   EXPECT_EQ("Rpc sent on a lame channel.", s.details());
 }
 
+void CancelRpc(ClientContext* context, int delay_us, TestServiceImpl* service) {
+  std::this_thread::sleep_for(std::chrono::microseconds(delay_us));
+  while (!service->signal_client()) {
+  }
+  context->TryCancel();
+}
+
+// Client cancels rpc after 10ms
+TEST_F(End2endTest, ClientCancelsRpc) {
+  ResetStub();
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello");
+  const int kCancelDelayUs = 10 * 1000;
+  request.mutable_param()->set_client_cancel_after_us(kCancelDelayUs);
+
+  ClientContext context;
+  std::thread cancel_thread(CancelRpc, &context, kCancelDelayUs, &service_);
+  Status s = stub_->Echo(&context, request, &response);
+  cancel_thread.join();
+  EXPECT_EQ(StatusCode::CANCELLED, s.code());
+  EXPECT_TRUE(s.details().empty());
+}
+
+// Server cancels rpc after 1ms
+TEST_F(End2endTest, ServerCancelsRpc) {
+  ResetStub();
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello");
+  request.mutable_param()->set_server_cancel_after_us(1000);
+
+  ClientContext context;
+  Status s = stub_->Echo(&context, request, &response);
+  EXPECT_EQ(StatusCode::CANCELLED, s.code());
+  EXPECT_TRUE(s.details().empty());
+}
+
 }  // namespace testing
 }  // namespace grpc
 
@@ -432,6 +500,5 @@
   ::testing::InitGoogleTest(&argc, argv);
   int result = RUN_ALL_TESTS();
   grpc_shutdown();
-  google::protobuf::ShutdownProtobufLibrary();
   return result;
 }
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index 711f1b9..eb6f536 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -38,7 +38,7 @@
 #include "src/cpp/util/time.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
-#include "test/cpp/util/echo.pb.h"
+#include "test/cpp/util/echo.grpc.pb.h"
 #include <grpc++/async_generic_service.h>
 #include <grpc++/async_unary_call.h>
 #include <grpc++/byte_buffer.h>
@@ -47,6 +47,7 @@
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/credentials.h>
+#include <grpc++/generic_stub.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
@@ -83,12 +84,21 @@
   buffer->Dump(&slices);
   grpc::string buf;
   buf.reserve(buffer->Length());
-  for (const Slice& s : slices) {
-    buf.append(reinterpret_cast<const char*>(s.begin()), s.size());
+  for (auto s = slices.begin(); s != slices.end(); s++) {
+    buf.append(reinterpret_cast<const char*>(s->begin()), s->size());
   }
   return message->ParseFromString(buf);
 }
 
+std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
+    grpc::protobuf::Message* message) {
+  grpc::string buf;
+  message->SerializeToString(&buf);
+  gpr_slice s = gpr_slice_from_copied_string(buf.c_str());
+  Slice slice(s, Slice::STEAL_REF);
+  return std::unique_ptr<ByteBuffer>(new ByteBuffer(&slice, 1));
+}
+
 class GenericEnd2endTest : public ::testing::Test {
  protected:
   GenericEnd2endTest() : generic_service_("*") {}
@@ -118,7 +128,7 @@
   void ResetStub() {
     std::shared_ptr<ChannelInterface> channel = CreateChannel(
         server_address_.str(), InsecureCredentials(), ChannelArguments());
-    stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel));
+    generic_stub_.reset(new GenericStub(channel));
   }
 
   void server_ok(int i) { verify_ok(&srv_cq_, i, true); }
@@ -127,6 +137,7 @@
   void client_fail(int i) { verify_ok(&cli_cq_, i, false); }
 
   void SendRpc(int num_rpcs) {
+    const grpc::string kMethodName("/grpc.cpp.test.util.TestService/Echo");
     for (int i = 0; i < num_rpcs; i++) {
       EchoRequest send_request;
       EchoRequest recv_request;
@@ -139,35 +150,42 @@
       GenericServerAsyncReaderWriter stream(&srv_ctx);
 
       send_request.set_message("Hello");
-      std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
-          stub_->AsyncEcho(&cli_ctx, send_request, &cli_cq_, tag(1)));
+      std::unique_ptr<GenericClientAsyncReaderWriter> call =
+          generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
       client_ok(1);
+      std::unique_ptr<ByteBuffer> send_buffer =
+          SerializeToByteBuffer(&send_request);
+      call->Write(*send_buffer, tag(2));
+      client_ok(2);
+      call->WritesDone(tag(3));
+      client_ok(3);
 
-      generic_service_.RequestCall(&srv_ctx, &stream, &srv_cq_, tag(2));
+      generic_service_.RequestCall(&srv_ctx, &stream, &srv_cq_, tag(4));
 
-      verify_ok(generic_service_.completion_queue(), 2, true);
+      verify_ok(generic_service_.completion_queue(), 4, true);
       EXPECT_EQ(server_address_.str(), srv_ctx.host());
-      EXPECT_EQ("/grpc.cpp.test.util.TestService/Echo", srv_ctx.method());
+      EXPECT_EQ(kMethodName, srv_ctx.method());
       ByteBuffer recv_buffer;
-      stream.Read(&recv_buffer, tag(3));
-      server_ok(3);
+      stream.Read(&recv_buffer, tag(5));
+      server_ok(5);
       EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
       EXPECT_EQ(send_request.message(), recv_request.message());
 
       send_response.set_message(recv_request.message());
-      grpc::string buf;
-      send_response.SerializeToString(&buf);
-      gpr_slice s = gpr_slice_from_copied_string(buf.c_str());
-      Slice slice(s, Slice::STEAL_REF);
-      ByteBuffer send_buffer(&slice, 1);
-      stream.Write(send_buffer, tag(4));
-      server_ok(4);
+      send_buffer = SerializeToByteBuffer(&send_response);
+      stream.Write(*send_buffer, tag(6));
+      server_ok(6);
 
-      stream.Finish(Status::OK, tag(5));
-      server_ok(5);
+      stream.Finish(Status::OK, tag(7));
+      server_ok(7);
 
-      response_reader->Finish(&recv_response, &recv_status, tag(4));
-      client_ok(4);
+      recv_buffer.Clear();
+      call->Read(&recv_buffer, tag(8));
+      client_ok(8);
+      EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
+
+      call->Finish(&recv_status, tag(9));
+      client_ok(9);
 
       EXPECT_EQ(send_response.message(), recv_response.message());
       EXPECT_TRUE(recv_status.IsOk());
@@ -177,6 +195,7 @@
   CompletionQueue cli_cq_;
   CompletionQueue srv_cq_;
   std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_;
+  std::unique_ptr<grpc::GenericStub> generic_stub_;
   std::unique_ptr<Server> server_;
   AsyncGenericService generic_service_;
   std::ostringstream server_address_;
@@ -196,6 +215,7 @@
 TEST_F(GenericEnd2endTest, SimpleBidiStreaming) {
   ResetStub();
 
+  const grpc::string kMethodName("/grpc.cpp.test.util.TestService/BidiStream");
   EchoRequest send_request;
   EchoRequest recv_request;
   EchoResponse send_response;
@@ -206,17 +226,19 @@
   GenericServerAsyncReaderWriter srv_stream(&srv_ctx);
 
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse> >
-      cli_stream(stub_->AsyncBidiStream(&cli_ctx, &cli_cq_, tag(1)));
+  std::unique_ptr<GenericClientAsyncReaderWriter> cli_stream =
+      generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
   client_ok(1);
 
   generic_service_.RequestCall(&srv_ctx, &srv_stream, &srv_cq_, tag(2));
 
   verify_ok(generic_service_.completion_queue(), 2, true);
   EXPECT_EQ(server_address_.str(), srv_ctx.host());
-  EXPECT_EQ("/grpc.cpp.test.util.TestService/BidiStream", srv_ctx.method());
+  EXPECT_EQ(kMethodName, srv_ctx.method());
 
-  cli_stream->Write(send_request, tag(3));
+  std::unique_ptr<ByteBuffer> send_buffer =
+      SerializeToByteBuffer(&send_request);
+  cli_stream->Write(*send_buffer, tag(3));
   client_ok(3);
 
   ByteBuffer recv_buffer;
@@ -226,22 +248,18 @@
   EXPECT_EQ(send_request.message(), recv_request.message());
 
   send_response.set_message(recv_request.message());
-  grpc::string buf;
-  send_response.SerializeToString(&buf);
-  gpr_slice s = gpr_slice_from_copied_string(buf.c_str());
-  Slice slice(s, Slice::STEAL_REF);
-  ByteBuffer send_buffer(&slice, 1);
-  srv_stream.Write(send_buffer, tag(5));
+  send_buffer = SerializeToByteBuffer(&send_response);
+  srv_stream.Write(*send_buffer, tag(5));
   server_ok(5);
 
-  cli_stream->Read(&recv_response, tag(6));
+  cli_stream->Read(&recv_buffer, tag(6));
   client_ok(6);
+  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
   EXPECT_EQ(send_response.message(), recv_response.message());
 
   cli_stream->WritesDone(tag(7));
   client_ok(7);
 
-  recv_buffer.Clear();
   srv_stream.Read(&recv_buffer, tag(8));
   server_fail(8);
 
@@ -265,6 +283,5 @@
   ::testing::InitGoogleTest(&argc, argv);
   int result = RUN_ALL_TESTS();
   grpc_shutdown();
-  google::protobuf::ShutdownProtobufLibrary();
   return result;
 }
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index de6c6b7..7c5e1aa 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -51,9 +51,9 @@
 #include <grpc++/status.h>
 #include <grpc++/stream.h>
 #include "test/cpp/util/create_test_channel.h"
-#include "test/cpp/interop/test.pb.h"
-#include "test/cpp/interop/empty.pb.h"
-#include "test/cpp/interop/messages.pb.h"
+#include "test/cpp/interop/test.grpc.pb.h"
+#include "test/cpp/interop/empty.grpc.pb.h"
+#include "test/cpp/interop/messages.grpc.pb.h"
 
 DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
 DEFINE_bool(use_prod_roots, false, "True to use SSL roots for google");
diff --git a/test/cpp/interop/server.cc b/test/cpp/interop/server.cc
index eceb600..87bf489 100644
--- a/test/cpp/interop/server.cc
+++ b/test/cpp/interop/server.cc
@@ -49,9 +49,9 @@
 #include <grpc++/server_credentials.h>
 #include <grpc++/status.h>
 #include <grpc++/stream.h>
-#include "test/cpp/interop/test.pb.h"
-#include "test/cpp/interop/empty.pb.h"
-#include "test/cpp/interop/messages.pb.h"
+#include "test/cpp/interop/test.grpc.pb.h"
+#include "test/cpp/interop/empty.grpc.pb.h"
+#include "test/cpp/interop/messages.grpc.pb.h"
 
 DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
 DEFINE_int32(port, 0, "Server port.");
@@ -213,8 +213,11 @@
   builder.RegisterService(&service);
   std::shared_ptr<ServerCredentials> creds = grpc::InsecureServerCredentials();
   if (FLAGS_enable_ssl) {
-    SslServerCredentialsOptions ssl_opts = {
-        "", {{test_server1_key, test_server1_cert}}};
+    SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
+							test_server1_cert};
+    SslServerCredentialsOptions ssl_opts;
+    ssl_opts.pem_root_certs = "";
+    ssl_opts.pem_key_cert_pairs.push_back(pkcp);
     creds = grpc::SslServerCredentials(ssl_opts);
   }
   builder.AddListeningPort(server_address.str(), creds);
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 221fb30..2dc5b38 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -36,7 +36,7 @@
 
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/timer.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 
 #include <condition_variable>
 #include <mutex>
@@ -104,7 +104,7 @@
 
   void EndThreads() { threads_.clear(); }
 
-  virtual void ThreadFunc(Histogram* histogram, size_t thread_idx) = 0;
+  virtual bool ThreadFunc(Histogram* histogram, size_t thread_idx) = 0;
 
  private:
   class Thread {
@@ -113,20 +113,24 @@
         : done_(false),
           new_(nullptr),
           impl_([this, idx, client]() {
-            for (;;) {
-              // run the loop body
-              client->ThreadFunc(&histogram_, idx);
-              // lock, see if we're done
-              std::lock_guard<std::mutex> g(mu_);
-              if (done_) return;
-              // also check if we're marking, and swap out the histogram if so
-              if (new_) {
-                new_->Swap(&histogram_);
-                new_ = nullptr;
-                cv_.notify_one();
+              for (;;) {
+                // run the loop body
+        	      bool thread_still_ok = client->ThreadFunc(&histogram_, idx);
+                // lock, see if we're done
+                std::lock_guard<std::mutex> g(mu_);
+                if (!thread_still_ok) {
+                  gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
+                  done_ = true;
+                }
+                if (done_) {return;}
+        	      // check if we're marking, swap out the histogram if so
+        	      if (new_) {
+                        new_->Swap(&histogram_);
+                        new_ = nullptr;
+                        cv_.notify_one();
+                }
               }
-            }
-          }) {}
+            }) {}
 
     ~Thread() {
       {
@@ -164,8 +168,12 @@
   std::unique_ptr<Timer> timer_;
 };
 
-std::unique_ptr<Client> CreateSynchronousClient(const ClientConfig& args);
-std::unique_ptr<Client> CreateAsyncClient(const ClientConfig& args);
+std::unique_ptr<Client>
+  CreateSynchronousUnaryClient(const ClientConfig& args);
+std::unique_ptr<Client>
+  CreateSynchronousStreamingClient(const ClientConfig& args);
+std::unique_ptr<Client> CreateAsyncUnaryClient(const ClientConfig& args);
+std::unique_ptr<Client> CreateAsyncStreamingClient(const ClientConfig& args);
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 526f37a..0a6d9be 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -46,9 +46,9 @@
 #include <grpc++/async_unary_call.h>
 #include <grpc++/client_context.h>
 #include <grpc++/status.h>
-#include "test/core/util/grpc_profiler.h"
+#include <grpc++/stream.h>
 #include "test/cpp/util/create_test_channel.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 #include "test/cpp/qps/timer.h"
 #include "test/cpp/qps/client.h"
 
@@ -59,13 +59,13 @@
  public:
   ClientRpcContext() {}
   virtual ~ClientRpcContext() {}
-  virtual bool RunNextState() = 0;  // do next state, return false if steps done
+  // next state, return false if done. Collect stats when appropriate
+  virtual bool RunNextState(bool, Histogram* hist) = 0;
   virtual void StartNewClone() = 0;
   static void* tag(ClientRpcContext* c) { return reinterpret_cast<void*>(c); }
   static ClientRpcContext* detag(void* t) {
     return reinterpret_cast<ClientRpcContext*>(t);
   }
-  virtual void report_stats(Histogram* hist) = 0;
 };
 
 template <class RequestType, class ResponseType>
@@ -89,9 +89,12 @@
         response_reader_(
             start_req(stub_, &context_, req_, ClientRpcContext::tag(this))) {}
   ~ClientRpcContextUnaryImpl() GRPC_OVERRIDE {}
-  bool RunNextState() GRPC_OVERRIDE { return (this->*next_state_)(); }
-  void report_stats(Histogram* hist) GRPC_OVERRIDE {
-    hist->Add((Timer::Now() - start_) * 1e9);
+  bool RunNextState(bool ok, Histogram* hist) GRPC_OVERRIDE {
+    bool ret = (this->*next_state_)(ok);
+    if (!ret) {
+      hist->Add((Timer::Now() - start_) * 1e9);
+    }
+    return ret;
   }
 
   void StartNewClone() GRPC_OVERRIDE {
@@ -99,16 +102,16 @@
   }
 
  private:
-  bool ReqSent() {
+  bool ReqSent(bool) {
     next_state_ = &ClientRpcContextUnaryImpl::RespDone;
     response_reader_->Finish(&response_, &status_, ClientRpcContext::tag(this));
     return true;
   }
-  bool RespDone() {
+  bool RespDone(bool) {
     next_state_ = &ClientRpcContextUnaryImpl::DoCallBack;
     return false;
   }
-  bool DoCallBack() {
+  bool DoCallBack(bool) {
     callback_(status_, &response_);
     return false;
   }
@@ -116,7 +119,7 @@
   TestService::Stub* stub_;
   RequestType req_;
   ResponseType response_;
-  bool (ClientRpcContextUnaryImpl::*next_state_)();
+  bool (ClientRpcContextUnaryImpl::*next_state_)(bool);
   std::function<void(grpc::Status, ResponseType*)> callback_;
   std::function<std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
       TestService::Stub*, grpc::ClientContext*, const RequestType&, void*)>
@@ -127,24 +130,19 @@
       response_reader_;
 };
 
-class AsyncClient GRPC_FINAL : public Client {
+class AsyncUnaryClient GRPC_FINAL : public Client {
  public:
-  explicit AsyncClient(const ClientConfig& config) : Client(config) {
+  explicit AsyncUnaryClient(const ClientConfig& config) : Client(config) {
     for (int i = 0; i < config.async_client_threads(); i++) {
       cli_cqs_.emplace_back(new CompletionQueue);
     }
 
-    auto payload_size = config.payload_size();
-    auto check_done = [payload_size](grpc::Status s, SimpleResponse* response) {
-      GPR_ASSERT(s.IsOk() && (response->payload().type() ==
-                              grpc::testing::PayloadType::COMPRESSABLE) &&
-                 (response->payload().body().length() ==
-                  static_cast<size_t>(payload_size)));
-    };
+    auto check_done = [](grpc::Status s, SimpleResponse* response) {};
 
     int t = 0;
     for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
-      for (auto& channel : channels_) {
+      for (auto channel = channels_.begin(); channel != channels_.end();
+	   channel++) {
         auto* cq = cli_cqs_[t].get();
         t = (t + 1) % cli_cqs_.size();
         auto start_req = [cq](TestService::Stub* stub, grpc::ClientContext* ctx,
@@ -152,7 +150,7 @@
           return stub->AsyncUnaryCall(ctx, request, cq, tag);
         };
 
-        TestService::Stub* stub = channel.get_stub();
+        TestService::Stub* stub = channel->get_stub();
         const SimpleRequest& request = request_;
         new ClientRpcContextUnaryImpl<SimpleRequest, SimpleResponse>(
             stub, request, start_req, check_done);
@@ -162,39 +160,181 @@
     StartThreads(config.async_client_threads());
   }
 
-  ~AsyncClient() GRPC_OVERRIDE {
+  ~AsyncUnaryClient() GRPC_OVERRIDE {
     EndThreads();
 
-    for (auto& cq : cli_cqs_) {
-      cq->Shutdown();
+    for (auto cq = cli_cqs_.begin(); cq != cli_cqs_.end(); cq++) {
+      (*cq)->Shutdown();
       void* got_tag;
       bool ok;
-      while (cq->Next(&got_tag, &ok)) {
+      while ((*cq)->Next(&got_tag, &ok)) {
         delete ClientRpcContext::detag(got_tag);
       }
     }
   }
 
-  void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
+  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
     void* got_tag;
     bool ok;
-    cli_cqs_[thread_idx]->Next(&got_tag, &ok);
+    switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) {
+      case CompletionQueue::SHUTDOWN: return false;
+      case CompletionQueue::TIMEOUT: return true;
+      case CompletionQueue::GOT_EVENT: break;
+    }
 
     ClientRpcContext* ctx = ClientRpcContext::detag(got_tag);
-    if (ctx->RunNextState() == false) {
+    if (ctx->RunNextState(ok, histogram) == false) {
       // call the callback and then delete it
-      ctx->report_stats(histogram);
-      ctx->RunNextState();
+      ctx->RunNextState(ok, histogram);
       ctx->StartNewClone();
       delete ctx;
     }
+
+    return true;
   }
 
   std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
 };
 
-std::unique_ptr<Client> CreateAsyncClient(const ClientConfig& args) {
-  return std::unique_ptr<Client>(new AsyncClient(args));
+template <class RequestType, class ResponseType>
+class ClientRpcContextStreamingImpl : public ClientRpcContext {
+ public:
+  ClientRpcContextStreamingImpl(
+      TestService::Stub *stub, const RequestType &req,
+      std::function<
+              std::unique_ptr<grpc::ClientAsyncReaderWriter<
+                              RequestType,ResponseType>>(
+              TestService::Stub *, grpc::ClientContext *, void *)> start_req,
+      std::function<void(grpc::Status, ResponseType *)> on_done)
+      : context_(),
+        stub_(stub),
+        req_(req),
+        response_(),
+        next_state_(&ClientRpcContextStreamingImpl::ReqSent),
+        callback_(on_done),
+        start_req_(start_req),
+        start_(Timer::Now()),
+        stream_(start_req_(stub_, &context_, ClientRpcContext::tag(this))) {}
+  ~ClientRpcContextStreamingImpl() GRPC_OVERRIDE {}
+  bool RunNextState(bool ok, Histogram *hist) GRPC_OVERRIDE {
+    return (this->*next_state_)(ok, hist);
+  }
+  void StartNewClone() GRPC_OVERRIDE {
+    new ClientRpcContextStreamingImpl(stub_, req_, start_req_, callback_);
+  }
+
+ private:
+  bool ReqSent(bool ok, Histogram *) {
+    return StartWrite(ok);
+  }
+  bool StartWrite(bool ok) {
+    if (!ok) {
+      return(false);
+    }
+    start_ = Timer::Now();
+    next_state_ = &ClientRpcContextStreamingImpl::WriteDone;
+    stream_->Write(req_, ClientRpcContext::tag(this));
+    return true;
+  }
+  bool WriteDone(bool ok, Histogram *) {
+    if (!ok) {
+      return(false);
+    }
+    next_state_ = &ClientRpcContextStreamingImpl::ReadDone;
+    stream_->Read(&response_, ClientRpcContext::tag(this)); 
+    return true;
+  }
+  bool ReadDone(bool ok, Histogram *hist) {
+    hist->Add((Timer::Now() - start_) * 1e9);
+    return StartWrite(ok);
+  }
+  grpc::ClientContext context_;
+  TestService::Stub *stub_;
+  RequestType req_;
+  ResponseType response_;
+  bool (ClientRpcContextStreamingImpl::*next_state_)(bool, Histogram *);
+  std::function<void(grpc::Status, ResponseType *)> callback_;
+  std::function<std::unique_ptr<grpc::ClientAsyncReaderWriter<
+				  RequestType,ResponseType>>(
+      TestService::Stub *, grpc::ClientContext *, void *)> start_req_;
+  grpc::Status status_;
+  double start_;
+  std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType,ResponseType>>
+    stream_;
+};
+
+class AsyncStreamingClient GRPC_FINAL : public Client {
+ public:
+  explicit AsyncStreamingClient(const ClientConfig &config) : Client(config) {
+    for (int i = 0; i < config.async_client_threads(); i++) {
+      cli_cqs_.emplace_back(new CompletionQueue);
+    }
+
+    auto check_done = [](grpc::Status s, SimpleResponse* response) {};
+
+    int t = 0;
+    for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
+      for (auto channel = channels_.begin(); channel != channels_.end();
+           channel++) {
+        auto* cq = cli_cqs_[t].get();
+        t = (t + 1) % cli_cqs_.size();
+        auto start_req = [cq](TestService::Stub *stub, grpc::ClientContext *ctx,
+                              void *tag) {
+          auto stream = stub->AsyncStreamingCall(ctx, cq, tag);
+          return stream;
+        };
+
+        TestService::Stub *stub = channel->get_stub();
+        const SimpleRequest &request = request_;
+        new ClientRpcContextStreamingImpl<SimpleRequest, SimpleResponse>(
+            stub, request, start_req, check_done);
+      }
+    }
+
+    StartThreads(config.async_client_threads());
+  }
+
+  ~AsyncStreamingClient() GRPC_OVERRIDE {
+    EndThreads();
+
+    for (auto cq = cli_cqs_.begin(); cq != cli_cqs_.end(); cq++) {
+      (*cq)->Shutdown();
+      void *got_tag;
+      bool ok;
+      while ((*cq)->Next(&got_tag, &ok)) {
+        delete ClientRpcContext::detag(got_tag);
+      }
+    }
+  }
+
+  bool ThreadFunc(Histogram *histogram, size_t thread_idx) GRPC_OVERRIDE {
+    void *got_tag;
+    bool ok;
+    switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) {
+      case CompletionQueue::SHUTDOWN: return false;
+      case CompletionQueue::TIMEOUT: return true;
+      case CompletionQueue::GOT_EVENT: break;
+    }
+
+    ClientRpcContext *ctx = ClientRpcContext::detag(got_tag);
+    if (ctx->RunNextState(ok, histogram) == false) {
+      // call the callback and then delete it
+      ctx->RunNextState(ok, histogram);
+      ctx->StartNewClone();
+      delete ctx;
+    }
+
+    return true;
+  }
+
+  std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
+};
+
+std::unique_ptr<Client> CreateAsyncUnaryClient(const ClientConfig& args) {
+  return std::unique_ptr<Client>(new AsyncUnaryClient(args));
+}
+std::unique_ptr<Client> CreateAsyncStreamingClient(const ClientConfig& args) {
+  return std::unique_ptr<Client>(new AsyncStreamingClient(args));
 }
 
 }  // namespace testing
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 7bb7231..aea5a0f 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -48,45 +48,91 @@
 #include <grpc/support/host_port.h>
 #include <gflags/gflags.h>
 #include <grpc++/client_context.h>
-#include <grpc++/status.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
-#include "test/core/util/grpc_profiler.h"
+#include <grpc++/status.h>
+#include <grpc++/stream.h>
+#include <gtest/gtest.h>
 #include "test/cpp/util/create_test_channel.h"
 #include "test/cpp/qps/client.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/timer.h"
 
 namespace grpc {
 namespace testing {
 
-class SynchronousClient GRPC_FINAL : public Client {
+class SynchronousClient : public Client {
  public:
   SynchronousClient(const ClientConfig& config) : Client(config) {
-    size_t num_threads =
-        config.outstanding_rpcs_per_channel() * config.client_channels();
-    responses_.resize(num_threads);
-    StartThreads(num_threads);
+    num_threads_ =
+      config.outstanding_rpcs_per_channel() * config.client_channels();
+    responses_.resize(num_threads_);
   }
 
-  ~SynchronousClient() { EndThreads(); }
+  virtual ~SynchronousClient() { EndThreads(); }
 
-  void ThreadFunc(Histogram* histogram, size_t thread_idx) {
+ protected:
+  size_t num_threads_;
+  std::vector<SimpleResponse> responses_;
+};
+
+class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient {
+ public:
+  SynchronousUnaryClient(const ClientConfig& config):
+    SynchronousClient(config) {StartThreads(num_threads_);}
+  ~SynchronousUnaryClient() {}
+  
+  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
     double start = Timer::Now();
     grpc::ClientContext context;
     grpc::Status s =
         stub->UnaryCall(&context, request_, &responses_[thread_idx]);
     histogram->Add((Timer::Now() - start) * 1e9);
+    return s.IsOk();
   }
-
- private:
-  std::vector<SimpleResponse> responses_;
 };
 
-std::unique_ptr<Client> CreateSynchronousClient(const ClientConfig& config) {
-  return std::unique_ptr<Client>(new SynchronousClient(config));
+class SynchronousStreamingClient GRPC_FINAL : public SynchronousClient {
+ public:
+  SynchronousStreamingClient(const ClientConfig& config):
+    SynchronousClient(config) {
+    for (size_t thread_idx=0;thread_idx<num_threads_;thread_idx++){
+      auto* stub = channels_[thread_idx % channels_.size()].get_stub();
+      stream_ = stub->StreamingCall(&context_);
+    }
+    StartThreads(num_threads_);
+  }
+  ~SynchronousStreamingClient() {
+    if (stream_) {
+      SimpleResponse response;
+      stream_->WritesDone();
+      EXPECT_TRUE(stream_->Finish().IsOk());
+    }
+  }
+
+  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
+    double start = Timer::Now();
+    if (stream_->Write(request_) && stream_->Read(&responses_[thread_idx])) {
+      histogram->Add((Timer::Now() - start) * 1e9);
+      return true;
+    }
+    return false;
+  }
+  private:
+    grpc::ClientContext context_;
+    std::unique_ptr<grpc::ClientReaderWriter<SimpleRequest,
+                                             SimpleResponse>> stream_;
+};
+
+std::unique_ptr<Client>
+CreateSynchronousUnaryClient(const ClientConfig& config) {
+  return std::unique_ptr<Client>(new SynchronousUnaryClient(config));
+}
+std::unique_ptr<Client>
+CreateSynchronousStreamingClient(const ClientConfig& config) {
+  return std::unique_ptr<Client>(new SynchronousStreamingClient(config));
 }
 
 }  // namespace testing
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index d29ca1d..f448837 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -74,7 +74,9 @@
 ScenarioResult RunScenario(const ClientConfig& initial_client_config,
                            size_t num_clients,
                            const ServerConfig& server_config,
-                           size_t num_servers) {
+                           size_t num_servers,
+                           int warmup_seconds,
+                           int benchmark_seconds) {
   // ClientContext allocator (all are destroyed at scope exit)
   list<ClientContext> contexts;
   auto alloc_context = [&contexts]() {
@@ -146,7 +148,7 @@
   // Let everything warmup
   gpr_log(GPR_INFO, "Warming up");
   gpr_timespec start = gpr_now();
-  gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(5)));
+  gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(warmup_seconds)));
 
   // Start a run
   gpr_log(GPR_INFO, "Starting");
@@ -154,55 +156,55 @@
   server_mark.mutable_mark();
   ClientArgs client_mark;
   client_mark.mutable_mark();
-  for (auto& server : servers) {
-    GPR_ASSERT(server.stream->Write(server_mark));
+  for (auto server = servers.begin(); server != servers.end(); server++) {
+    GPR_ASSERT(server->stream->Write(server_mark));
   }
-  for (auto& client : clients) {
-    GPR_ASSERT(client.stream->Write(client_mark));
+  for (auto client = clients.begin(); client != clients.end(); client++) {
+    GPR_ASSERT(client->stream->Write(client_mark));
   }
   ServerStatus server_status;
   ClientStatus client_status;
-  for (auto& server : servers) {
-    GPR_ASSERT(server.stream->Read(&server_status));
+  for (auto server = servers.begin(); server != servers.end(); server++) {
+    GPR_ASSERT(server->stream->Read(&server_status));
   }
-  for (auto& client : clients) {
-    GPR_ASSERT(client.stream->Read(&client_status));
+  for (auto client = clients.begin(); client != clients.end(); client++) {
+    GPR_ASSERT(client->stream->Read(&client_status));
   }
 
   // Wait some time
   gpr_log(GPR_INFO, "Running");
-  gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(15)));
+  gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(benchmark_seconds)));
 
   // Finish a run
   ScenarioResult result;
   gpr_log(GPR_INFO, "Finishing");
-  for (auto& server : servers) {
-    GPR_ASSERT(server.stream->Write(server_mark));
+  for (auto server = servers.begin(); server != servers.end(); server++) {
+    GPR_ASSERT(server->stream->Write(server_mark));
   }
-  for (auto& client : clients) {
-    GPR_ASSERT(client.stream->Write(client_mark));
+  for (auto client = clients.begin(); client != clients.end(); client++) {
+    GPR_ASSERT(client->stream->Write(client_mark));
   }
-  for (auto& server : servers) {
-    GPR_ASSERT(server.stream->Read(&server_status));
+  for (auto server = servers.begin(); server != servers.end(); server++) {
+    GPR_ASSERT(server->stream->Read(&server_status));
     const auto& stats = server_status.stats();
     result.server_resources.push_back(ResourceUsage{
         stats.time_elapsed(), stats.time_user(), stats.time_system()});
   }
-  for (auto& client : clients) {
-    GPR_ASSERT(client.stream->Read(&client_status));
+  for (auto client = clients.begin(); client != clients.end(); client++) {
+    GPR_ASSERT(client->stream->Read(&client_status));
     const auto& stats = client_status.stats();
     result.latencies.MergeProto(stats.latencies());
     result.client_resources.push_back(ResourceUsage{
         stats.time_elapsed(), stats.time_user(), stats.time_system()});
   }
 
-  for (auto& client : clients) {
-    GPR_ASSERT(client.stream->WritesDone());
-    GPR_ASSERT(client.stream->Finish().IsOk());
+  for (auto client = clients.begin(); client != clients.end(); client++) {
+    GPR_ASSERT(client->stream->WritesDone());
+    GPR_ASSERT(client->stream->Finish().IsOk());
   }
-  for (auto& server : servers) {
-    GPR_ASSERT(server.stream->WritesDone());
-    GPR_ASSERT(server.stream->Finish().IsOk());
+  for (auto server = servers.begin(); server != servers.end(); server++) {
+    GPR_ASSERT(server->stream->WritesDone());
+    GPR_ASSERT(server->stream->Finish().IsOk());
   }
   return result;
 }
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index d87e80d..b3a8bf8 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -35,7 +35,7 @@
 #define TEST_QPS_DRIVER_H
 
 #include "test/cpp/qps/histogram.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -54,7 +54,10 @@
 ScenarioResult RunScenario(const grpc::testing::ClientConfig& client_config,
                            size_t num_clients,
                            const grpc::testing::ServerConfig& server_config,
-                           size_t num_servers);
+                           size_t num_servers,
+                           int warmup_seconds,
+                           int benchmark_seconds);
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h
index 7ba00e9..0547b72 100644
--- a/test/cpp/qps/histogram.h
+++ b/test/cpp/qps/histogram.h
@@ -35,7 +35,7 @@
 #define TEST_QPS_HISTOGRAM_H
 
 #include <grpc/support/histogram.h>
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -50,10 +50,10 @@
 
   void Merge(Histogram* h) { gpr_histogram_merge(impl_, h->impl_); }
   void Add(double value) { gpr_histogram_add(impl_, value); }
-  double Percentile(double pctile) {
+  double Percentile(double pctile) const {
     return gpr_histogram_percentile(impl_, pctile);
   }
-  double Count() { return gpr_histogram_count(impl_); }
+  double Count() const { return gpr_histogram_count(impl_); }
   void Swap(Histogram* other) { std::swap(impl_, other->impl_); }
   void FillProto(HistogramData* p) {
     size_t n;
diff --git a/test/cpp/qps/qps-sweep.sh b/test/cpp/qps/qps-sweep.sh
new file mode 100755
index 0000000..7bc6ead
--- /dev/null
+++ b/test/cpp/qps/qps-sweep.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+if [ x"$QPS_WORKERS" == x ]; then
+  echo Error: Must set QPS_WORKERS variable in form \
+    "host:port,host:port,..." 1>&2
+  exit 1
+fi
+
+bins=`find . .. ../.. ../../.. -name bins | head -1`
+
+for channels in 1 2 4 8
+do
+  for client in SYNCHRONOUS_CLIENT ASYNC_CLIENT
+  do
+    for server in SYNCHRONOUS_SERVER ASYNC_SERVER
+    do
+      for rpc in UNARY STREAMING
+      do
+        echo "Test $rpc $client $server , $channels channels"
+        "$bins"/opt/qps_driver --rpc_type=$rpc \
+          --client_type=$client --server_type=$server
+      done
+    done
+  done
+done
diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc
index 5e9a577..220f826 100644
--- a/test/cpp/qps/qps_driver.cc
+++ b/test/cpp/qps/qps_driver.cc
@@ -35,13 +35,17 @@
 #include <grpc/support/log.h>
 
 #include "test/cpp/qps/driver.h"
-#include "test/cpp/qps/stats.h"
+#include "test/cpp/qps/report.h"
 
 DEFINE_int32(num_clients, 1, "Number of client binaries");
 DEFINE_int32(num_servers, 1, "Number of server binaries");
 
+DEFINE_int32(warmup_seconds, 5, "Warmup time (in seconds)");
+DEFINE_int32(benchmark_seconds, 30, "Benchmark time (in seconds)");
+
 // Common config
 DEFINE_bool(enable_ssl, false, "Use SSL");
+DEFINE_string(rpc_type, "UNARY", "Type of RPC: UNARY or STREAMING");
 
 // Server config
 DEFINE_int32(server_threads, 1, "Number of server threads");
@@ -59,8 +63,8 @@
 using grpc::testing::ServerConfig;
 using grpc::testing::ClientType;
 using grpc::testing::ServerType;
+using grpc::testing::RpcType;
 using grpc::testing::ResourceUsage;
-using grpc::testing::sum;
 
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
@@ -73,6 +77,9 @@
   grpc_init();
   ParseCommandLineFlags(&argc, &argv, true);
 
+  RpcType rpc_type;
+  GPR_ASSERT(RpcType_Parse(FLAGS_rpc_type, &rpc_type));
+
   ClientType client_type;
   ServerType server_type;
   GPR_ASSERT(ClientType_Parse(FLAGS_client_type, &client_type));
@@ -86,46 +93,20 @@
   client_config.set_client_channels(FLAGS_client_channels);
   client_config.set_payload_size(FLAGS_payload_size);
   client_config.set_async_client_threads(FLAGS_async_client_threads);
+  client_config.set_rpc_type(rpc_type);
 
   ServerConfig server_config;
   server_config.set_server_type(server_type);
   server_config.set_threads(FLAGS_server_threads);
   server_config.set_enable_ssl(FLAGS_enable_ssl);
 
-  auto result = RunScenario(client_config, FLAGS_num_clients, server_config,
-                            FLAGS_num_servers);
+  auto result = RunScenario(client_config, FLAGS_num_clients,
+                            server_config, FLAGS_num_servers,
+                            FLAGS_warmup_seconds, FLAGS_benchmark_seconds);
 
-  gpr_log(GPR_INFO, "QPS: %.1f",
-          result.latencies.Count() /
-              average(result.client_resources,
-                      [](ResourceUsage u) { return u.wall_time; }));
-
-  gpr_log(GPR_INFO, "Latencies (50/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f us",
-          result.latencies.Percentile(50) / 1000,
-          result.latencies.Percentile(95) / 1000,
-          result.latencies.Percentile(99) / 1000,
-          result.latencies.Percentile(99.9) / 1000);
-
-  gpr_log(GPR_INFO, "Server system time: %.2f%%",
-          100.0 * sum(result.server_resources,
-                      [](ResourceUsage u) { return u.system_time; }) /
-              sum(result.server_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
-  gpr_log(GPR_INFO, "Server user time:   %.2f%%",
-          100.0 * sum(result.server_resources,
-                      [](ResourceUsage u) { return u.user_time; }) /
-              sum(result.server_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
-  gpr_log(GPR_INFO, "Client system time: %.2f%%",
-          100.0 * sum(result.client_resources,
-                      [](ResourceUsage u) { return u.system_time; }) /
-              sum(result.client_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
-  gpr_log(GPR_INFO, "Client user time:   %.2f%%",
-          100.0 * sum(result.client_resources,
-                      [](ResourceUsage u) { return u.user_time; }) /
-              sum(result.client_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
+  ReportQPSPerCore(result, server_config);
+  ReportLatency(result);
+  ReportTimes(result);
 
   grpc_shutdown();
   return 0;
diff --git a/test/cpp/qps/qpstest.proto b/test/cpp/qps/qpstest.proto
index 6a7170b..1553ef5 100644
--- a/test/cpp/qps/qpstest.proto
+++ b/test/cpp/qps/qpstest.proto
@@ -87,15 +87,21 @@
   ASYNC_SERVER = 2;
 }
 
+enum RpcType {
+  UNARY = 1;
+  STREAMING = 2;
+}
+
 message ClientConfig {
   repeated string server_targets = 1;
   required ClientType client_type = 2;
-  required bool enable_ssl = 3;
+  optional bool enable_ssl = 3 [default=false];
   required int32 outstanding_rpcs_per_channel = 4;
   required int32 client_channels = 5;
   required int32 payload_size = 6;
   // only for async client:
   optional int32 async_client_threads = 7;
+  optional RpcType rpc_type = 8 [default=UNARY];
 }
 
 // Request current stats
@@ -121,8 +127,8 @@
 
 message ServerConfig {
   required ServerType server_type = 1;
-  required int32 threads = 2;
-  required bool enable_ssl = 3;
+  optional int32 threads = 2 [default=1];
+  optional bool enable_ssl = 3 [default=false];
 }
 
 message ServerArgs {
@@ -144,7 +150,7 @@
 
   // Desired payload size in the response from the server.
   // If response_type is COMPRESSABLE, this denotes the size before compression.
-  optional int32 response_size = 2;
+  optional int32 response_size = 2 [default=0];
 
   // Optional input payload sent along with the request.
   optional Payload payload = 3;
@@ -154,72 +160,14 @@
   optional Payload payload = 1;
 }
 
-message StreamingInputCallRequest {
-  // Optional input payload sent along with the request.
-  optional Payload payload = 1;
-
-  // Not expecting any payload from the response.
-}
-
-message StreamingInputCallResponse {
-  // Aggregated size of payloads received from the client.
-  optional int32 aggregated_payload_size = 1;
-}
-
-message ResponseParameters {
-  // Desired payload sizes in responses from the server.
-  // If response_type is COMPRESSABLE, this denotes the size before compression.
-  required int32 size = 1;
-
-  // Desired interval between consecutive responses in the response stream in
-  // microseconds.
-  required int32 interval_us = 2;
-}
-
-message StreamingOutputCallRequest {
-  // Desired payload type in the response from the server.
-  // If response_type is RANDOM, the payload from each response in the stream
-  // might be of different types. This is to simulate a mixed type of payload
-  // stream.
-  optional PayloadType response_type = 1 [default=COMPRESSABLE];
-
-  repeated ResponseParameters response_parameters = 2;
-
-  // Optional input payload sent along with the request.
-  optional Payload payload = 3;
-}
-
-message StreamingOutputCallResponse {
-  optional Payload payload = 1;
-}
-
 service TestService {
   // One request followed by one response.
   // The server returns the client payload as-is.
   rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
 
-  // One request followed by a sequence of responses (streamed download).
-  // The server returns the payload with client desired type and sizes.
-  rpc StreamingOutputCall(StreamingOutputCallRequest)
-      returns (stream StreamingOutputCallResponse);
-
-  // A sequence of requests followed by one response (streamed upload).
-  // The server returns the aggregated size of client payload as the result.
-  rpc StreamingInputCall(stream StreamingInputCallRequest)
-      returns (StreamingInputCallResponse);
-
-  // A sequence of requests with each request served by the server immediately.
-  // As one request could lead to multiple responses, this interface
-  // demonstrates the idea of full duplexing.
-  rpc FullDuplexCall(stream StreamingOutputCallRequest)
-      returns (stream StreamingOutputCallResponse);
-
-  // A sequence of requests followed by a sequence of responses.
-  // The server buffers all the client requests and then serves them in order. A
-  // stream of responses are returned to the client when the server starts with
-  // first request.
-  rpc HalfDuplexCall(stream StreamingOutputCallRequest)
-      returns (stream StreamingOutputCallResponse);
+  // One request followed by one response.
+  // The server returns the client payload as-is.
+  rpc StreamingCall(stream SimpleRequest) returns (stream SimpleResponse);
 }
 
 service Worker {
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
new file mode 100644
index 0000000..29d88da
--- /dev/null
+++ b/test/cpp/qps/report.cc
@@ -0,0 +1,94 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "test/cpp/qps/report.h"
+
+#include <grpc/support/log.h>
+#include "test/cpp/qps/stats.h"
+
+namespace grpc {
+namespace testing {
+
+// QPS: XXX
+void ReportQPS(const ScenarioResult& result) {
+  gpr_log(GPR_INFO, "QPS: %.1f",
+          result.latencies.Count() /
+              average(result.client_resources,
+                      [](ResourceUsage u) { return u.wall_time; }));
+}
+
+// QPS: XXX (YYY/server core)
+void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& server_config) {
+  auto qps = 
+      result.latencies.Count() /
+      average(result.client_resources,
+          [](ResourceUsage u) { return u.wall_time; });
+
+  gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps, qps/server_config.threads());
+}
+
+// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us
+void ReportLatency(const ScenarioResult& result) {
+  gpr_log(GPR_INFO, "Latencies (50/90/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f/%.1f us",
+          result.latencies.Percentile(50) / 1000,
+          result.latencies.Percentile(90) / 1000,
+          result.latencies.Percentile(95) / 1000,
+          result.latencies.Percentile(99) / 1000,
+          result.latencies.Percentile(99.9) / 1000);
+}
+
+void ReportTimes(const ScenarioResult& result) {
+  gpr_log(GPR_INFO, "Server system time: %.2f%%",
+          100.0 * sum(result.server_resources,
+                      [](ResourceUsage u) { return u.system_time; }) /
+              sum(result.server_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+  gpr_log(GPR_INFO, "Server user time:   %.2f%%",
+          100.0 * sum(result.server_resources,
+                      [](ResourceUsage u) { return u.user_time; }) /
+              sum(result.server_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+  gpr_log(GPR_INFO, "Client system time: %.2f%%",
+          100.0 * sum(result.client_resources,
+                      [](ResourceUsage u) { return u.system_time; }) /
+              sum(result.client_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+  gpr_log(GPR_INFO, "Client user time:   %.2f%%",
+          100.0 * sum(result.client_resources,
+                      [](ResourceUsage u) { return u.user_time; }) /
+              sum(result.client_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/php/ext/grpc/event.h b/test/cpp/qps/report.h
old mode 100755
new mode 100644
similarity index 72%
copy from src/php/ext/grpc/event.h
copy to test/cpp/qps/report.h
index ef5846a..343e426
--- a/src/php/ext/grpc/event.h
+++ b/test/cpp/qps/report.h
@@ -31,21 +31,27 @@
  *
  */
 
-#ifndef NET_GRPC_PHP_GRPC_EVENT_H_
-#define NET_GRPC_PHP_GRPC_EVENT_H_
+#ifndef TEST_QPS_REPORT_H
+#define TEST_QPS_REPORT_H
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include "test/cpp/qps/driver.h"
+
+namespace grpc {
+namespace testing {
+
+// QPS: XXX
+void ReportQPS(const ScenarioResult& result);
+// QPS: XXX (YYY/server core)
+void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& config);
+// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us
+void ReportLatency(const ScenarioResult& result);
+// Server system time: XX%
+// Server user time: XX%
+// Client system time: XX%
+// Client user time: XX%
+void ReportTimes(const ScenarioResult& result);
+
+}  // namespace testing
+}  // namespace grpc
+
 #endif
-
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "php_grpc.h"
-
-#include "grpc/grpc.h"
-
-/* Create a new Event object that wraps an existing grpc_event struct */
-zval *grpc_php_convert_event(grpc_event *event);
-
-#endif /* NET_GRPC_PHP_GRPC_COMPLETION_CHANNEL_H */
diff --git a/test/cpp/qps/server.cc b/test/cpp/qps/server.cc
deleted file mode 100644
index e1907b0..0000000
--- a/test/cpp/qps/server.cc
+++ /dev/null
@@ -1,172 +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.
- *
- */
-
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/signal.h>
-#include <thread>
-
-#include <unistd.h>
-
-#include <gflags/gflags.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc++/config.h>
-#include <grpc++/server.h>
-#include <grpc++/server_builder.h>
-#include <grpc++/server_context.h>
-#include <grpc++/server_credentials.h>
-#include <grpc++/status.h>
-#include "src/cpp/server/thread_pool.h"
-#include "test/core/util/grpc_profiler.h"
-#include "test/cpp/qps/qpstest.pb.h"
-
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-
-DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
-DEFINE_int32(port, 0, "Server port.");
-DEFINE_int32(server_threads, 4, "Number of server threads.");
-
-using grpc::Server;
-using grpc::ServerBuilder;
-using grpc::ServerContext;
-using grpc::ThreadPool;
-using grpc::testing::Payload;
-using grpc::testing::PayloadType;
-using grpc::testing::ServerStats;
-using grpc::testing::SimpleRequest;
-using grpc::testing::SimpleResponse;
-using grpc::testing::StatsRequest;
-using grpc::testing::TestService;
-using grpc::Status;
-
-// In some distros, gflags is in the namespace google, and in some others,
-// in gflags. This hack is enabling us to find both.
-namespace google {}
-namespace gflags {}
-using namespace google;
-using namespace gflags;
-
-static bool got_sigint = false;
-
-static void sigint_handler(int x) { got_sigint = 1; }
-
-static double time_double(struct timeval* tv) {
-  return tv->tv_sec + 1e-6 * tv->tv_usec;
-}
-
-static bool SetPayload(PayloadType type, int size, Payload* payload) {
-  PayloadType response_type = type;
-  // TODO(yangg): Support UNCOMPRESSABLE payload.
-  if (type != PayloadType::COMPRESSABLE) {
-    return false;
-  }
-  payload->set_type(response_type);
-  std::unique_ptr<char[]> body(new char[size]());
-  payload->set_body(body.get(), size);
-  return true;
-}
-
-namespace {
-
-class TestServiceImpl GRPC_FINAL : public TestService::Service {
- public:
-  Status CollectServerStats(ServerContext* context, const StatsRequest*,
-                            ServerStats* response) {
-    struct rusage usage;
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    getrusage(RUSAGE_SELF, &usage);
-    response->set_time_now(time_double(&tv));
-    response->set_time_user(time_double(&usage.ru_utime));
-    response->set_time_system(time_double(&usage.ru_stime));
-    return Status::OK;
-  }
-  Status UnaryCall(ServerContext* context, const SimpleRequest* request,
-                   SimpleResponse* response) {
-    if (request->has_response_size() && request->response_size() > 0) {
-      if (!SetPayload(request->response_type(), request->response_size(),
-                      response->mutable_payload())) {
-        return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
-      }
-    }
-    return Status::OK;
-  }
-};
-
-}  // namespace
-
-static void RunServer() {
-  char* server_address = NULL;
-  gpr_join_host_port(&server_address, "::", FLAGS_port);
-
-  TestServiceImpl service;
-
-  SimpleRequest request;
-  SimpleResponse response;
-
-  ServerBuilder builder;
-  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
-  builder.RegisterService(&service);
-
-  std::unique_ptr<ThreadPool> pool(new ThreadPool(FLAGS_server_threads));
-  builder.SetThreadPool(pool.get());
-
-  std::unique_ptr<Server> server(builder.BuildAndStart());
-  gpr_log(GPR_INFO, "Server listening on %s\n", server_address);
-
-  grpc_profiler_start("qps_server.prof");
-
-  while (!got_sigint) {
-    sleep(5);
-  }
-
-  grpc_profiler_stop();
-
-  gpr_free(server_address);
-}
-
-int main(int argc, char** argv) {
-  grpc_init();
-  ParseCommandLineFlags(&argc, &argv, true);
-
-  signal(SIGINT, sigint_handler);
-
-  GPR_ASSERT(FLAGS_port != 0);
-  GPR_ASSERT(!FLAGS_enable_ssl);
-  RunServer();
-
-  grpc_shutdown();
-  return 0;
-}
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index ef71cb9..68e0115 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -35,7 +35,7 @@
 #define TEST_QPS_SERVER_H
 
 #include "test/cpp/qps/timer.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 586b6e7..b19c443 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -33,6 +33,7 @@
 
 #include <forward_list>
 #include <functional>
+#include <mutex>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/signal.h>
@@ -48,10 +49,10 @@
 #include <grpc++/server_context.h>
 #include <grpc++/server_credentials.h>
 #include <grpc++/status.h>
+#include <grpc++/stream.h>
 #include <gtest/gtest.h>
 #include "src/cpp/server/thread_pool.h"
-#include "test/core/util/grpc_profiler.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 #include "test/cpp/qps/server.h"
 
 #include <grpc/grpc.h>
@@ -63,7 +64,8 @@
 class AsyncQpsServerTest : public Server {
  public:
   AsyncQpsServerTest(const ServerConfig& config, int port)
-      : srv_cq_(), async_service_(&srv_cq_), server_(nullptr) {
+      : srv_cq_(), async_service_(&srv_cq_), server_(nullptr),
+        shutdown_(false) {
     char* server_address = NULL;
     gpr_join_host_port(&server_address, "::", port);
 
@@ -78,10 +80,16 @@
     using namespace std::placeholders;
     request_unary_ = std::bind(&TestService::AsyncService::RequestUnaryCall,
                                &async_service_, _1, _2, _3, &srv_cq_, _4);
+    request_streaming_ =
+      std::bind(&TestService::AsyncService::RequestStreamingCall,
+		&async_service_, _1, _2, &srv_cq_, _3);
     for (int i = 0; i < 100; i++) {
       contexts_.push_front(
           new ServerRpcContextUnaryImpl<SimpleRequest, SimpleResponse>(
-              request_unary_, UnaryCall));
+              request_unary_, ProcessRPC));
+      contexts_.push_front(
+          new ServerRpcContextStreamingImpl<SimpleRequest, SimpleResponse>(
+              request_streaming_, ProcessRPC));
     }
     for (int i = 0; i < config.threads(); i++) {
       threads_.push_back(std::thread([=]() {
@@ -89,11 +97,12 @@
         bool ok;
         void* got_tag;
         while (srv_cq_.Next(&got_tag, &ok)) {
-          if (ok) {
-            ServerRpcContext* ctx = detag(got_tag);
-            // The tag is a pointer to an RPC context to invoke
-            if (ctx->RunNextState() == false) {
-              // this RPC context is done, so refresh it
+          ServerRpcContext* ctx = detag(got_tag);
+          // The tag is a pointer to an RPC context to invoke
+          if (ctx->RunNextState(ok) == false) {
+            // this RPC context is done, so refresh it
+            std::lock_guard<std::mutex> g(shutdown_mutex_);
+            if (!shutdown_) {
               ctx->Reset();
             }
           }
@@ -104,9 +113,13 @@
   }
   ~AsyncQpsServerTest() {
     server_->Shutdown();
-    srv_cq_.Shutdown();
-    for (auto& thr : threads_) {
-      thr.join();
+    {
+      std::lock_guard<std::mutex> g(shutdown_mutex_);
+      shutdown_ = true;
+      srv_cq_.Shutdown();
+    }
+    for (auto thr = threads_.begin(); thr != threads_.end(); thr++) {
+      thr->join();
     }
     while (!contexts_.empty()) {
       delete contexts_.front();
@@ -119,7 +132,7 @@
    public:
     ServerRpcContext() {}
     virtual ~ServerRpcContext(){};
-    virtual bool RunNextState() = 0;  // do next state, return false if all done
+    virtual bool RunNextState(bool) = 0;  // next state, return false if done
     virtual void Reset() = 0;         // start this back at a clean state
   };
   static void* tag(ServerRpcContext* func) {
@@ -130,7 +143,7 @@
   }
 
   template <class RequestType, class ResponseType>
-  class ServerRpcContextUnaryImpl : public ServerRpcContext {
+  class ServerRpcContextUnaryImpl GRPC_FINAL : public ServerRpcContext {
    public:
     ServerRpcContextUnaryImpl(
         std::function<void(ServerContext*, RequestType*,
@@ -146,7 +159,7 @@
                       AsyncQpsServerTest::tag(this));
     }
     ~ServerRpcContextUnaryImpl() GRPC_OVERRIDE {}
-    bool RunNextState() GRPC_OVERRIDE { return (this->*next_state_)(); }
+    bool RunNextState(bool ok) GRPC_OVERRIDE {return (this->*next_state_)(ok);}
     void Reset() GRPC_OVERRIDE {
       srv_ctx_ = ServerContext();
       req_ = RequestType();
@@ -160,8 +173,12 @@
     }
 
    private:
-    bool finisher() { return false; }
-    bool invoker() {
+    bool finisher(bool) { return false; }
+    bool invoker(bool ok) {
+      if (!ok) {
+        return false;
+      }
+
       ResponseType response;
 
       // Call the RPC processing function
@@ -174,7 +191,7 @@
     }
     ServerContext srv_ctx_;
     RequestType req_;
-    bool (ServerRpcContextUnaryImpl::*next_state_)();
+    bool (ServerRpcContextUnaryImpl::*next_state_)(bool);
     std::function<void(ServerContext*, RequestType*,
                        grpc::ServerAsyncResponseWriter<ResponseType>*, void*)>
         request_method_;
@@ -183,9 +200,89 @@
     grpc::ServerAsyncResponseWriter<ResponseType> response_writer_;
   };
 
-  static Status UnaryCall(const SimpleRequest* request,
-                          SimpleResponse* response) {
-    if (request->has_response_size() && request->response_size() > 0) {
+  template <class RequestType, class ResponseType>
+  class ServerRpcContextStreamingImpl GRPC_FINAL : public ServerRpcContext {
+   public:
+    ServerRpcContextStreamingImpl(
+        std::function<void(ServerContext *,
+                           grpc::ServerAsyncReaderWriter<ResponseType,
+			   RequestType> *, void *)> request_method,
+        std::function<grpc::Status(const RequestType *, ResponseType *)>
+            invoke_method)
+        : next_state_(&ServerRpcContextStreamingImpl::request_done),
+          request_method_(request_method),
+          invoke_method_(invoke_method),
+          stream_(&srv_ctx_) {
+      request_method_(&srv_ctx_, &stream_, AsyncQpsServerTest::tag(this));
+    }
+    ~ServerRpcContextStreamingImpl() GRPC_OVERRIDE {
+    }
+    bool RunNextState(bool ok) GRPC_OVERRIDE {return (this->*next_state_)(ok);}
+    void Reset() GRPC_OVERRIDE {
+      srv_ctx_ = ServerContext();
+      req_ = RequestType();
+      stream_ = grpc::ServerAsyncReaderWriter<ResponseType,
+					      RequestType>(&srv_ctx_);
+
+      // Then request the method
+      next_state_ = &ServerRpcContextStreamingImpl::request_done;
+      request_method_(&srv_ctx_, &stream_, AsyncQpsServerTest::tag(this));
+    }
+
+   private:
+    bool request_done(bool ok) {
+      if (!ok) {
+        return false;
+      }
+      stream_.Read(&req_, AsyncQpsServerTest::tag(this));
+      next_state_ = &ServerRpcContextStreamingImpl::read_done;
+      return true;
+    }
+
+    bool read_done(bool ok) {
+      if (ok) {
+	// invoke the method
+	ResponseType response;
+	// Call the RPC processing function
+	grpc::Status status = invoke_method_(&req_, &response);
+	// initiate the write
+	stream_.Write(response, AsyncQpsServerTest::tag(this));
+	next_state_ = &ServerRpcContextStreamingImpl::write_done;
+      } else {	// client has sent writes done
+	// finish the stream
+	stream_.Finish(Status::OK, AsyncQpsServerTest::tag(this));
+	next_state_ = &ServerRpcContextStreamingImpl::finish_done;
+      }
+      return true;
+    }
+    bool write_done(bool ok) {
+      // now go back and get another streaming read!
+      if (ok) {
+	stream_.Read(&req_, AsyncQpsServerTest::tag(this));
+	next_state_ = &ServerRpcContextStreamingImpl::read_done;
+      }
+      else {
+	stream_.Finish(Status::OK, AsyncQpsServerTest::tag(this));
+	next_state_ = &ServerRpcContextStreamingImpl::finish_done;
+      }
+      return true;
+    }
+    bool finish_done(bool ok) {return false; /* reset the context */ }
+
+    ServerContext srv_ctx_;
+    RequestType req_;
+    bool (ServerRpcContextStreamingImpl::*next_state_)(bool);
+    std::function<void(ServerContext *,
+		       grpc::ServerAsyncReaderWriter<ResponseType,
+		       RequestType> *, void *)> request_method_;
+    std::function<grpc::Status(const RequestType *, ResponseType *)>
+        invoke_method_;
+    grpc::ServerAsyncReaderWriter<ResponseType,RequestType> stream_;
+  };
+
+  static Status ProcessRPC(const SimpleRequest* request,
+			   SimpleResponse* response) {
+    if (request->response_size() > 0) {
       if (!SetPayload(request->response_type(), request->response_size(),
                       response->mutable_payload())) {
         return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
@@ -200,7 +297,13 @@
   std::function<void(ServerContext*, SimpleRequest*,
                      grpc::ServerAsyncResponseWriter<SimpleResponse>*, void*)>
       request_unary_;
+  std::function<void(ServerContext*, grpc::ServerAsyncReaderWriter<
+		     SimpleResponse,SimpleRequest>*, void*)>
+      request_streaming_;
   std::forward_list<ServerRpcContext*> contexts_;
+
+  std::mutex shutdown_mutex_;
+  bool shutdown_;
 };
 
 std::unique_ptr<Server> CreateAsyncServer(const ServerConfig& config,
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index 3e15fb6..2770233 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -47,8 +47,7 @@
 #include <grpc++/status.h>
 #include <grpc++/stream.h>
 #include "src/cpp/server/thread_pool.h"
-#include "test/core/util/grpc_profiler.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 #include "test/cpp/qps/server.h"
 #include "test/cpp/qps/timer.h"
 
@@ -62,7 +61,7 @@
  public:
   Status UnaryCall(ServerContext* context, const SimpleRequest* request,
                    SimpleResponse* response) GRPC_OVERRIDE {
-    if (request->has_response_size() && request->response_size() > 0) {
+    if (request->response_size() > 0) {
       if (!Server::SetPayload(request->response_type(),
                               request->response_size(),
                               response->mutable_payload())) {
@@ -71,6 +70,23 @@
     }
     return Status::OK;
   }
+  Status StreamingCall(ServerContext *context,
+		       ServerReaderWriter<SimpleResponse, SimpleRequest>*
+		       stream) GRPC_OVERRIDE {
+    SimpleRequest request;
+    while (stream->Read(&request)) {
+      SimpleResponse response;
+      if (request.response_size() > 0) {
+	if (!Server::SetPayload(request.response_type(),
+				request.response_size(),
+				response.mutable_payload())) {
+	  return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
+	}
+      }
+      stream->Write(response);
+    }
+    return Status::OK;
+  }
 };
 
 class SynchronousServer GRPC_FINAL : public grpc::testing::Server {
diff --git a/test/cpp/qps/smoke_test.cc b/test/cpp/qps/smoke_test.cc
new file mode 100644
index 0000000..c9d321f
--- /dev/null
+++ b/test/cpp/qps/smoke_test.cc
@@ -0,0 +1,149 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <grpc/support/log.h>
+
+#include "test/cpp/qps/driver.h"
+#include "test/cpp/qps/report.h"
+
+namespace grpc {
+namespace testing {
+
+static const int WARMUP = 5;
+static const int BENCHMARK = 10;
+
+static void RunSynchronousUnaryPingPong() {
+  gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong");
+
+  ClientConfig client_config;
+  client_config.set_client_type(SYNCHRONOUS_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1);
+  client_config.set_client_channels(1);
+  client_config.set_payload_size(1);
+  client_config.set_rpc_type(UNARY);
+
+  ServerConfig server_config;
+  server_config.set_server_type(SYNCHRONOUS_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(1);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPS(result);
+  ReportLatency(result);
+}
+
+static void RunSynchronousStreamingPingPong() {
+  gpr_log(GPR_INFO, "Running Synchronous Streaming Ping Pong");
+
+  ClientConfig client_config;
+  client_config.set_client_type(SYNCHRONOUS_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1);
+  client_config.set_client_channels(1);
+  client_config.set_payload_size(1);
+  client_config.set_rpc_type(STREAMING);
+
+  ServerConfig server_config;
+  server_config.set_server_type(SYNCHRONOUS_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(1);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPS(result);
+  ReportLatency(result);
+}
+
+static void RunAsyncUnaryPingPong() {
+  gpr_log(GPR_INFO, "Running Async Unary Ping Pong");
+
+  ClientConfig client_config;
+  client_config.set_client_type(ASYNC_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1);
+  client_config.set_client_channels(1);
+  client_config.set_payload_size(1);
+  client_config.set_async_client_threads(1);
+  client_config.set_rpc_type(UNARY);
+
+  ServerConfig server_config;
+  server_config.set_server_type(ASYNC_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(1);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPS(result);
+  ReportLatency(result);
+}
+
+static void RunQPS() {
+  gpr_log(GPR_INFO, "Running QPS test");
+
+  ClientConfig client_config;
+  client_config.set_client_type(ASYNC_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1000);
+  client_config.set_client_channels(8);
+  client_config.set_payload_size(1);
+  client_config.set_async_client_threads(8);
+  client_config.set_rpc_type(UNARY);
+
+  ServerConfig server_config;
+  server_config.set_server_type(ASYNC_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(4);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPSPerCore(result, server_config);
+  ReportLatency(result);
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_init();
+
+  using namespace grpc::testing;
+  RunSynchronousStreamingPingPong();
+  RunSynchronousUnaryPingPong();
+  RunAsyncUnaryPingPong();
+  RunQPS();
+
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/cpp/qps/smoke_test.sh b/test/cpp/qps/smoke_test.sh
new file mode 100755
index 0000000..ba7f0a4
--- /dev/null
+++ b/test/cpp/qps/smoke_test.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# performs a single qps run with one client and one server
+
+set -ex
+
+cd $(dirname $0)/../../..
+
+killall qps_worker || true
+
+config=opt
+
+NUMCPUS=`python2.7 -c 'import multiprocessing; print multiprocessing.cpu_count()'`
+
+make CONFIG=$config qps_worker qps_smoke_test -j$NUMCPUS
+
+bins/$config/qps_worker -driver_port 10000 -server_port 10001 &
+PID1=$!
+bins/$config/qps_worker -driver_port 10010 -server_port 10011 &
+PID2=$!
+
+export QPS_WORKERS="localhost:10000,localhost:10010"
+
+bins/$config/qps_smoke_test $*
+
+kill -2 $PID1 $PID2
+wait
+
diff --git a/test/cpp/qps/stats.h b/test/cpp/qps/stats.h
index ca59390..82dc03e 100644
--- a/test/cpp/qps/stats.h
+++ b/test/cpp/qps/stats.h
@@ -43,8 +43,8 @@
 template <class T, class F>
 double sum(const T& container, F functor) {
   double r = 0;
-  for (auto v : container) {
-    r += functor(v);
+  for (auto v = container.begin(); v != container.end(); v++) {
+    r += functor(*v);
   }
   return r;
 }
diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc
index 3c13420..d1b6bc1 100644
--- a/test/cpp/qps/timer.cc
+++ b/test/cpp/qps/timer.cc
@@ -36,6 +36,7 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <grpc/support/time.h>
+#include <grpc++/config.h>
 
 Timer::Timer() : start_(Sample()) {}
 
diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc
index fdcd9d5..101eb9f 100644
--- a/test/cpp/qps/worker.cc
+++ b/test/cpp/qps/worker.cc
@@ -55,7 +55,7 @@
 #include <grpc++/stream.h>
 #include "test/core/util/grpc_profiler.h"
 #include "test/cpp/util/create_test_channel.h"
-#include "test/cpp/qps/qpstest.pb.h"
+#include "test/cpp/qps/qpstest.grpc.pb.h"
 #include "test/cpp/qps/client.h"
 #include "test/cpp/qps/server.h"
 
@@ -71,15 +71,20 @@
 
 static bool got_sigint = false;
 
+static void sigint_handler(int x) {got_sigint = true;}
+
 namespace grpc {
 namespace testing {
 
 std::unique_ptr<Client> CreateClient(const ClientConfig& config) {
   switch (config.client_type()) {
     case ClientType::SYNCHRONOUS_CLIENT:
-      return CreateSynchronousClient(config);
+      return (config.rpc_type() == RpcType::UNARY) ?
+	CreateSynchronousUnaryClient(config) :
+	CreateSynchronousStreamingClient(config);
     case ClientType::ASYNC_CLIENT:
-      return CreateAsyncClient(config);
+      return (config.rpc_type() == RpcType::UNARY) ?
+	CreateAsyncUnaryClient(config) : CreateAsyncStreamingClient(config);
   }
   abort();
 }
@@ -106,30 +111,10 @@
       return Status(RESOURCE_EXHAUSTED);
     }
 
-    ClientArgs args;
-    if (!stream->Read(&args)) {
-      return Status(INVALID_ARGUMENT);
-    }
-    if (!args.has_setup()) {
-      return Status(INVALID_ARGUMENT);
-    }
-    auto client = CreateClient(args.setup());
-    if (!client) {
-      return Status(INVALID_ARGUMENT);
-    }
-    ClientStatus status;
-    if (!stream->Write(status)) {
-      return Status(UNKNOWN);
-    }
-    while (stream->Read(&args)) {
-      if (!args.has_mark()) {
-        return Status(INVALID_ARGUMENT);
-      }
-      *status.mutable_stats() = client->Mark();
-      stream->Write(status);
-    }
-
-    return Status::OK;
+    grpc_profiler_start("qps_client.prof");
+    Status ret = RunTestBody(ctx,stream);
+    grpc_profiler_stop();
+    return ret;
   }
 
   Status RunServer(ServerContext* ctx,
@@ -140,31 +125,10 @@
       return Status(RESOURCE_EXHAUSTED);
     }
 
-    ServerArgs args;
-    if (!stream->Read(&args)) {
-      return Status(INVALID_ARGUMENT);
-    }
-    if (!args.has_setup()) {
-      return Status(INVALID_ARGUMENT);
-    }
-    auto server = CreateServer(args.setup());
-    if (!server) {
-      return Status(INVALID_ARGUMENT);
-    }
-    ServerStatus status;
-    status.set_port(FLAGS_server_port);
-    if (!stream->Write(status)) {
-      return Status(UNKNOWN);
-    }
-    while (stream->Read(&args)) {
-      if (!args.has_mark()) {
-        return Status(INVALID_ARGUMENT);
-      }
-      *status.mutable_stats() = server->Mark();
-      stream->Write(status);
-    }
-
-    return Status::OK;
+    grpc_profiler_start("qps_server.prof");
+    Status ret = RunServerBody(ctx,stream);
+    grpc_profiler_stop();
+    return ret;
   }
 
  private:
@@ -199,6 +163,63 @@
     acquired_ = false;
   }
 
+  Status RunTestBody(ServerContext* ctx,
+                     ServerReaderWriter<ClientStatus, ClientArgs>* stream) {
+    ClientArgs args;
+    if (!stream->Read(&args)) {
+      return Status(INVALID_ARGUMENT);
+    }
+    if (!args.has_setup()) {
+      return Status(INVALID_ARGUMENT);
+    }
+    auto client = CreateClient(args.setup());
+    if (!client) {
+      return Status(INVALID_ARGUMENT);
+    }
+    ClientStatus status;
+    if (!stream->Write(status)) {
+      return Status(UNKNOWN);
+    }
+    while (stream->Read(&args)) {
+      if (!args.has_mark()) {
+        return Status(INVALID_ARGUMENT);
+      }
+      *status.mutable_stats() = client->Mark();
+      stream->Write(status);
+    }
+
+    return Status::OK;
+  }
+
+  Status RunServerBody(ServerContext* ctx,
+                       ServerReaderWriter<ServerStatus, ServerArgs>* stream) {
+    ServerArgs args;
+    if (!stream->Read(&args)) {
+      return Status(INVALID_ARGUMENT);
+    }
+    if (!args.has_setup()) {
+      return Status(INVALID_ARGUMENT);
+    }
+    auto server = CreateServer(args.setup());
+    if (!server) {
+      return Status(INVALID_ARGUMENT);
+    }
+    ServerStatus status;
+    status.set_port(FLAGS_server_port);
+    if (!stream->Write(status)) {
+      return Status(UNKNOWN);
+    }
+    while (stream->Read(&args)) {
+      if (!args.has_mark()) {
+        return Status(INVALID_ARGUMENT);
+      }
+      *status.mutable_stats() = server->Mark();
+      stream->Write(status);
+    }
+
+    return Status::OK;
+  }
+
   std::mutex mu_;
   bool acquired_;
 };
@@ -229,6 +250,8 @@
   grpc_init();
   ParseCommandLineFlags(&argc, &argv, true);
 
+  signal(SIGINT, sigint_handler);
+
   grpc::testing::RunServer();
 
   grpc_shutdown();
diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc
new file mode 100644
index 0000000..eb67b8d
--- /dev/null
+++ b/test/cpp/util/cli_call.cc
@@ -0,0 +1,106 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "test/cpp/util/cli_call.h"
+
+#include <iostream>
+
+#include <grpc++/byte_buffer.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/generic_stub.h>
+#include <grpc++/status.h>
+#include <grpc++/stream.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+
+namespace grpc {
+namespace testing {
+namespace {
+void* tag(int i) { return (void*)(gpr_intptr) i; }
+}  // namespace
+
+void CliCall::Call(std::shared_ptr<grpc::ChannelInterface> channel,
+                   const grpc::string& method, const grpc::string& request,
+                   grpc::string* response) {
+  std::unique_ptr<grpc::GenericStub> stub(new grpc::GenericStub(channel));
+  grpc::ClientContext ctx;
+  grpc::CompletionQueue cq;
+  std::unique_ptr<grpc::GenericClientAsyncReaderWriter> call(
+      stub->Call(&ctx, method, &cq, tag(1)));
+  void* got_tag;
+  bool ok;
+  cq.Next(&got_tag, &ok);
+  GPR_ASSERT(ok);
+
+  gpr_slice s = gpr_slice_from_copied_string(request.c_str());
+  grpc::Slice req_slice(s, grpc::Slice::STEAL_REF);
+  grpc::ByteBuffer send_buffer(&req_slice, 1);
+  call->Write(send_buffer, tag(2));
+  cq.Next(&got_tag, &ok);
+  GPR_ASSERT(ok);
+  call->WritesDone(tag(3));
+  cq.Next(&got_tag, &ok);
+  GPR_ASSERT(ok);
+  grpc::ByteBuffer recv_buffer;
+  call->Read(&recv_buffer, tag(4));
+  cq.Next(&got_tag, &ok);
+  if (!ok) {
+    std::cout << "Failed to read response." << std::endl;
+    return;
+  }
+  grpc::Status status;
+  call->Finish(&status, tag(5));
+  cq.Next(&got_tag, &ok);
+  GPR_ASSERT(ok);
+
+  if (status.IsOk()) {
+    std::cout << "RPC finished with OK status." << std::endl;
+    std::vector<grpc::Slice> slices;
+    recv_buffer.Dump(&slices);
+
+    response->clear();
+    for (size_t i = 0; i < slices.size(); i++) {
+      response->append(reinterpret_cast<const char*>(slices[i].begin()),
+                       slices[i].size());
+    }
+  } else {
+    std::cout << "RPC finished with status code " << status.code()
+              << " details: " << status.details() << std::endl;
+  }
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/php/tests/unit_tests/CompletionQueueTest.php b/test/cpp/util/cli_call.h
old mode 100755
new mode 100644
similarity index 75%
rename from src/php/tests/unit_tests/CompletionQueueTest.php
rename to test/cpp/util/cli_call.h
index 76ee61d..7be8bb6
--- a/src/php/tests/unit_tests/CompletionQueueTest.php
+++ b/test/cpp/util/cli_call.h
@@ -1,4 +1,3 @@
-<?php
 /*
  *
  * Copyright 2015, Google Inc.
@@ -31,16 +30,24 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-class CompletionQueueTest extends PHPUnit_Framework_TestCase{
-  public function testNextReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->next(Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
 
-  public function testPluckReturnsNullWithNoCall() {
-    $cq = new Grpc\CompletionQueue();
-    $event = $cq->pluck(0, Grpc\Timeval::zero());
-    $this->assertNull($event);
-  }
-}
+#ifndef GRPC_TEST_CPP_UTIL_CLI_CALL_H
+#define GRPC_TEST_CPP_UTIL_CLI_CALL_H
+
+#include <grpc++/channel_interface.h>
+#include <grpc++/config.h>
+
+namespace grpc {
+namespace testing {
+
+class CliCall GRPC_FINAL {
+ public:
+  static void Call(std::shared_ptr<grpc::ChannelInterface> channel,
+                   const grpc::string& method, const grpc::string& request,
+                   grpc::string* response);
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_CLI_CALL_H
diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc
new file mode 100644
index 0000000..32ef392
--- /dev/null
+++ b/test/cpp/util/cli_call_test.cc
@@ -0,0 +1,131 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/cli_call.h"
+#include "test/cpp/util/echo.grpc.pb.h"
+#include "src/cpp/server/thread_pool.h"
+#include <grpc++/channel_arguments.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/credentials.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc++/server_credentials.h>
+#include <grpc++/status.h>
+#include "test/core/util/port.h"
+#include <gtest/gtest.h>
+
+#include <grpc/grpc.h>
+
+using grpc::cpp::test::util::EchoRequest;
+using grpc::cpp::test::util::EchoResponse;
+
+namespace grpc {
+namespace testing {
+
+class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service {
+ public:
+  Status Echo(ServerContext* context, const EchoRequest* request,
+              EchoResponse* response) GRPC_OVERRIDE {
+    response->set_message(request->message());
+    return Status::OK;
+  }
+};
+
+class CliCallTest : public ::testing::Test {
+ protected:
+  CliCallTest() : thread_pool_(2) {}
+
+  void SetUp() GRPC_OVERRIDE {
+    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_);
+    builder.SetThreadPool(&thread_pool_);
+    server_ = builder.BuildAndStart();
+  }
+
+  void TearDown() GRPC_OVERRIDE { server_->Shutdown(); }
+
+  void ResetStub() {
+    channel_ = CreateChannel(server_address_.str(), InsecureCredentials(),
+                             ChannelArguments());
+    stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_));
+  }
+
+  std::shared_ptr<ChannelInterface> channel_;
+  std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_;
+  std::unique_ptr<Server> server_;
+  std::ostringstream server_address_;
+  TestServiceImpl service_;
+  ThreadPool thread_pool_;
+};
+
+// Send a rpc with a normal stub and then a CliCall. Verify they match.
+TEST_F(CliCallTest, SimpleRpc) {
+  ResetStub();
+  // Normal stub.
+  EchoRequest request;
+  EchoResponse response;
+  request.set_message("Hello");
+
+  ClientContext context;
+  Status s = stub_->Echo(&context, request, &response);
+  EXPECT_EQ(response.message(), request.message());
+  EXPECT_TRUE(s.IsOk());
+
+  const grpc::string kMethod("/grpc.cpp.test.util.TestService/Echo");
+  grpc::string request_bin, response_bin, expected_response_bin;
+  EXPECT_TRUE(request.SerializeToString(&request_bin));
+  EXPECT_TRUE(response.SerializeToString(&expected_response_bin));
+  CliCall::Call(channel_, kMethod, request_bin, &response_bin);
+  EXPECT_EQ(expected_response_bin, response_bin);
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+  ::testing::InitGoogleTest(&argc, argv);
+  int result = RUN_ALL_TESTS();
+  grpc_shutdown();
+  return result;
+}
diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc
new file mode 100644
index 0000000..f2271d9
--- /dev/null
+++ b/test/cpp/util/grpc_cli.cc
@@ -0,0 +1,139 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/*
+  A command line tool to talk to any grpc server.
+  Example of talking to grpc interop server:
+  1. Prepare request binary file:
+    a. create a text file input.txt, containing the following:
+        response_size: 10
+        payload: {
+          body: "hello world"
+        }
+    b. under grpc/ run
+        protoc --proto_path=test/cpp/interop/ \
+        --encode=grpc.testing.SimpleRequest test/cpp/interop/messages.proto \
+        < input.txt > input.bin
+  2. Start a server
+    make interop_server && bins/opt/interop_server --port=50051
+  3. Run the tool
+    make grpc_cli && bins/opt/grpc_cli call localhost:50051 \
+    /grpc.testing.TestService/UnaryCall --enable_ssl=false \
+    --input_binary_file=input.bin --output_binary_file=output.bin
+  4. Decode response
+    protoc --proto_path=test/cpp/interop/ \
+    --decode=grpc.testing.SimpleResponse test/cpp/interop/messages.proto \
+    < output.bin > output.txt
+  5. Now the text form of response should be in output.txt
+*/
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <gflags/gflags.h>
+#include "test/cpp/util/cli_call.h"
+#include <grpc++/channel_arguments.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/credentials.h>
+
+#include <grpc/grpc.h>
+
+// In some distros, gflags is in the namespace google, and in some others,
+// in gflags. This hack is enabling us to find both.
+namespace google {}
+namespace gflags {}
+using namespace google;
+using namespace gflags;
+
+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, "output.bin",
+              "Path to output file to write serialized response.");
+
+int main(int argc, char** argv) {
+  grpc_init();
+
+  ParseCommandLineFlags(&argc, &argv, true);
+
+  if (argc < 4 || grpc::string(argv[1]) != "call") {
+    std::cout << "Usage: grpc_cli call server_host:port full_method_string\n"
+              << "Example: grpc_cli call service.googleapis.com "
+              << "/grpc.testing.TestService/UnaryCall "
+              << "--input_binary_file=input.bin --output_binary_file=output.bin"
+              << std::endl;
+  }
+  grpc::string server_address(argv[2]);
+  // TODO(yangg) basic check of method string
+  grpc::string method(argv[3]);
+
+  if (FLAGS_input_binary_file.empty()) {
+    std::cout << "Missing --input_binary_file for serialized request."
+              << std::endl;
+    return 1;
+  }
+  std::cout << "connecting to " << server_address << std::endl;
+
+  std::ifstream input_file(FLAGS_input_binary_file,
+                           std::ios::in | std::ios::binary);
+  std::stringstream input_stream;
+  input_stream << input_file.rdbuf();
+
+  std::unique_ptr<grpc::Credentials> creds;
+  if (!FLAGS_enable_ssl) {
+    creds = grpc::InsecureCredentials();
+  } else {
+    if (FLAGS_use_auth) {
+      creds = grpc::GoogleDefaultCredentials();
+    } else {
+      creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
+    }
+  }
+  std::shared_ptr<grpc::ChannelInterface> channel =
+      grpc::CreateChannel(server_address, creds, grpc::ChannelArguments());
+
+  grpc::string response;
+  grpc::testing::CliCall::Call(channel, method, input_stream.str(), &response);
+  if (!response.empty()) {
+    std::ofstream output_file(FLAGS_output_binary_file,
+                              std::ios::trunc | std::ios::binary);
+    output_file << response;
+  }
+
+  channel.reset();
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/cpp/util/messages.proto b/test/cpp/util/messages.proto
index 9c27f68..a79bce1 100644
--- a/test/cpp/util/messages.proto
+++ b/test/cpp/util/messages.proto
@@ -34,6 +34,8 @@
 
 message RequestParams {
   optional bool echo_deadline = 1;
+  optional int32 client_cancel_after_us = 2;
+  optional int32 server_cancel_after_us = 3;
 }
 
 message EchoRequest {
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
index 2e17add..4641fdb 100644
--- a/test/cpp/util/time_test.cc
+++ b/test/cpp/util/time_test.cc
@@ -61,11 +61,24 @@
   EXPECT_TRUE(tp == tp_converted_2);
 }
 
-// gpr_inf_future is treated specially and mapped to time_point::max()
+// gpr_inf_future is treated specially and mapped to/from time_point::max()
 TEST_F(TimeTest, InfFuture) {
   EXPECT_EQ(system_clock::time_point::max(),
             Timespec2Timepoint(gpr_inf_future));
+  gpr_timespec from_time_point_max;
+  Timepoint2Timespec(system_clock::time_point::max(), &from_time_point_max);
+  EXPECT_EQ(0, gpr_time_cmp(gpr_inf_future, from_time_point_max));
+  // This will cause an overflow
+  Timepoint2Timespec(
+      std::chrono::time_point<system_clock, std::chrono::seconds>::max(),
+      &from_time_point_max);
+  EXPECT_EQ(0, gpr_time_cmp(gpr_inf_future, from_time_point_max));
 }
 
 }  // namespace
 }  // namespace grpc
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/third_party/openssl b/third_party/openssl
index 4ac0329..3df69d3 160000
--- a/third_party/openssl
+++ b/third_party/openssl
@@ -1 +1 @@
-Subproject commit 4ac0329582829f5378d8078c8d314ad37db87736
+Subproject commit 3df69d3aefde7671053d4e3c242b228e5d79c83f
diff --git a/tools/distpackages/build_deb_packages.sh b/tools/distpackages/build_deb_packages.sh
index 7b2acb6..0beb41e 100755
--- a/tools/distpackages/build_deb_packages.sh
+++ b/tools/distpackages/build_deb_packages.sh
@@ -30,11 +30,28 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 # Where to put resulting .deb packages.
-deb_dest="deb_out"
+set -x
+deb_dest="/tmp/deb_out"
 mkdir -p $deb_dest
 
-version='0.5.0.0'
+# Where the grpc disto is
+grpc_root="/var/local/git/grpc"
+
+# Update version from default values if the file /version.txt exists
+#
+# - when present, /version.txt will added by the docker build.
 pkg_version='0.5.0'
+if [ -f /version.txt ]; then
+  pkg_version=$(cat /version.txt)
+fi
+version="${pkg_version}.0"
+release_tag="release-${pkg_version//./_}"
+echo "Target release => $pkg_version, will checkout tag $release_tag"
+
+# Switch grpc_root to the release tag
+pushd $grpc_root
+git checkout $release_tag || { echo "bad release tag ${release_tag}"; exit 1; }
+popd
 
 if [ -f /.dockerinit ]; then
   # We're in Docker where uname -p returns "unknown".
@@ -64,7 +81,9 @@
   if [ $pkg_name == "libgrpc" ]
   then
     # Copy shared libraries
-    (cd ../..; make install-shared_c prefix=$tmp_dir/$pkg_name/usr/lib)
+    pushd $grpc_root
+    make install-shared_c prefix=$tmp_dir/$pkg_name/usr/lib
+    popd
     mv $tmp_dir/$pkg_name/usr/lib/lib $arch_lib_dir
 
     # non-dev package should contain so.0 symlinks
@@ -77,7 +96,10 @@
   if [ $pkg_name == "libgrpc-dev" ]
   then
     # Copy headers and static libraries
-    (cd ../..; make install-headers_c install-static_c prefix=$tmp_dir/$pkg_name/usr/lib)
+    pushd $grpc_root
+    make install-headers_c install-static_c prefix=$tmp_dir/$pkg_name/usr/lib
+    popd
+
     mv $tmp_dir/$pkg_name/usr/lib/include $tmp_dir/$pkg_name/usr/include
     mv $tmp_dir/$pkg_name/usr/lib/lib $arch_lib_dir
 
@@ -110,8 +132,5 @@
   dpkg-deb -c $deb_path
   echo "Problems reported by lintian:"
   lintian $deb_path
-
   echo
 done
-
-
diff --git a/tools/distpackages/templates/libgrpc/DEBIAN/control b/tools/distpackages/templates/libgrpc/DEBIAN/control
index 417a825..5854b1f 100644
--- a/tools/distpackages/templates/libgrpc/DEBIAN/control
+++ b/tools/distpackages/templates/libgrpc/DEBIAN/control
@@ -2,7 +2,8 @@
 Version: 0.5.0
 Architecture: amd64
 Maintainer: Jan Tattermusch <jtattermusch@google.com>
-Depends: libc6
+Depends: libc6, openssl (1.0.2-1)
+Build-Depends-Indep: openssl (1.0.2-1)
 Section: libs
 Priority: optional
 Homepage: https://github.com/grpc/grpc
diff --git a/tools/distrib/python/submit.py b/tools/distrib/python/submit.py
new file mode 100755
index 0000000..79ebb93
--- /dev/null
+++ b/tools/distrib/python/submit.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+import argparse
+import os
+import shutil
+import subprocess
+
+parser = argparse.ArgumentParser(
+    description='Submit the package to a PyPI repository.')
+parser.add_argument(
+    '--repository', '-r', metavar='r', type=str, default='pypi',
+    help='The repository to push the package to. '
+         'Ensure the value appears in your .pypirc file. '
+         'Defaults to "pypi".'
+)
+parser.add_argument(
+    '--identity', '-i', metavar='i', type=str,
+    help='GPG identity to sign the files with.'
+)
+parser.add_argument(
+    '--username', '-u', metavar='u', type=str,
+    help='Username to authenticate with the repository. Not needed if you have '
+         'configured your .pypirc to include your username.'
+)
+parser.add_argument(
+    '--password', '-p', metavar='p', type=str,
+    help='Password to authenticate with the repository. Not needed if you have '
+         'configured your .pypirc to include your password.'
+)
+args = parser.parse_args()
+
+# Move to the root directory of Python GRPC.
+pkgdir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                      '../../../src/python/src')
+# Remove previous distributions; they somehow confuse twine.
+try:
+  shutil.rmtree(os.path.join(pkgdir, 'dist/'))
+except:
+  pass
+
+# Make the push.
+cmd = ['python', 'setup.py', 'sdist']
+subprocess.call(cmd, cwd=pkgdir)
+
+cmd = ['twine', 'upload', '-r', args.repository]
+if args.identity is not None:
+  cmd.extend(['-i', args.identity])
+if args.username is not None:
+  cmd.extend(['-u', args.username])
+if args.password is not None:
+  cmd.extend(['-p', args.password])
+cmd.append('dist/*')
+
+subprocess.call(cmd, cwd=pkgdir)
diff --git a/tools/dockerfile/grpc_build_deb/Dockerfile b/tools/dockerfile/grpc_build_deb/Dockerfile
index 24ffc73..7f025b6 100644
--- a/tools/dockerfile/grpc_build_deb/Dockerfile
+++ b/tools/dockerfile/grpc_build_deb/Dockerfile
@@ -30,8 +30,17 @@
 # Dockerfile to build Debian packages for gRPC C core.
 FROM grpc/base
 
+# Add the file containing the gRPC version
+ADD version.txt version.txt
+
+# Add the update-to-date distpackages folder
+ADD distpackages distpackages
+
 # Install dependencies
-RUN apt-get update && apt-get install -y lintian
+RUN echo 'deb http://http.debian.net/debian experimental main contrib non-free' >> /etc/apt/sources.list
+RUN apt-get update \
+  && apt-get -t experimental install -y openssl=1.0.2-1 \
+  && apt-get install -y lintian
 
 # Get the source from GitHub
 RUN git clone https://github.com/grpc/grpc.git /var/local/git/grpc
@@ -39,4 +48,4 @@
   git pull --recurse-submodules && \
   git submodule update --init --recursive
 
-RUN /bin/bash -l -c 'cd /var/local/git/grpc/tools/distpackages && ./build_deb_packages.sh'
+RUN /bin/bash -l -c 'cd /distpackages && ./build_deb_packages.sh'
diff --git a/tools/dockerfile/grpc_build_deb/version.txt b/tools/dockerfile/grpc_build_deb/version.txt
new file mode 100644
index 0000000..a918a2a
--- /dev/null
+++ b/tools/dockerfile/grpc_build_deb/version.txt
@@ -0,0 +1 @@
+0.6.0
diff --git a/tools/dockerfile/grpc_dist_proto/version.txt b/tools/dockerfile/grpc_dist_proto/version.txt
index 8f0916f..a918a2a 100644
--- a/tools/dockerfile/grpc_dist_proto/version.txt
+++ b/tools/dockerfile/grpc_dist_proto/version.txt
@@ -1 +1 @@
-0.5.0
+0.6.0
diff --git a/tools/dockerfile/grpc_java_base/Dockerfile b/tools/dockerfile/grpc_java_base/Dockerfile
index 2ee0a62..57b1b90 100644
--- a/tools/dockerfile/grpc_java_base/Dockerfile
+++ b/tools/dockerfile/grpc_java_base/Dockerfile
@@ -57,8 +57,6 @@
   ./autogen.sh && \
   ./configure --prefix=/usr && \
   make -j12 && make check && make install && \
-  cd java && mvn install && cd .. && \
-  cd javanano && mvn install && cd .. && \
   rm -r "$(pwd)"
 
 # Trigger download of as many Maven and Gradle artifacts as possible. We don't build grpc-java
diff --git a/tools/dockerfile/grpc_php/Dockerfile b/tools/dockerfile/grpc_php/Dockerfile
index 100d7b3..770d0d2 100644
--- a/tools/dockerfile/grpc_php/Dockerfile
+++ b/tools/dockerfile/grpc_php/Dockerfile
@@ -45,3 +45,9 @@
 RUN cd /var/local/git/grpc/src/php/ext/grpc \
   && ./configure \
   && make
+
+RUN cd /var/local/git/grpc/src/php && composer install
+
+RUN cd /var/local/git/grpc/src/php && protoc-gen-php -i tests/interop/ -o tests/interop/ tests/interop/test.proto
+
+RUN cd /var/local/git/grpc/src/php && ./bin/run_tests.sh
\ No newline at end of file
diff --git a/tools/dockerfile/grpc_php_base/Dockerfile b/tools/dockerfile/grpc_php_base/Dockerfile
index cc874fd..c49d3fe 100644
--- a/tools/dockerfile/grpc_php_base/Dockerfile
+++ b/tools/dockerfile/grpc_php_base/Dockerfile
@@ -32,6 +32,10 @@
 # Includes PHP installation dependencies, things that are unlikely to vary.
 FROM grpc/base
 
+RUN echo "deb http://packages.dotdeb.org wheezy-php55 all" >> /etc/apt/sources.list.d/dotdeb.list
+RUN echo "deb-src http://packages.dotdeb.org wheezy-php55 all" >> /etc/apt/sources.list.d/dotdeb.list
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- |apt-key add -
+
 # Install RVM dependencies and other packages
 RUN apt-get update && apt-get install -y \
     autoconf \
@@ -50,29 +54,25 @@
     libsqlite3-dev \
     libssl-dev \
     libtool \
+    libxml2 \
     libyaml-dev \
     make \
     patch \
     procps \
-# TODO(mlumish): Uncomment these lines when building against them works
-#    php5-common \
-#    php5-cli \
-#    php5-dev \
-#    php-pear \
+    php5-common \
+    php5-cli \
+    php5-dev \
+    php-pear \
     pkg-config \
     procps \
     sqlite3 \
     zlib1g-dev
 
-# Install the version of PHP gRPC is tested against
 ENV DEBIAN_FRONTEND noniteractive
-RUN apt-get update && apt-get install -y libxml2 libxml2-dev  # used by PHP
-RUN cd /var/local \
-  && curl -o php-5.5.17.tar.gz http://php.net/distributions/php-5.5.17.tar.gz \
-  && tar -xf php-5.5.17.tar.gz \
-  && cd php-5.5.17 \
-  && ./configure --with-zlib=/usr --with-libxml-dir=ext/libxml \
-  && make -j12 && make install
+
+# Install composer
+RUN curl -sS https://getcomposer.org/installer | php
+RUN mv composer.phar /usr/local/bin/composer
 
 # Download the patched PHP protobuf so that PHP gRPC clients can be generated
 # from proto3 schemas.
diff --git a/tools/dockerfile/grpc_scan_build/Dockerfile b/tools/dockerfile/grpc_scan_build/Dockerfile
new file mode 100644
index 0000000..9f26384
--- /dev/null
+++ b/tools/dockerfile/grpc_scan_build/Dockerfile
@@ -0,0 +1,47 @@
+# 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.
+
+FROM grpc/clang:latest
+
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  libtool \
+  libgflags-dev \
+  libgtest-dev \
+  && apt-get clean
+
+RUN git clone --recursive https://github.com/grpc/grpc.git
+
+EXPOSE 8181
+
+CMD \
+  (cd grpc ; git pull) && \
+  (cd grpc ; git submodule update --init --recursive) && \
+  llvm/tools/clang/tools/scan-build/scan-build -o /tmp/grpc --use-analyzer=/usr/local/bin/clang make -C grpc buildtests && \
+  llvm/tools/clang/tools/scan-view/scan-view /tmp/grpc/`ls /tmp/grpc` --host 0.0.0.0 --no-browser --allow-all-hosts
diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh
index 497112c..4063429 100755
--- a/tools/gce_setup/grpc_docker.sh
+++ b/tools/gce_setup/grpc_docker.sh
@@ -673,7 +673,7 @@
 }
 
 # grpc_build_proto_bins
-# 
+#
 # - rebuilds the dist_proto docker image
 #   * doing this builds the protoc and the ruby, python and cpp bins statically
 #
@@ -693,11 +693,11 @@
   gce_has_instance $grpc_project $host || return 1;
   local project_opt="--project $grpc_project"
   local zone_opt="--zone $grpc_zone"
-  
+
   # rebuild the dist_proto image
   local label='dist_proto'
   grpc_update_image -- -h $host $label || return 1
- 
+
   # run a command to copy the generated archive to the docker host
   local docker_prefix='sudo docker run -v /tmp:/tmp/proto_bins_out'
   local tar_name='proto-bins*.tar.gz'
@@ -715,6 +715,63 @@
   gcloud compute copy-files $rmt_tar $local_copy $project_opt $zone_opt || return 1
 }
 
+_grpc_build_debs_args() {
+  [[ -n $1 ]] && {  # host
+    host=$1
+    shift
+  } || {
+    host='grpc-docker-builder'
+  }
+}
+
+# grpc_build_debs
+#
+# - rebuilds the build_debs
+#   * doing this builds a deb package for release debs
+#
+# - runs a docker command that copies the debs from the docker instance to its
+#   host
+# - copies the debs from the host to the local machine
+grpc_build_debs() {
+  _grpc_ensure_gcloud_ssh || return 1;
+
+  # declare vars local so that they don't pollute the shell environment
+  # where this func is used.
+  local grpc_zone grpc_project dry_run  # set by _grpc_set_project_and_zone
+  # set by _grpc_build_debs_args
+  local host
+
+  # set the project zone and check that all necessary args are provided
+  _grpc_set_project_and_zone -f _grpc_build_debs_args "$@" || return 1
+  gce_has_instance $grpc_project $host || return 1;
+  local project_opt="--project $grpc_project"
+  local zone_opt="--zone $grpc_zone"
+
+  # Update the remote distpackages_dir
+  local src_dist_dir='tools/distpackages'
+  local rmt_dist_dir="$host:~"
+  gcloud compute copy-files $src_dist_dir $rmt_dist_dir $project_opt $zone_opt || return 1
+
+  # rebuild the build_deb image
+  local label='build_deb'
+  grpc_update_image -- -h $host $label || return 1
+
+  # run a command to copy the debs from the docker instance to the host.
+  local docker_prefix='sudo docker run -v /tmp:/tmp/host_deb_out'
+  local cp_cmd="/bin/bash -c 'cp -v /tmp/deb_out/*.deb /tmp/host_deb_out'"
+  local cmd="$docker_prefix grpc/$label $cp_cmd"
+  local ssh_cmd="bash -l -c \"$cmd\""
+  echo "will run:"
+  echo "  $ssh_cmd"
+  echo "on $host"
+  gcloud compute $project_opt ssh $zone_opt $host --command "$cmd" || return 1
+
+  # copy the debs from host machine to the local one.
+  local rmt_debs="$host:/tmp/*.deb"
+  local local_copy="$(pwd)"
+  gcloud compute copy-files $rmt_debs $local_copy $project_opt $zone_opt || return 1
+}
+
 _grpc_launch_servers_args() {
   [[ -n $1 ]] && {  # host
     host=$1
@@ -984,6 +1041,35 @@
   echo $the_cmd
 }
 
+# constructs the full dockerized python service_account auth interop test cmd.
+#
+# call-seq:
+#   flags= .... # generic flags to include the command
+#   cmd=$($grpc_gen_test_cmd $flags)
+grpc_cloud_prod_auth_service_account_creds_gen_python_cmd() {
+  local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c";
+  local gfe_flags=$(_grpc_prod_gfe_flags)
+  local added_gfe_flags=$(_grpc_default_creds_test_flags)
+  local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem"
+  env_prefix+=" GOOGLE_APPLICATION_CREDENTIALS=/service_account/stubbyCloudTestingTest-7dd63462c60c.json"
+  local the_cmd="$cmd_prefix '$env_prefix python -B -m interop.client --use_tls $gfe_flags $added_gfe_flags $@'"
+  echo $the_cmd
+}
+
+# constructs the full dockerized python gce auth interop test cmd.
+#
+# call-seq:
+#   flags= .... # generic flags to include the command
+#   cmd=$($grpc_gen_test_cmd $flags)
+grpc_cloud_prod_auth_compute_engine_creds_gen_python_cmd() {
+  local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c";
+  local gfe_flags=$(_grpc_prod_gfe_flags)
+  local added_gfe_flags=$(_grpc_gce_test_flags)
+  local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem"
+  local the_cmd="$cmd_prefix '$env_prefix python -B -m interop.client --use_tls $gfe_flags $added_gfe_flags $@'"
+  echo $the_cmd
+}
+
 # constructs the full dockerized java interop test cmd.
 #
 # call-seq:
@@ -1310,5 +1396,3 @@
 _grpc_gce_test_flags() {
   echo " --default_service_account=155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel@developer.gserviceaccount.com --oauth_scope=https://www.googleapis.com/auth/xapi.zoo"
 }
-
-# TODO(grpc-team): add grpc_interop_gen_xxx_cmd for python
diff --git a/tools/gce_setup/interop_test_runner.sh b/tools/gce_setup/interop_test_runner.sh
index 7f0b5ba..1c6122e 100755
--- a/tools/gce_setup/interop_test_runner.sh
+++ b/tools/gce_setup/interop_test_runner.sh
@@ -36,7 +36,7 @@
 main() {
   source grpc_docker.sh
   test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
-  clients=(cxx java go ruby node python csharp_mono)
+  clients=(cxx java go ruby node python csharp_mono php)
   servers=(cxx java go ruby node python csharp_mono)
   for test_case in "${test_cases[@]}"
   do
diff --git a/tools/gce_setup/shared_startup_funcs.sh b/tools/gce_setup/shared_startup_funcs.sh
index e6eecc5..c4a0767 100755
--- a/tools/gce_setup/shared_startup_funcs.sh
+++ b/tools/gce_setup/shared_startup_funcs.sh
@@ -434,6 +434,12 @@
     grpc_docker_sync_service_account $dockerfile_dir/service_account || return 1;
   }
 
+  # For deb builds, copy the distpackages folder into the docker directory so
+  # that it can be installed using ADD distpackages distpackages.
+  [[ $image_label == "grpc/build_deb" ]] && {
+    cp -vR ~/distpackages $dockerfile_dir
+  }
+
   # TODO(temiola): maybe make cache/no-cache a func option?
   sudo docker build $cache_opt -t $image_label $dockerfile_dir || {
     echo "$FUNCNAME:: build of $image_label <- $dockerfile_dir"
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 6b8cd11..14ee179 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -224,6 +224,24 @@
   def __str__(self):
     return 'csharp'
 
+class Build(object):
+
+  def test_specs(self, config, travis):
+    return []
+
+  def make_targets(self):
+    return ['all']
+
+  def build_steps(self):
+    return []
+
+  def supports_multi_config(self):
+    return True
+
+  def __str__(self):
+    return self.make_target
+
+
 # different configurations we can run under
 _CONFIGS = {
     'dbg': SimpleConfig('dbg'),
@@ -248,7 +266,8 @@
     'php': PhpLanguage(),
     'python': PythonLanguage(),
     'ruby': RubyLanguage(),
-    'csharp': CSharpLanguage()
+    'csharp': CSharpLanguage(),
+    'build': Build(),
     }
 
 # parse command line
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 355d573..eab0704 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -349,11 +349,21 @@
   {
     "flaky": false, 
     "language": "c++", 
+    "name": "cli_call_test"
+  }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
     "name": "credentials_test"
   }, 
   {
     "flaky": false, 
     "language": "c++", 
+    "name": "cxx_time_test"
+  }, 
+  {
+    "flaky": false, 
+    "language": "c++", 
     "name": "end2end_test"
   }, 
   {
diff --git a/vsprojects/vs2010/Grpc.mak b/vsprojects/vs2010/Grpc.mak
new file mode 100644
index 0000000..203c787
--- /dev/null
+++ b/vsprojects/vs2010/Grpc.mak
@@ -0,0 +1,712 @@
+# 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.
+# NMake file to build secondary gRPC targets on Windows.
+# Use grpc.sln to solution to build the gRPC libraries.
+
+OUT_DIR=test_bin
+
+CC=cl.exe
+LINK=link.exe
+
+INCLUDES=/I..\.. /I..\..\include /I..\..\third_party\zlib /I..\third_party /I..\..\third_party\openssl\inc32
+DEFINES=/D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /D _CRT_SECURE_NO_WARNINGS
+CFLAGS=/c $(INCLUDES) /nologo /Z7 /W3 /WX- /sdl $(DEFINES) /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze-
+LFLAGS=/DEBUG /INCREMENTAL /NOLOGO /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86
+
+OPENSSL_LIBS=..\..\third_party\openssl\out32\ssleay32.lib ..\..\third_party\openssl\out32\libeay32.lib
+WINSOCK_LIBS=ws2_32.lib
+ZLIB_LIBS=Debug\zlibwapi.lib
+LIBS=$(OPENSSL_LIBS) $(WINSOCK_LIBS) $(ZLIB_LIBS)
+
+gpr_test_util:
+	MSBuild.exe gpr_test_util.vcxproj /p:Configuration=Debug
+
+grpc_test_util:
+	MSBuild.exe grpc_test_util.vcxproj /p:Configuration=Debug
+
+$(OUT_DIR):
+	mkdir $(OUT_DIR)
+
+buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_useful_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe 
+	echo All tests built.
+
+test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test multi_init_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test transport_security_test 
+	echo All tests ran.
+
+test_gpr: gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test 
+	echo All tests ran.
+
+alarm_heap_test.exe: grpc_test_util
+	echo Building alarm_heap_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\alarm_heap_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alarm_heap_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alarm_heap_test.obj 
+alarm_heap_test: alarm_heap_test.exe
+	echo Running alarm_heap_test
+	$(OUT_DIR)\alarm_heap_test.exe
+
+alarm_list_test.exe: grpc_test_util
+	echo Building alarm_list_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\alarm_list_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alarm_list_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alarm_list_test.obj 
+alarm_list_test: alarm_list_test.exe
+	echo Running alarm_list_test
+	$(OUT_DIR)\alarm_list_test.exe
+
+alarm_test.exe: grpc_test_util
+	echo Building alarm_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\alarm_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alarm_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alarm_test.obj 
+alarm_test: alarm_test.exe
+	echo Running alarm_test
+	$(OUT_DIR)\alarm_test.exe
+
+alpn_test.exe: grpc_test_util
+	echo Building alpn_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\alpn_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alpn_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alpn_test.obj 
+alpn_test: alpn_test.exe
+	echo Running alpn_test
+	$(OUT_DIR)\alpn_test.exe
+
+bin_encoder_test.exe: grpc_test_util
+	echo Building bin_encoder_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\bin_encoder_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\bin_encoder_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\bin_encoder_test.obj 
+bin_encoder_test: bin_encoder_test.exe
+	echo Running bin_encoder_test
+	$(OUT_DIR)\bin_encoder_test.exe
+
+census_hash_table_test.exe: grpc_test_util
+	echo Building census_hash_table_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\hash_table_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_hash_table_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\hash_table_test.obj 
+census_hash_table_test: census_hash_table_test.exe
+	echo Running census_hash_table_test
+	$(OUT_DIR)\census_hash_table_test.exe
+
+census_statistics_multiple_writers_circular_buffer_test.exe: grpc_test_util
+	echo Building census_statistics_multiple_writers_circular_buffer_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\multiple_writers_circular_buffer_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_multiple_writers_circular_buffer_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multiple_writers_circular_buffer_test.obj 
+census_statistics_multiple_writers_circular_buffer_test: census_statistics_multiple_writers_circular_buffer_test.exe
+	echo Running census_statistics_multiple_writers_circular_buffer_test
+	$(OUT_DIR)\census_statistics_multiple_writers_circular_buffer_test.exe
+
+census_statistics_multiple_writers_test.exe: grpc_test_util
+	echo Building census_statistics_multiple_writers_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\multiple_writers_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_multiple_writers_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multiple_writers_test.obj 
+census_statistics_multiple_writers_test: census_statistics_multiple_writers_test.exe
+	echo Running census_statistics_multiple_writers_test
+	$(OUT_DIR)\census_statistics_multiple_writers_test.exe
+
+census_statistics_performance_test.exe: grpc_test_util
+	echo Building census_statistics_performance_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\performance_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_performance_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\performance_test.obj 
+census_statistics_performance_test: census_statistics_performance_test.exe
+	echo Running census_statistics_performance_test
+	$(OUT_DIR)\census_statistics_performance_test.exe
+
+census_statistics_quick_test.exe: grpc_test_util
+	echo Building census_statistics_quick_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\quick_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_quick_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\quick_test.obj 
+census_statistics_quick_test: census_statistics_quick_test.exe
+	echo Running census_statistics_quick_test
+	$(OUT_DIR)\census_statistics_quick_test.exe
+
+census_statistics_small_log_test.exe: grpc_test_util
+	echo Building census_statistics_small_log_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\small_log_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_small_log_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\small_log_test.obj 
+census_statistics_small_log_test: census_statistics_small_log_test.exe
+	echo Running census_statistics_small_log_test
+	$(OUT_DIR)\census_statistics_small_log_test.exe
+
+census_stats_store_test.exe: grpc_test_util
+	echo Building census_stats_store_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\rpc_stats_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_stats_store_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\rpc_stats_test.obj 
+census_stats_store_test: census_stats_store_test.exe
+	echo Running census_stats_store_test
+	$(OUT_DIR)\census_stats_store_test.exe
+
+census_stub_test.exe: grpc_test_util
+	echo Building census_stub_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\census_stub_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_stub_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\census_stub_test.obj 
+census_stub_test: census_stub_test.exe
+	echo Running census_stub_test
+	$(OUT_DIR)\census_stub_test.exe
+
+census_trace_store_test.exe: grpc_test_util
+	echo Building census_trace_store_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\trace_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_trace_store_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\trace_test.obj 
+census_trace_store_test: census_trace_store_test.exe
+	echo Running census_trace_store_test
+	$(OUT_DIR)\census_trace_store_test.exe
+
+census_window_stats_test.exe: grpc_test_util
+	echo Building census_window_stats_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\window_stats_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_window_stats_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\window_stats_test.obj 
+census_window_stats_test: census_window_stats_test.exe
+	echo Running census_window_stats_test
+	$(OUT_DIR)\census_window_stats_test.exe
+
+chttp2_status_conversion_test.exe: grpc_test_util
+	echo Building chttp2_status_conversion_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\status_conversion_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_status_conversion_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\status_conversion_test.obj 
+chttp2_status_conversion_test: chttp2_status_conversion_test.exe
+	echo Running chttp2_status_conversion_test
+	$(OUT_DIR)\chttp2_status_conversion_test.exe
+
+chttp2_stream_encoder_test.exe: grpc_test_util
+	echo Building chttp2_stream_encoder_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\stream_encoder_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_stream_encoder_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stream_encoder_test.obj 
+chttp2_stream_encoder_test: chttp2_stream_encoder_test.exe
+	echo Running chttp2_stream_encoder_test
+	$(OUT_DIR)\chttp2_stream_encoder_test.exe
+
+chttp2_stream_map_test.exe: grpc_test_util
+	echo Building chttp2_stream_map_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\stream_map_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_stream_map_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stream_map_test.obj 
+chttp2_stream_map_test: chttp2_stream_map_test.exe
+	echo Running chttp2_stream_map_test
+	$(OUT_DIR)\chttp2_stream_map_test.exe
+
+chttp2_transport_end2end_test.exe: grpc_test_util
+	echo Building chttp2_transport_end2end_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2_transport_end2end_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_transport_end2end_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\chttp2_transport_end2end_test.obj 
+chttp2_transport_end2end_test: chttp2_transport_end2end_test.exe
+	echo Running chttp2_transport_end2end_test
+	$(OUT_DIR)\chttp2_transport_end2end_test.exe
+
+dualstack_socket_test.exe: grpc_test_util
+	echo Building dualstack_socket_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\end2end\dualstack_socket_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\dualstack_socket_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dualstack_socket_test.obj 
+dualstack_socket_test: dualstack_socket_test.exe
+	echo Running dualstack_socket_test
+	$(OUT_DIR)\dualstack_socket_test.exe
+
+echo_client.exe: grpc_test_util
+	echo Building echo_client
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\echo\client.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\echo_client.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\client.obj 
+echo_client: echo_client.exe
+	echo Running echo_client
+	$(OUT_DIR)\echo_client.exe
+
+echo_server.exe: grpc_test_util
+	echo Building echo_server
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\echo\server.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\echo_server.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\server.obj 
+echo_server: echo_server.exe
+	echo Running echo_server
+	$(OUT_DIR)\echo_server.exe
+
+echo_test.exe: grpc_test_util
+	echo Building echo_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\echo\echo_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\echo_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\echo_test.obj 
+echo_test: echo_test.exe
+	echo Running echo_test
+	$(OUT_DIR)\echo_test.exe
+
+fd_posix_test.exe: grpc_test_util
+	echo Building fd_posix_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\fd_posix_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fd_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fd_posix_test.obj 
+fd_posix_test: fd_posix_test.exe
+	echo Running fd_posix_test
+	$(OUT_DIR)\fd_posix_test.exe
+
+fling_client.exe: grpc_test_util
+	echo Building fling_client
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\client.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_client.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\client.obj 
+fling_client: fling_client.exe
+	echo Running fling_client
+	$(OUT_DIR)\fling_client.exe
+
+fling_server.exe: grpc_test_util
+	echo Building fling_server
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\server.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_server.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\server.obj 
+fling_server: fling_server.exe
+	echo Running fling_server
+	$(OUT_DIR)\fling_server.exe
+
+fling_stream_test.exe: grpc_test_util
+	echo Building fling_stream_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\fling_stream_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_stream_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fling_stream_test.obj 
+fling_stream_test: fling_stream_test.exe
+	echo Running fling_stream_test
+	$(OUT_DIR)\fling_stream_test.exe
+
+fling_test.exe: grpc_test_util
+	echo Building fling_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\fling_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fling_test.obj 
+fling_test: fling_test.exe
+	echo Running fling_test
+	$(OUT_DIR)\fling_test.exe
+
+gen_hpack_tables.exe: grpc_test_util
+	echo Building gen_hpack_tables
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\src\core\transport\chttp2\gen_hpack_tables.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gen_hpack_tables.exe" Debug\grpc_test_util.lib Debug\gpr.lib Debug\grpc.lib $(LIBS) $(OUT_DIR)\gen_hpack_tables.obj 
+gen_hpack_tables: gen_hpack_tables.exe
+	echo Running gen_hpack_tables
+	$(OUT_DIR)\gen_hpack_tables.exe
+
+gpr_cancellable_test.exe: grpc_test_util
+	echo Building gpr_cancellable_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\cancellable_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_cancellable_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\cancellable_test.obj 
+gpr_cancellable_test: gpr_cancellable_test.exe
+	echo Running gpr_cancellable_test
+	$(OUT_DIR)\gpr_cancellable_test.exe
+
+gpr_cmdline_test.exe: grpc_test_util
+	echo Building gpr_cmdline_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\cmdline_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_cmdline_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\cmdline_test.obj 
+gpr_cmdline_test: gpr_cmdline_test.exe
+	echo Running gpr_cmdline_test
+	$(OUT_DIR)\gpr_cmdline_test.exe
+
+gpr_env_test.exe: grpc_test_util
+	echo Building gpr_env_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\env_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_env_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\env_test.obj 
+gpr_env_test: gpr_env_test.exe
+	echo Running gpr_env_test
+	$(OUT_DIR)\gpr_env_test.exe
+
+gpr_file_test.exe: grpc_test_util
+	echo Building gpr_file_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\file_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_file_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\file_test.obj 
+gpr_file_test: gpr_file_test.exe
+	echo Running gpr_file_test
+	$(OUT_DIR)\gpr_file_test.exe
+
+gpr_histogram_test.exe: grpc_test_util
+	echo Building gpr_histogram_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\histogram_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_histogram_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\histogram_test.obj 
+gpr_histogram_test: gpr_histogram_test.exe
+	echo Running gpr_histogram_test
+	$(OUT_DIR)\gpr_histogram_test.exe
+
+gpr_host_port_test.exe: grpc_test_util
+	echo Building gpr_host_port_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\host_port_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_host_port_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\host_port_test.obj 
+gpr_host_port_test: gpr_host_port_test.exe
+	echo Running gpr_host_port_test
+	$(OUT_DIR)\gpr_host_port_test.exe
+
+gpr_log_test.exe: grpc_test_util
+	echo Building gpr_log_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\log_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_log_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\log_test.obj 
+gpr_log_test: gpr_log_test.exe
+	echo Running gpr_log_test
+	$(OUT_DIR)\gpr_log_test.exe
+
+gpr_slice_buffer_test.exe: grpc_test_util
+	echo Building gpr_slice_buffer_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\slice_buffer_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_slice_buffer_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\slice_buffer_test.obj 
+gpr_slice_buffer_test: gpr_slice_buffer_test.exe
+	echo Running gpr_slice_buffer_test
+	$(OUT_DIR)\gpr_slice_buffer_test.exe
+
+gpr_slice_test.exe: grpc_test_util
+	echo Building gpr_slice_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\slice_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_slice_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\slice_test.obj 
+gpr_slice_test: gpr_slice_test.exe
+	echo Running gpr_slice_test
+	$(OUT_DIR)\gpr_slice_test.exe
+
+gpr_string_test.exe: grpc_test_util
+	echo Building gpr_string_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\string_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_string_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\string_test.obj 
+gpr_string_test: gpr_string_test.exe
+	echo Running gpr_string_test
+	$(OUT_DIR)\gpr_string_test.exe
+
+gpr_sync_test.exe: grpc_test_util
+	echo Building gpr_sync_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\sync_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_sync_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\sync_test.obj 
+gpr_sync_test: gpr_sync_test.exe
+	echo Running gpr_sync_test
+	$(OUT_DIR)\gpr_sync_test.exe
+
+gpr_thd_test.exe: grpc_test_util
+	echo Building gpr_thd_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\thd_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_thd_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\thd_test.obj 
+gpr_thd_test: gpr_thd_test.exe
+	echo Running gpr_thd_test
+	$(OUT_DIR)\gpr_thd_test.exe
+
+gpr_time_test.exe: grpc_test_util
+	echo Building gpr_time_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\time_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_time_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\time_test.obj 
+gpr_time_test: gpr_time_test.exe
+	echo Running gpr_time_test
+	$(OUT_DIR)\gpr_time_test.exe
+
+gpr_useful_test.exe: grpc_test_util
+	echo Building gpr_useful_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\useful_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_useful_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\useful_test.obj 
+gpr_useful_test: gpr_useful_test.exe
+	echo Running gpr_useful_test
+	$(OUT_DIR)\gpr_useful_test.exe
+
+grpc_base64_test.exe: grpc_test_util
+	echo Building grpc_base64_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\base64_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_base64_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\base64_test.obj 
+grpc_base64_test: grpc_base64_test.exe
+	echo Running grpc_base64_test
+	$(OUT_DIR)\grpc_base64_test.exe
+
+grpc_byte_buffer_reader_test.exe: grpc_test_util
+	echo Building grpc_byte_buffer_reader_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\byte_buffer_reader_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_byte_buffer_reader_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\byte_buffer_reader_test.obj 
+grpc_byte_buffer_reader_test: grpc_byte_buffer_reader_test.exe
+	echo Running grpc_byte_buffer_reader_test
+	$(OUT_DIR)\grpc_byte_buffer_reader_test.exe
+
+grpc_channel_stack_test.exe: grpc_test_util
+	echo Building grpc_channel_stack_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\channel\channel_stack_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_channel_stack_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\channel_stack_test.obj 
+grpc_channel_stack_test: grpc_channel_stack_test.exe
+	echo Running grpc_channel_stack_test
+	$(OUT_DIR)\grpc_channel_stack_test.exe
+
+grpc_completion_queue_benchmark.exe: grpc_test_util
+	echo Building grpc_completion_queue_benchmark
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\completion_queue_benchmark.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_completion_queue_benchmark.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\completion_queue_benchmark.obj 
+grpc_completion_queue_benchmark: grpc_completion_queue_benchmark.exe
+	echo Running grpc_completion_queue_benchmark
+	$(OUT_DIR)\grpc_completion_queue_benchmark.exe
+
+grpc_completion_queue_test.exe: grpc_test_util
+	echo Building grpc_completion_queue_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\completion_queue_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_completion_queue_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\completion_queue_test.obj 
+grpc_completion_queue_test: grpc_completion_queue_test.exe
+	echo Running grpc_completion_queue_test
+	$(OUT_DIR)\grpc_completion_queue_test.exe
+
+grpc_create_jwt.exe: grpc_test_util
+	echo Building grpc_create_jwt
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\create_jwt.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_create_jwt.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\create_jwt.obj 
+grpc_create_jwt: grpc_create_jwt.exe
+	echo Running grpc_create_jwt
+	$(OUT_DIR)\grpc_create_jwt.exe
+
+grpc_credentials_test.exe: grpc_test_util
+	echo Building grpc_credentials_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\credentials_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_credentials_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\credentials_test.obj 
+grpc_credentials_test: grpc_credentials_test.exe
+	echo Running grpc_credentials_test
+	$(OUT_DIR)\grpc_credentials_test.exe
+
+grpc_fetch_oauth2.exe: grpc_test_util
+	echo Building grpc_fetch_oauth2
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\fetch_oauth2.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_fetch_oauth2.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fetch_oauth2.obj 
+grpc_fetch_oauth2: grpc_fetch_oauth2.exe
+	echo Running grpc_fetch_oauth2
+	$(OUT_DIR)\grpc_fetch_oauth2.exe
+
+grpc_json_token_test.exe: grpc_test_util
+	echo Building grpc_json_token_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\json_token_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_json_token_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_token_test.obj 
+grpc_json_token_test: grpc_json_token_test.exe
+	echo Running grpc_json_token_test
+	$(OUT_DIR)\grpc_json_token_test.exe
+
+grpc_print_google_default_creds_token.exe: grpc_test_util
+	echo Building grpc_print_google_default_creds_token
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\print_google_default_creds_token.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_print_google_default_creds_token.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\print_google_default_creds_token.obj 
+grpc_print_google_default_creds_token: grpc_print_google_default_creds_token.exe
+	echo Running grpc_print_google_default_creds_token
+	$(OUT_DIR)\grpc_print_google_default_creds_token.exe
+
+grpc_stream_op_test.exe: grpc_test_util
+	echo Building grpc_stream_op_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\stream_op_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_stream_op_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stream_op_test.obj 
+grpc_stream_op_test: grpc_stream_op_test.exe
+	echo Running grpc_stream_op_test
+	$(OUT_DIR)\grpc_stream_op_test.exe
+
+hpack_parser_test.exe: grpc_test_util
+	echo Building hpack_parser_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\hpack_parser_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\hpack_parser_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\hpack_parser_test.obj 
+hpack_parser_test: hpack_parser_test.exe
+	echo Running hpack_parser_test
+	$(OUT_DIR)\hpack_parser_test.exe
+
+hpack_table_test.exe: grpc_test_util
+	echo Building hpack_table_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\hpack_table_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\hpack_table_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\hpack_table_test.obj 
+hpack_table_test: hpack_table_test.exe
+	echo Running hpack_table_test
+	$(OUT_DIR)\hpack_table_test.exe
+
+httpcli_format_request_test.exe: grpc_test_util
+	echo Building httpcli_format_request_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\httpcli\format_request_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\httpcli_format_request_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\format_request_test.obj 
+httpcli_format_request_test: httpcli_format_request_test.exe
+	echo Running httpcli_format_request_test
+	$(OUT_DIR)\httpcli_format_request_test.exe
+
+httpcli_parser_test.exe: grpc_test_util
+	echo Building httpcli_parser_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\httpcli\parser_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\httpcli_parser_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\parser_test.obj 
+httpcli_parser_test: httpcli_parser_test.exe
+	echo Running httpcli_parser_test
+	$(OUT_DIR)\httpcli_parser_test.exe
+
+httpcli_test.exe: grpc_test_util
+	echo Building httpcli_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\httpcli\httpcli_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\httpcli_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\httpcli_test.obj 
+httpcli_test: httpcli_test.exe
+	echo Running httpcli_test
+	$(OUT_DIR)\httpcli_test.exe
+
+json_rewrite.exe: grpc_test_util
+	echo Building json_rewrite
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\json\json_rewrite.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\json_rewrite.exe" Debug\grpc.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_rewrite.obj 
+json_rewrite: json_rewrite.exe
+	echo Running json_rewrite
+	$(OUT_DIR)\json_rewrite.exe
+
+json_rewrite_test.exe: grpc_test_util
+	echo Building json_rewrite_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\json\json_rewrite_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\json_rewrite_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_rewrite_test.obj 
+json_rewrite_test: json_rewrite_test.exe
+	echo Running json_rewrite_test
+	$(OUT_DIR)\json_rewrite_test.exe
+
+json_test.exe: grpc_test_util
+	echo Building json_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\json\json_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\json_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_test.obj 
+json_test: json_test.exe
+	echo Running json_test
+	$(OUT_DIR)\json_test.exe
+
+lame_client_test.exe: grpc_test_util
+	echo Building lame_client_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\lame_client_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\lame_client_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\lame_client_test.obj 
+lame_client_test: lame_client_test.exe
+	echo Running lame_client_test
+	$(OUT_DIR)\lame_client_test.exe
+
+low_level_ping_pong_benchmark.exe: grpc_test_util
+	echo Building low_level_ping_pong_benchmark
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\network_benchmarks\low_level_ping_pong.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\low_level_ping_pong_benchmark.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\low_level_ping_pong.obj 
+low_level_ping_pong_benchmark: low_level_ping_pong_benchmark.exe
+	echo Running low_level_ping_pong_benchmark
+	$(OUT_DIR)\low_level_ping_pong_benchmark.exe
+
+message_compress_test.exe: grpc_test_util
+	echo Building message_compress_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\compression\message_compress_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\message_compress_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\message_compress_test.obj 
+message_compress_test: message_compress_test.exe
+	echo Running message_compress_test
+	$(OUT_DIR)\message_compress_test.exe
+
+metadata_buffer_test.exe: grpc_test_util
+	echo Building metadata_buffer_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\channel\metadata_buffer_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\metadata_buffer_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\metadata_buffer_test.obj 
+metadata_buffer_test: metadata_buffer_test.exe
+	echo Running metadata_buffer_test
+	$(OUT_DIR)\metadata_buffer_test.exe
+
+multi_init_test.exe: grpc_test_util
+	echo Building multi_init_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\multi_init_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\multi_init_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multi_init_test.obj 
+multi_init_test: multi_init_test.exe
+	echo Running multi_init_test
+	$(OUT_DIR)\multi_init_test.exe
+
+murmur_hash_test.exe: grpc_test_util
+	echo Building murmur_hash_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\murmur_hash_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\murmur_hash_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\murmur_hash_test.obj 
+murmur_hash_test: murmur_hash_test.exe
+	echo Running murmur_hash_test
+	$(OUT_DIR)\murmur_hash_test.exe
+
+no_server_test.exe: grpc_test_util
+	echo Building no_server_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\end2end\no_server_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\no_server_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\no_server_test.obj 
+no_server_test: no_server_test.exe
+	echo Running no_server_test
+	$(OUT_DIR)\no_server_test.exe
+
+poll_kick_posix_test.exe: grpc_test_util
+	echo Building poll_kick_posix_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\poll_kick_posix_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\poll_kick_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\poll_kick_posix_test.obj 
+poll_kick_posix_test: poll_kick_posix_test.exe
+	echo Running poll_kick_posix_test
+	$(OUT_DIR)\poll_kick_posix_test.exe
+
+resolve_address_test.exe: grpc_test_util
+	echo Building resolve_address_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\resolve_address_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\resolve_address_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\resolve_address_test.obj 
+resolve_address_test: resolve_address_test.exe
+	echo Running resolve_address_test
+	$(OUT_DIR)\resolve_address_test.exe
+
+secure_endpoint_test.exe: grpc_test_util
+	echo Building secure_endpoint_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\secure_endpoint_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_endpoint_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\secure_endpoint_test.obj 
+secure_endpoint_test: secure_endpoint_test.exe
+	echo Running secure_endpoint_test
+	$(OUT_DIR)\secure_endpoint_test.exe
+
+sockaddr_utils_test.exe: grpc_test_util
+	echo Building sockaddr_utils_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\sockaddr_utils_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\sockaddr_utils_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\sockaddr_utils_test.obj 
+sockaddr_utils_test: sockaddr_utils_test.exe
+	echo Running sockaddr_utils_test
+	$(OUT_DIR)\sockaddr_utils_test.exe
+
+tcp_client_posix_test.exe: grpc_test_util
+	echo Building tcp_client_posix_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\tcp_client_posix_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\tcp_client_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tcp_client_posix_test.obj 
+tcp_client_posix_test: tcp_client_posix_test.exe
+	echo Running tcp_client_posix_test
+	$(OUT_DIR)\tcp_client_posix_test.exe
+
+tcp_posix_test.exe: grpc_test_util
+	echo Building tcp_posix_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\tcp_posix_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\tcp_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tcp_posix_test.obj 
+tcp_posix_test: tcp_posix_test.exe
+	echo Running tcp_posix_test
+	$(OUT_DIR)\tcp_posix_test.exe
+
+tcp_server_posix_test.exe: grpc_test_util
+	echo Building tcp_server_posix_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\tcp_server_posix_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\tcp_server_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tcp_server_posix_test.obj 
+tcp_server_posix_test: tcp_server_posix_test.exe
+	echo Running tcp_server_posix_test
+	$(OUT_DIR)\tcp_server_posix_test.exe
+
+time_averaged_stats_test.exe: grpc_test_util
+	echo Building time_averaged_stats_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\time_averaged_stats_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\time_averaged_stats_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\time_averaged_stats_test.obj 
+time_averaged_stats_test: time_averaged_stats_test.exe
+	echo Running time_averaged_stats_test
+	$(OUT_DIR)\time_averaged_stats_test.exe
+
+time_test.exe: grpc_test_util
+	echo Building time_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\time_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\time_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\time_test.obj 
+time_test: time_test.exe
+	echo Running time_test
+	$(OUT_DIR)\time_test.exe
+
+timeout_encoding_test.exe: grpc_test_util
+	echo Building timeout_encoding_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\timeout_encoding_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\timeout_encoding_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\timeout_encoding_test.obj 
+timeout_encoding_test: timeout_encoding_test.exe
+	echo Running timeout_encoding_test
+	$(OUT_DIR)\timeout_encoding_test.exe
+
+transport_metadata_test.exe: grpc_test_util
+	echo Building transport_metadata_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\metadata_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\transport_metadata_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\metadata_test.obj 
+transport_metadata_test: transport_metadata_test.exe
+	echo Running transport_metadata_test
+	$(OUT_DIR)\transport_metadata_test.exe
+
+transport_security_test.exe: grpc_test_util
+	echo Building transport_security_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\tsi\transport_security_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\transport_security_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\transport_security_test.obj 
+transport_security_test: transport_security_test.exe
+	echo Running transport_security_test
+	$(OUT_DIR)\transport_security_test.exe
+
diff --git a/vsprojects/vs2010/build_openssl_x86.bat b/vsprojects/vs2010/build_openssl_x86.bat
new file mode 100644
index 0000000..9f7a013
--- /dev/null
+++ b/vsprojects/vs2010/build_openssl_x86.bat
@@ -0,0 +1,8 @@
+@echo Building OpenSSL 32bits using Visual Studio 2010.
+
+@call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
+
+cd ..\..\third_party\openssl
+nmake /F ..\..\vsprojects\third_party\openssl\OpenSSL.mak init out32\ssleay32.lib out32\libeay32.lib
+
+pause
diff --git a/vsprojects/vs2010/global.props b/vsprojects/vs2010/global.props
new file mode 100644
index 0000000..ae44e18
--- /dev/null
+++ b/vsprojects/vs2010/global.props
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ImportGroup Label="PropertySheets" />

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup />

+  <ItemDefinitionGroup>

+    <ClCompile>

+      <AdditionalIncludeDirectories>$(SolutionDir)\..\..;$(SolutionDir)\..\..\include;$(SolutionDir)\..\..\third_party\zlib;$(SolutionDir)\..\third_party;$(SolutionDir)\..\..\third_party\openssl\inc32;$(SolutionDir)\..\..\third_party\protobuf\src</AdditionalIncludeDirectories>

+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <WarningLevel>EnableAllWarnings</WarningLevel>

+    </ClCompile>

+  </ItemDefinitionGroup>

+  <ItemGroup />

+</Project>
\ No newline at end of file
diff --git a/vsprojects/vs2013/gpr_shared.vcxproj b/vsprojects/vs2010/gpr.vcxproj
similarity index 93%
rename from vsprojects/vs2013/gpr_shared.vcxproj
rename to vsprojects/vs2010/gpr.vcxproj
index 892490e..d23124c 100644
--- a/vsprojects/vs2013/gpr_shared.vcxproj
+++ b/vsprojects/vs2010/gpr.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
       <Configuration>Debug</Configuration>
@@ -11,20 +11,18 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}</ProjectGuid>
+    <ProjectGuid>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</ProjectGuid>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v120</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
     <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v120</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
     <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
@@ -85,6 +83,7 @@
     <ClInclude Include="..\..\include\grpc\support\atm_win32.h" />
     <ClInclude Include="..\..\include\grpc\support\cancellable_platform.h" />
     <ClInclude Include="..\..\include\grpc\support\cmdline.h" />
+    <ClInclude Include="..\..\include\grpc\support\cpu.h" />
     <ClInclude Include="..\..\include\grpc\support\histogram.h" />
     <ClInclude Include="..\..\include\grpc\support\host_port.h" />
     <ClInclude Include="..\..\include\grpc\support\log.h" />
@@ -115,6 +114,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\cmdline.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\cpu_iphone.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\cpu_linux.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\cpu_posix.c">
@@ -165,6 +166,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\sync_win32.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\thd.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\thd_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\thd_win32.c">
diff --git a/vsprojects/vs2013/gpr_shared.vcxproj.filters b/vsprojects/vs2010/gpr.vcxproj.filters
similarity index 95%
rename from vsprojects/vs2013/gpr_shared.vcxproj.filters
rename to vsprojects/vs2010/gpr.vcxproj.filters
index 9b78c3a..1f87944 100644
--- a/vsprojects/vs2013/gpr_shared.vcxproj.filters
+++ b/vsprojects/vs2010/gpr.vcxproj.filters
@@ -10,6 +10,9 @@
     <ClCompile Include="..\..\src\core\support\cmdline.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\cpu_iphone.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\cpu_linux.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -85,6 +88,9 @@
     <ClCompile Include="..\..\src\core\support\sync_win32.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\thd.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\thd_posix.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -123,6 +129,9 @@
     <ClInclude Include="..\..\include\grpc\support\cmdline.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\cpu.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\support\histogram.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2010/gpr_test_util.vcxproj b/vsprojects/vs2010/gpr_test_util.vcxproj
new file mode 100644
index 0000000..0568fcf
--- /dev/null
+++ b/vsprojects/vs2010/gpr_test_util.vcxproj
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <TargetName>gpr_test_util</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <TargetName>gpr_test_util</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\test\core\util\test_config.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\test\core\util\test_config.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
diff --git a/vsprojects/vs2010/grpc++.vcxproj b/vsprojects/vs2010/grpc++.vcxproj
new file mode 100644
index 0000000..003355e
--- /dev/null
+++ b/vsprojects/vs2010/grpc++.vcxproj
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <TargetName>grpc++</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <TargetName>grpc++</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\include\grpc++\async_generic_service.h" />
+    <ClInclude Include="..\..\include\grpc++\async_unary_call.h" />
+    <ClInclude Include="..\..\include\grpc++\byte_buffer.h" />
+    <ClInclude Include="..\..\include\grpc++\channel_arguments.h" />
+    <ClInclude Include="..\..\include\grpc++\channel_interface.h" />
+    <ClInclude Include="..\..\include\grpc++\client_context.h" />
+    <ClInclude Include="..\..\include\grpc++\completion_queue.h" />
+    <ClInclude Include="..\..\include\grpc++\config.h" />
+    <ClInclude Include="..\..\include\grpc++\create_channel.h" />
+    <ClInclude Include="..\..\include\grpc++\credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\generic_stub.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\call.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\client_unary_call.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\internal_stub.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\service_type.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\server.h" />
+    <ClInclude Include="..\..\include\grpc++\server_builder.h" />
+    <ClInclude Include="..\..\include\grpc++\server_context.h" />
+    <ClInclude Include="..\..\include\grpc++\server_credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\slice.h" />
+    <ClInclude Include="..\..\include\grpc++\status.h" />
+    <ClInclude Include="..\..\include\grpc++\status_code_enum.h" />
+    <ClInclude Include="..\..\include\grpc++\stream.h" />
+    <ClInclude Include="..\..\include\grpc++\thread_pool_interface.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h" />
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h" />
+    <ClInclude Include="..\..\src\cpp\client\channel.h" />
+    <ClInclude Include="..\..\src\cpp\proto\proto_utils.h" />
+    <ClInclude Include="..\..\src\cpp\server\thread_pool.h" />
+    <ClInclude Include="..\..\src\cpp\util\time.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\cpp\client\secure_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\secure_server_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\channel.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\channel_arguments.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\client_context.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\client_unary_call.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\create_channel.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\credentials.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\generic_stub.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\insecure_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\internal_stub.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\call.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\completion_queue.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\rpc_method.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\proto\proto_utils.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\async_generic_service.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server_builder.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server_context.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\slice.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\status.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\time.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+    <ProjectReference Include="grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
diff --git a/vsprojects/vs2010/grpc++.vcxproj.filters b/vsprojects/vs2010/grpc++.vcxproj.filters
new file mode 100644
index 0000000..6466a0f
--- /dev/null
+++ b/vsprojects/vs2010/grpc++.vcxproj.filters
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="..\..\src\cpp\client\secure_credentials.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\secure_server_credentials.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\channel.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\channel_arguments.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\client_context.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\client_unary_call.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\create_channel.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\credentials.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\generic_stub.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\insecure_credentials.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\internal_stub.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\call.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\completion_queue.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\common\rpc_method.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\proto\proto_utils.cc">
+      <Filter>src\cpp\proto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\async_generic_service.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server_builder.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server_context.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\server_credentials.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
+      <Filter>src\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\slice.cc">
+      <Filter>src\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\status.cc">
+      <Filter>src\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\time.cc">
+      <Filter>src\cpp\util</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\include\grpc++\async_generic_service.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\async_unary_call.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\byte_buffer.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\channel_arguments.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\channel_interface.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\client_context.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\completion_queue.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\config.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\create_channel.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\credentials.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\generic_stub.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\call.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\client_unary_call.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\internal_stub.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\service_type.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\server.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\server_builder.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\server_context.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\server_credentials.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\slice.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\status.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\status_code_enum.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\stream.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\thread_pool_interface.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h">
+      <Filter>src\cpp\client</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h">
+      <Filter>src\cpp\server</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\client\channel.h">
+      <Filter>src\cpp\client</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\proto\proto_utils.h">
+      <Filter>src\cpp\proto</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\server\thread_pool.h">
+      <Filter>src\cpp\server</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\util\time.h">
+      <Filter>src\cpp\util</Filter>
+    </ClInclude>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="include">
+      <UniqueIdentifier>{82445414-24cd-8198-1fe1-4267c3f3df00}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++">
+      <UniqueIdentifier>{784a0281-f547-aeb0-9f55-b26b7de9c769}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl">
+      <UniqueIdentifier>{0da8cd95-314f-da1b-5ce7-7791a5be1f1a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src">
+      <UniqueIdentifier>{328ff211-2886-406e-56f9-18ba1686f363}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp">
+      <UniqueIdentifier>{2420a905-e4f1-a5aa-a364-6a112878a39e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\client">
+      <UniqueIdentifier>{7febf32a-d7a6-76fa-9e17-f189f591c062}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\common">
+      <UniqueIdentifier>{2336e396-7e0b-8bf9-3b09-adc6ad1f0e5b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\proto">
+      <UniqueIdentifier>{c22e8b9b-d2eb-a2e8-0cb8-3f7e3c902a7b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\server">
+      <UniqueIdentifier>{321b0980-74ad-e8ca-f23b-deffa5d6bb8f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\util">
+      <UniqueIdentifier>{f842537a-2bf1-1ec3-b495-7d62c64a1c06}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vs2010/grpc.sln b/vsprojects/vs2010/grpc.sln
new file mode 100644
index 0000000..8d1f877
--- /dev/null
+++ b/vsprojects/vs2010/grpc.sln
@@ -0,0 +1,97 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr", "gpr.vcxproj", "{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_test_util", "gpr_test_util.vcxproj", "{EAB0A629-17A9-44DB-B5FF-E91A721FE037}"
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc", "grpc.vcxproj", "{29D16885-7228-4C31-81ED-5F9187C7F2A9}"
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_test_util", "grpc_test_util.vcxproj", "{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}"
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_unsecure", "grpc_unsecure.vcxproj", "{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}"
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++", "grpc++.vcxproj", "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}"
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_csharp_ext", "grpc_csharp_ext.vcxproj", "{D64C6D63-4458-4A88-AB38-35678384A7E4}"
+	ProjectSection(ProjectDependencies) = postProject
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_csharp_ext_shared", "grpc_csharp_ext_shared.vcxproj", "{C26D04A8-37C6-44C7-B458-906C9FCE928C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "third_party\zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}.Debug|Win32.Build.0 = Debug|Win32
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}.Release|Win32.ActiveCfg = Release|Win32
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}.Release|Win32.Build.0 = Release|Win32
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037}.Debug|Win32.ActiveCfg = Debug|Win32
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037}.Debug|Win32.Build.0 = Debug|Win32
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037}.Release|Win32.ActiveCfg = Release|Win32
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037}.Release|Win32.Build.0 = Release|Win32
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9}.Debug|Win32.ActiveCfg = Debug|Win32
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9}.Debug|Win32.Build.0 = Debug|Win32
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9}.Release|Win32.ActiveCfg = Release|Win32
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9}.Release|Win32.Build.0 = Release|Win32
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}.Debug|Win32.Build.0 = Debug|Win32
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}.Release|Win32.ActiveCfg = Release|Win32
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}.Release|Win32.Build.0 = Release|Win32
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Debug|Win32.ActiveCfg = Debug|Win32
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Debug|Win32.Build.0 = Debug|Win32
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|Win32.ActiveCfg = Release|Win32
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|Win32.Build.0 = Release|Win32
+		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Debug|Win32.Build.0 = Debug|Win32
+		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release|Win32.ActiveCfg = Release|Win32
+		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release|Win32.Build.0 = Release|Win32
+		{D64C6D63-4458-4A88-AB38-35678384A7E4}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D64C6D63-4458-4A88-AB38-35678384A7E4}.Debug|Win32.Build.0 = Debug|Win32
+		{D64C6D63-4458-4A88-AB38-35678384A7E4}.Release|Win32.ActiveCfg = Release|Win32
+		{D64C6D63-4458-4A88-AB38-35678384A7E4}.Release|Win32.Build.0 = Release|Win32
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32
+		{8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Debug|Win32.Build.0 = Debug|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Release|Win32.ActiveCfg = Release|Win32
+		{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}.Release|Win32.Build.0 = Release|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Debug|Win32.Build.0 = Debug|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Release|Win32.ActiveCfg = Release|Win32
+		{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}.Release|Win32.Build.0 = Release|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Debug|Win32.Build.0 = Debug|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Release|Win32.ActiveCfg = Release|Win32
+		{C26D04A8-37C6-44C7-B458-906C9FCE928C}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/vsprojects/vs2013/grpc_shared.vcxproj b/vsprojects/vs2010/grpc.vcxproj
similarity index 96%
rename from vsprojects/vs2013/grpc_shared.vcxproj
rename to vsprojects/vs2010/grpc.vcxproj
index f5575dc..203ca34 100644
--- a/vsprojects/vs2013/grpc_shared.vcxproj
+++ b/vsprojects/vs2010/grpc.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
       <Configuration>Debug</Configuration>
@@ -11,20 +11,18 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}</ProjectGuid>
+    <ProjectGuid>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</ProjectGuid>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v120</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
     <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v120</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
     <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
@@ -35,14 +33,10 @@
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     <Import Project="global.props" />
-    <Import Project="ssl.props" />
-    <Import Project="winsock.props" />
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     <Import Project="global.props" />
-    <Import Project="ssl.props" />
-    <Import Project="winsock.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -86,6 +80,7 @@
     <ClInclude Include="..\..\include\grpc\byte_buffer.h" />
     <ClInclude Include="..\..\include\grpc\byte_buffer_reader.h" />
     <ClInclude Include="..\..\include\grpc\grpc.h" />
+    <ClInclude Include="..\..\include\grpc\grpc_http.h" />
     <ClInclude Include="..\..\include\grpc\status.h" />
   </ItemGroup>
   <ItemGroup>
@@ -97,6 +92,7 @@
     <ClInclude Include="..\..\src\core\security\base64.h" />
     <ClInclude Include="..\..\src\core\security\credentials.h" />
     <ClInclude Include="..\..\src\core\security\json_token.h" />
+    <ClInclude Include="..\..\src\core\security\secure_endpoint.h" />
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h" />
     <ClInclude Include="..\..\src\core\security\security_context.h" />
     <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h" />
@@ -167,6 +163,7 @@
     <ClInclude Include="..\..\src\core\surface\init.h" />
     <ClInclude Include="..\..\src\core\surface\server.h" />
     <ClInclude Include="..\..\src\core\surface\surface_trace.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame_data.h" />
@@ -359,6 +356,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\call_details.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
@@ -428,12 +427,8 @@
     <ProjectReference Include="gpr.vcxproj">
       <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
     </ProjectReference>
-    <ProjectReference Include="third_party\zlibvc.vcxproj">
-      <Project>{8fd826f8-3739-44e6-8cc8-997122e53b8d}</Project>
-    </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
 </Project>
-
diff --git a/vsprojects/vs2013/grpc_shared.vcxproj.filters b/vsprojects/vs2010/grpc.vcxproj.filters
similarity index 97%
rename from vsprojects/vs2013/grpc_shared.vcxproj.filters
rename to vsprojects/vs2010/grpc.vcxproj.filters
index af38d8d..20dbe8c 100644
--- a/vsprojects/vs2013/grpc_shared.vcxproj.filters
+++ b/vsprojects/vs2010/grpc.vcxproj.filters
@@ -253,6 +253,9 @@
     <ClCompile Include="..\..\src\core\surface\call_details.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -363,6 +366,9 @@
     <ClInclude Include="..\..\include\grpc\grpc.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\grpc_http.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -392,6 +398,9 @@
     <ClInclude Include="..\..\src\core\security\json_token.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\security\secure_endpoint.h">
+      <Filter>src\core\security</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
@@ -602,6 +611,9 @@
     <ClInclude Include="..\..\src\core\surface\surface_trace.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2010/grpc_csharp_ext.vcxproj b/vsprojects/vs2010/grpc_csharp_ext.vcxproj
new file mode 100644
index 0000000..a507a9b
--- /dev/null
+++ b/vsprojects/vs2010/grpc_csharp_ext.vcxproj
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{D64C6D63-4458-4A88-AB38-35678384A7E4}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <TargetName>grpc_csharp_ext</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <TargetName>grpc_csharp_ext</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\csharp\ext\grpc_csharp_ext.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+    <ProjectReference Include="grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+
diff --git a/vsprojects/vs2010/grpc_csharp_ext_shared.vcxproj b/vsprojects/vs2010/grpc_csharp_ext_shared.vcxproj
new file mode 100644
index 0000000..b17f927
--- /dev/null
+++ b/vsprojects/vs2010/grpc_csharp_ext_shared.vcxproj
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{C26D04A8-37C6-44C7-B458-906C9FCE928C}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+    <Import Project="winsock.props" />
+    <Import Project="ssl.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+    <Import Project="winsock.props" />
+    <Import Project="ssl.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <TargetName>grpc_csharp_ext</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <TargetName>grpc_csharp_ext</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\csharp\ext\grpc_csharp_ext.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+    <ProjectReference Include="grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
+
diff --git a/vsprojects/vs2010/grpc_test_util.vcxproj b/vsprojects/vs2010/grpc_test_util.vcxproj
new file mode 100644
index 0000000..967543f
--- /dev/null
+++ b/vsprojects/vs2010/grpc_test_util.vcxproj
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="global.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <TargetName>grpc_test_util</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <TargetName>grpc_test_util</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\test\core\end2end\cq_verifier.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\end2end\data\server1_cert.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\end2end\data\server1_key.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\end2end\data\test_root_cert.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\iomgr\endpoint_tests.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\statistics\census_log_tests.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\transport\transport_end2end_tests.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\util\grpc_profiler.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\util\parse_hexstring.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\util\port_posix.c">
+    </ClCompile>
+    <ClCompile Include="..\..\test\core\util\slice_splitter.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+    <ProjectReference Include="gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
diff --git a/vsprojects/vs2013/grpc_shared.vcxproj b/vsprojects/vs2010/grpc_unsecure.vcxproj
similarity index 83%
copy from vsprojects/vs2013/grpc_shared.vcxproj
copy to vsprojects/vs2010/grpc_unsecure.vcxproj
index f5575dc..1558d72 100644
--- a/vsprojects/vs2013/grpc_shared.vcxproj
+++ b/vsprojects/vs2010/grpc_unsecure.vcxproj
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
       <Configuration>Debug</Configuration>
@@ -11,20 +11,18 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}</ProjectGuid>
+    <ProjectGuid>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</ProjectGuid>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v120</PlatformToolset>
     <CharacterSet>Unicode</CharacterSet>
     <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v120</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
     <IntDir>$(Configuration)\$(ProjectName)\</IntDir>
@@ -35,21 +33,17 @@
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     <Import Project="global.props" />
-    <Import Project="ssl.props" />
-    <Import Project="winsock.props" />
   </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
     <Import Project="global.props" />
-    <Import Project="ssl.props" />
-    <Import Project="winsock.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <TargetName>grpc</TargetName>
+    <TargetName>grpc_unsecure</TargetName>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-    <TargetName>grpc</TargetName>
+    <TargetName>grpc_unsecure</TargetName>
   </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
@@ -82,27 +76,13 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClInclude Include="..\..\include\grpc\grpc_security.h" />
     <ClInclude Include="..\..\include\grpc\byte_buffer.h" />
     <ClInclude Include="..\..\include\grpc\byte_buffer_reader.h" />
     <ClInclude Include="..\..\include\grpc\grpc.h" />
+    <ClInclude Include="..\..\include\grpc\grpc_http.h" />
     <ClInclude Include="..\..\include\grpc\status.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\..\src\core\httpcli\format_request.h" />
-    <ClInclude Include="..\..\src\core\httpcli\httpcli.h" />
-    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_context.h" />
-    <ClInclude Include="..\..\src\core\httpcli\parser.h" />
-    <ClInclude Include="..\..\src\core\security\auth.h" />
-    <ClInclude Include="..\..\src\core\security\base64.h" />
-    <ClInclude Include="..\..\src\core\security\credentials.h" />
-    <ClInclude Include="..\..\src\core\security\json_token.h" />
-    <ClInclude Include="..\..\src\core\security\secure_transport_setup.h" />
-    <ClInclude Include="..\..\src\core\security\security_context.h" />
-    <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h" />
-    <ClInclude Include="..\..\src\core\tsi\ssl_transport_security.h" />
-    <ClInclude Include="..\..\src\core\tsi\transport_security.h" />
-    <ClInclude Include="..\..\src\core\tsi\transport_security_interface.h" />
     <ClInclude Include="..\..\src\core\channel\census_filter.h" />
     <ClInclude Include="..\..\src\core\channel\channel_args.h" />
     <ClInclude Include="..\..\src\core\channel\channel_stack.h" />
@@ -167,6 +147,7 @@
     <ClInclude Include="..\..\src\core\surface\init.h" />
     <ClInclude Include="..\..\src\core\surface\server.h" />
     <ClInclude Include="..\..\src\core\surface\surface_trace.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame_data.h" />
@@ -191,47 +172,7 @@
     <ClInclude Include="..\..\src\core\transport\transport_impl.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="..\..\src\core\httpcli\format_request.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_context.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\parser.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\auth.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\base64.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\credentials.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\credentials_posix.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\credentials_win32.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\factories.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\google_default_credentials.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\json_token.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\secure_endpoint.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\security_context.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\server_secure_chttp2.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\init_secure.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\secure_channel_create.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\tsi\fake_transport_security.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\tsi\ssl_transport_security.c">
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\tsi\transport_security.c">
+    <ClCompile Include="..\..\src\core\surface\init_unsecure.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\channel\call_op_string.c">
     </ClCompile>
@@ -359,6 +300,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\call_details.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
@@ -428,12 +371,8 @@
     <ProjectReference Include="gpr.vcxproj">
       <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
     </ProjectReference>
-    <ProjectReference Include="third_party\zlibvc.vcxproj">
-      <Project>{8fd826f8-3739-44e6-8cc8-997122e53b8d}</Project>
-    </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
 </Project>
-
diff --git a/vsprojects/vs2013/grpc_shared.vcxproj.filters b/vsprojects/vs2010/grpc_unsecure.vcxproj.filters
similarity index 81%
copy from vsprojects/vs2013/grpc_shared.vcxproj.filters
copy to vsprojects/vs2010/grpc_unsecure.vcxproj.filters
index af38d8d..4b758d6 100644
--- a/vsprojects/vs2013/grpc_shared.vcxproj.filters
+++ b/vsprojects/vs2010/grpc_unsecure.vcxproj.filters
@@ -1,69 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="..\..\src\core\httpcli\format_request.c">
-      <Filter>src\core\httpcli</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli.c">
-      <Filter>src\core\httpcli</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\httpcli_security_context.c">
-      <Filter>src\core\httpcli</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\httpcli\parser.c">
-      <Filter>src\core\httpcli</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\auth.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\base64.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\credentials.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\credentials_posix.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\credentials_win32.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\factories.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\google_default_credentials.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\json_token.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\secure_endpoint.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\secure_transport_setup.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\security_context.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\security\server_secure_chttp2.c">
-      <Filter>src\core\security</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\init_secure.c">
+    <ClCompile Include="..\..\src\core\surface\init_unsecure.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\surface\secure_channel_create.c">
-      <Filter>src\core\surface</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\tsi\fake_transport_security.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\tsi\ssl_transport_security.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\src\core\tsi\transport_security.c">
-      <Filter>src\core\tsi</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\core\channel\call_op_string.c">
       <Filter>src\core\channel</Filter>
     </ClCompile>
@@ -253,6 +193,9 @@
     <ClCompile Include="..\..\src\core\surface\call_details.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -351,9 +294,6 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\..\include\grpc\grpc_security.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\include\grpc\byte_buffer.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -363,53 +303,14 @@
     <ClInclude Include="..\..\include\grpc\grpc.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\grpc_http.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="..\..\src\core\httpcli\format_request.h">
-      <Filter>src\core\httpcli</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\httpcli\httpcli.h">
-      <Filter>src\core\httpcli</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\httpcli\httpcli_security_context.h">
-      <Filter>src\core\httpcli</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\httpcli\parser.h">
-      <Filter>src\core\httpcli</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\security\auth.h">
-      <Filter>src\core\security</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\security\base64.h">
-      <Filter>src\core\security</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\security\credentials.h">
-      <Filter>src\core\security</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\security\json_token.h">
-      <Filter>src\core\security</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\security\secure_transport_setup.h">
-      <Filter>src\core\security</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\security\security_context.h">
-      <Filter>src\core\security</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\tsi\ssl_transport_security.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\tsi\transport_security.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\src\core\tsi\transport_security_interface.h">
-      <Filter>src\core\tsi</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\core\channel\census_filter.h">
       <Filter>src\core\channel</Filter>
     </ClInclude>
@@ -602,6 +503,9 @@
     <ClInclude Include="..\..\src\core\surface\surface_trace.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>
@@ -672,52 +576,43 @@
 
   <ItemGroup>
     <Filter Include="include">
-      <UniqueIdentifier>{968de0a1-346d-b75a-6f19-6a55119b8235}</UniqueIdentifier>
+      <UniqueIdentifier>{10076c7e-7c8e-8005-0c81-64454af2cbc8}</UniqueIdentifier>
     </Filter>
     <Filter Include="include\grpc">
-      <UniqueIdentifier>{880c644d-b84f-cfca-98bd-e145f36232ab}</UniqueIdentifier>
+      <UniqueIdentifier>{77b9717b-b8d8-dd5f-14bb-a3e96809a70a}</UniqueIdentifier>
     </Filter>
     <Filter Include="src">
-      <UniqueIdentifier>{d538af37-07b2-062b-fa2a-d9f882cb2737}</UniqueIdentifier>
+      <UniqueIdentifier>{aaf326a1-c884-46ea-875a-cbbd9983e539}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core">
-      <UniqueIdentifier>{ea745680-21ea-9c5e-679b-64dc40562d08}</UniqueIdentifier>
+      <UniqueIdentifier>{88491077-386b-2039-d14c-0c40136b5f7a}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\channel">
-      <UniqueIdentifier>{d897b6c3-c555-234e-a589-b4f008063615}</UniqueIdentifier>
+      <UniqueIdentifier>{cc102c4b-66ff-cf4c-2288-d76327e1a183}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\compression">
-      <UniqueIdentifier>{263cb913-dfe6-42a4-096b-cac231f76305}</UniqueIdentifier>
+      <UniqueIdentifier>{2e3aca1d-223d-10a1-b282-7f9fc68ee6f5}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\debug">
-      <UniqueIdentifier>{1da7ef8a-a06d-5499-b3de-19fee4a4214d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\httpcli">
-      <UniqueIdentifier>{a9bc00ad-835f-c625-c6d9-6a1324f98b9f}</UniqueIdentifier>
+      <UniqueIdentifier>{6d8d5774-7291-554d-fafa-583463cd3fd9}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\iomgr">
-      <UniqueIdentifier>{1baf3894-af37-e647-bdbc-95dc17ed0073}</UniqueIdentifier>
+      <UniqueIdentifier>{a9df8b24-ecea-ff6d-8999-d8fa54cd70bf}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\json">
-      <UniqueIdentifier>{e665cc0e-b994-d7c5-cc18-2007392019f0}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\security">
-      <UniqueIdentifier>{1d850ac6-e639-4eab-5338-4ba40272fcc9}</UniqueIdentifier>
+      <UniqueIdentifier>{443ffc61-1bea-2477-6e54-1ddf8c139264}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\statistics">
-      <UniqueIdentifier>{0ef49896-2313-4a3f-1ce2-716fa0e5c6ca}</UniqueIdentifier>
+      <UniqueIdentifier>{e084164c-a069-00e3-db35-4e0b1cd6f0b7}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\surface">
-      <UniqueIdentifier>{aeb18e82-5d25-0aad-8b02-a0a3470073ce}</UniqueIdentifier>
+      <UniqueIdentifier>{6cd0127e-c24b-d43c-38f5-198db8d4322a}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\transport">
-      <UniqueIdentifier>{168fa1b1-1c18-eb55-9a4d-746bc58df2c1}</UniqueIdentifier>
+      <UniqueIdentifier>{6687ff98-e36e-c0b1-2756-1bc79edec406}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\core\transport\chttp2">
-      <UniqueIdentifier>{b8b623c3-a168-a2b1-0d5f-b70a1f1cd8d2}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\core\tsi">
-      <UniqueIdentifier>{0b0f9ab1-efa4-7f03-e446-6fb9b5227e84}</UniqueIdentifier>
+      <UniqueIdentifier>{5fcd6206-f774-9ae6-4b85-305d6a723843}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>
diff --git a/vsprojects/vs2010/ssl.props b/vsprojects/vs2010/ssl.props
new file mode 100644
index 0000000..283bd17
--- /dev/null
+++ b/vsprojects/vs2010/ssl.props
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ImportGroup Label="PropertySheets" />

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup />

+  <ItemDefinitionGroup>

+    <Link>

+      <AdditionalLibraryDirectories>..\..\third_party\openssl\out32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+      <AdditionalDependencies>ssleay32.lib;libeay32.lib;%(AdditionalDependencies)</AdditionalDependencies>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup />

+</Project>
\ No newline at end of file
diff --git a/vsprojects/vs2010/third_party/zlibvc.vcxproj b/vsprojects/vs2010/third_party/zlibvc.vcxproj
new file mode 100644
index 0000000..749e3fc
--- /dev/null
+++ b/vsprojects/vs2010/third_party/zlibvc.vcxproj
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{8FD826F8-3739-44E6-8CC8-997122E53B8D}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseOfMfc>false</UseOfMfc>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseOfMfc>false</UseOfMfc>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</GenerateManifest>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+    <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</GenerateManifest>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">zlibwapi</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">zlibwapi</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Midl>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MkTypLibCompatible>true</MkTypLibCompatible>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TargetEnvironment>Win32</TargetEnvironment>
+      <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
+    </Midl>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+    <AdditionalIncludeDirectories>..\..\..\third_party\zlib;..\..\..\third_party\zlib\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ExceptionHandling>
+      </ExceptionHandling>
+      <BufferSecurityCheck>false</BufferSecurityCheck>
+      <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
+      <BrowseInformation>
+      </BrowseInformation>
+      <WarningLevel>Level3</WarningLevel>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <Culture>0x040c</Culture>
+    </ResourceCompile>
+    <Link>
+      <AdditionalOptions>/MACHINE:I386 /SAFESEH:NO %(AdditionalOptions)</AdditionalOptions>
+      <AdditionalDependencies>..\..\..\third_party\zlib\contrib\masmx86\match686.obj;..\..\..\third_party\zlib\contrib\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies>
+      <OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
+      <GenerateMapFile>true</GenerateMapFile>
+      <MapFileName>$(OutDir)zlibwapi.map</MapFileName>
+      <SubSystem>Windows</SubSystem>
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>
+      <DataExecutionPrevention>
+      </DataExecutionPrevention>
+      <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
+    </Link>
+    <PreBuildEvent>
+      <Command>cd ..\..\..\third_party\zlib\contrib\masmx86
+      bld_ml32.bat</Command>
+    </PreBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Midl>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MkTypLibCompatible>true</MkTypLibCompatible>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <TargetEnvironment>Win32</TargetEnvironment>
+      <TypeLibraryName>$(OutDir)zlibvc.tlb</TypeLibraryName>
+    </Midl>
+    <ClCompile>
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+      <AdditionalIncludeDirectories>..\..\..\third_party\zlib;..\..\..\third_party\zlib\contrib\masmx86;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <StringPooling>true</StringPooling>
+      <ExceptionHandling>
+      </ExceptionHandling>
+      <BufferSecurityCheck>false</BufferSecurityCheck>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeaderOutputFile>$(IntDir)zlibvc.pch</PrecompiledHeaderOutputFile>
+      <AssemblerOutput>All</AssemblerOutput>
+      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+      <ObjectFileName>$(IntDir)</ObjectFileName>
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
+      <BrowseInformation>
+      </BrowseInformation>
+      <WarningLevel>Level3</WarningLevel>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+    </ClCompile>
+    <ResourceCompile>
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <Culture>0x040c</Culture>
+    </ResourceCompile>
+    <Link>
+      <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
+      <AdditionalDependencies>..\..\..\third_party\zlib\contrib\masmx86\match686.obj;..\..\..\third_party\zlib\contrib\masmx86\inffas32.obj;%(AdditionalDependencies)</AdditionalDependencies>
+      <OutputFile>$(OutDir)zlibwapi.dll</OutputFile>
+      <SuppressStartupBanner>true</SuppressStartupBanner>
+      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+      <ModuleDefinitionFile>.\zlibvc.def</ModuleDefinitionFile>
+      <ProgramDatabaseFile>$(OutDir)zlibwapi.pdb</ProgramDatabaseFile>
+      <GenerateMapFile>true</GenerateMapFile>
+      <MapFileName>$(OutDir)zlibwapi.map</MapFileName>
+      <SubSystem>Windows</SubSystem>
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>
+      <DataExecutionPrevention>
+      </DataExecutionPrevention>
+      <ImportLibrary>$(OutDir)zlibwapi.lib</ImportLibrary>
+    </Link>
+    <PreBuildEvent>
+      <Command>cd ..\..\..\third_party\zlib\contrib\masmx86
+      bld_ml32.bat</Command>
+    </PreBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\..\third_party\zlib\adler32.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\compress.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\crc32.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\deflate.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\gzclose.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\gzlib.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\gzread.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\gzwrite.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\infback.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\inffast.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\inflate.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\inftrees.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\contrib\minizip\ioapi.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\contrib\minizip\iowin32.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\trees.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\uncompr.c" />
+    <ClCompile Include="..\..\..\third_party\zlib\contrib\minizip\unzip.c">
+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ZLIB_INTERNAL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <ClCompile Include="..\..\..\third_party\zlib\contrib\minizip\zip.c">
+      <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ZLIB_INTERNAL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <ClCompile Include="..\..\..\third_party\zlib\zutil.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\..\third_party\zlib\deflate.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\infblock.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\infcodes.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\inffast.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\inftrees.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\infutil.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\zconf.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\zlib.h" />
+    <ClInclude Include="..\..\..\third_party\zlib\zutil.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
diff --git a/vsprojects/vs2010/winsock.props b/vsprojects/vs2010/winsock.props
new file mode 100644
index 0000000..1e84104
--- /dev/null
+++ b/vsprojects/vs2010/winsock.props
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ImportGroup Label="PropertySheets" />

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup />

+  <ItemDefinitionGroup>

+    <Link>

+      <AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>

+    </Link>

+  </ItemDefinitionGroup>

+  <ItemGroup />

+</Project>
\ No newline at end of file
diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj
index 3d97007..e0fa68e 100644
--- a/vsprojects/vs2013/gpr.vcxproj
+++ b/vsprojects/vs2013/gpr.vcxproj
@@ -85,6 +85,7 @@
     <ClInclude Include="..\..\include\grpc\support\atm_win32.h" />
     <ClInclude Include="..\..\include\grpc\support\cancellable_platform.h" />
     <ClInclude Include="..\..\include\grpc\support\cmdline.h" />
+    <ClInclude Include="..\..\include\grpc\support\cpu.h" />
     <ClInclude Include="..\..\include\grpc\support\histogram.h" />
     <ClInclude Include="..\..\include\grpc\support\host_port.h" />
     <ClInclude Include="..\..\include\grpc\support\log.h" />
@@ -115,6 +116,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\cmdline.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\cpu_iphone.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\cpu_linux.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\cpu_posix.c">
@@ -165,6 +168,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\sync_win32.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\thd.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\thd_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\thd_win32.c">
diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters
index 9b78c3a..1f87944 100644
--- a/vsprojects/vs2013/gpr.vcxproj.filters
+++ b/vsprojects/vs2013/gpr.vcxproj.filters
@@ -10,6 +10,9 @@
     <ClCompile Include="..\..\src\core\support\cmdline.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\cpu_iphone.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\cpu_linux.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -85,6 +88,9 @@
     <ClCompile Include="..\..\src\core\support\sync_win32.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\thd.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\thd_posix.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -123,6 +129,9 @@
     <ClInclude Include="..\..\include\grpc\support\cmdline.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\cpu.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\support\histogram.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2013/gpr_test_util.vcxproj b/vsprojects/vs2013/gpr_test_util.vcxproj
index 04caa7e..e0608b3 100644
--- a/vsprojects/vs2013/gpr_test_util.vcxproj
+++ b/vsprojects/vs2013/gpr_test_util.vcxproj
@@ -78,6 +78,9 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\test\core\util\test_config.h" />
+  </ItemGroup>
+  <ItemGroup>
     <ClCompile Include="..\..\test\core\util\test_config.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vs2013/grpc++.vcxproj b/vsprojects/vs2013/grpc++.vcxproj
index f0a623b..dff5881 100644
--- a/vsprojects/vs2013/grpc++.vcxproj
+++ b/vsprojects/vs2013/grpc++.vcxproj
@@ -78,7 +78,9 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\include\grpc++\async_generic_service.h" />
     <ClInclude Include="..\..\include\grpc++\async_unary_call.h" />
+    <ClInclude Include="..\..\include\grpc++\byte_buffer.h" />
     <ClInclude Include="..\..\include\grpc++\channel_arguments.h" />
     <ClInclude Include="..\..\include\grpc++\channel_interface.h" />
     <ClInclude Include="..\..\include\grpc++\client_context.h" />
@@ -86,22 +88,32 @@
     <ClInclude Include="..\..\include\grpc++\config.h" />
     <ClInclude Include="..\..\include\grpc++\create_channel.h" />
     <ClInclude Include="..\..\include\grpc++\credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\generic_stub.h" />
     <ClInclude Include="..\..\include\grpc++\impl\call.h" />
     <ClInclude Include="..\..\include\grpc++\impl\client_unary_call.h" />
     <ClInclude Include="..\..\include\grpc++\impl\internal_stub.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h" />
     <ClInclude Include="..\..\include\grpc++\server.h" />
     <ClInclude Include="..\..\include\grpc++\server_builder.h" />
     <ClInclude Include="..\..\include\grpc++\server_context.h" />
     <ClInclude Include="..\..\include\grpc++\server_credentials.h" />
+    <ClInclude Include="..\..\include\grpc++\slice.h" />
     <ClInclude Include="..\..\include\grpc++\status.h" />
     <ClInclude Include="..\..\include\grpc++\status_code_enum.h" />
     <ClInclude Include="..\..\include\grpc++\stream.h" />
     <ClInclude Include="..\..\include\grpc++\thread_pool_interface.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h" />
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h" />
     <ClInclude Include="..\..\src\cpp\client\channel.h" />
     <ClInclude Include="..\..\src\cpp\proto\proto_utils.h" />
     <ClInclude Include="..\..\src\cpp\server\thread_pool.h" />
@@ -124,6 +136,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\credentials.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\generic_stub.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\insecure_credentials.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\internal_stub.cc">
@@ -136,6 +150,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\proto\proto_utils.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\async_generic_service.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\server.cc">
@@ -148,6 +164,10 @@
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\slice.cc">
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\status.cc">
     </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\time.cc">
diff --git a/vsprojects/vs2013/grpc++.vcxproj.filters b/vsprojects/vs2013/grpc++.vcxproj.filters
index 34ebb17..6466a0f 100644
--- a/vsprojects/vs2013/grpc++.vcxproj.filters
+++ b/vsprojects/vs2013/grpc++.vcxproj.filters
@@ -25,6 +25,9 @@
     <ClCompile Include="..\..\src\cpp\client\credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\client\generic_stub.cc">
+      <Filter>src\cpp\client</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\client\insecure_credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
@@ -43,6 +46,9 @@
     <ClCompile Include="..\..\src\cpp\proto\proto_utils.cc">
       <Filter>src\cpp\proto</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\server\async_generic_service.cc">
+      <Filter>src\cpp\server</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\server\insecure_server_credentials.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
@@ -61,6 +67,12 @@
     <ClCompile Include="..\..\src\cpp\server\thread_pool.cc">
       <Filter>src\cpp\server</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\byte_buffer.cc">
+      <Filter>src\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\cpp\util\slice.cc">
+      <Filter>src\cpp\util</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\cpp\util\status.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
@@ -69,9 +81,15 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\include\grpc++\async_generic_service.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\async_unary_call.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\byte_buffer.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\channel_arguments.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -93,6 +111,9 @@
     <ClInclude Include="..\..\include\grpc++\credentials.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\generic_stub.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\impl\call.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
@@ -111,6 +132,24 @@
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\server.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -123,6 +162,9 @@
     <ClInclude Include="..\..\include\grpc++\server_credentials.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\slice.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\status.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -137,6 +179,12 @@
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h">
+      <Filter>src\cpp\client</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h">
+      <Filter>src\cpp\server</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\cpp\client\channel.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2013/grpc.sln b/vsprojects/vs2013/grpc.sln
index a3915b3..dfefddf 100644
--- a/vsprojects/vs2013/grpc.sln
+++ b/vsprojects/vs2013/grpc.sln
@@ -18,6 +18,7 @@
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_test_util", "grpc_test_util.vcxproj", "{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}"
 	ProjectSection(ProjectDependencies) = postProject
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
@@ -38,10 +39,6 @@
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_shared", "gpr_shared.vcxproj", "{3D304D6B-AAF8-428B-AC7D-A698DDDE93C0}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_shared", "grpc_shared.vcxproj", "{F2EE8FDB-F1E0-43A0-A297-6F255BB52AAA}"
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_csharp_ext_shared", "grpc_csharp_ext_shared.vcxproj", "{C26D04A8-37C6-44C7-B458-906C9FCE928C}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "third_party\zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}"
diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj
index 9d0bcb3..a88eb34 100644
--- a/vsprojects/vs2013/grpc.vcxproj
+++ b/vsprojects/vs2013/grpc.vcxproj
@@ -82,6 +82,7 @@
     <ClInclude Include="..\..\include\grpc\byte_buffer.h" />
     <ClInclude Include="..\..\include\grpc\byte_buffer_reader.h" />
     <ClInclude Include="..\..\include\grpc\grpc.h" />
+    <ClInclude Include="..\..\include\grpc\grpc_http.h" />
     <ClInclude Include="..\..\include\grpc\status.h" />
   </ItemGroup>
   <ItemGroup>
@@ -93,6 +94,7 @@
     <ClInclude Include="..\..\src\core\security\base64.h" />
     <ClInclude Include="..\..\src\core\security\credentials.h" />
     <ClInclude Include="..\..\src\core\security\json_token.h" />
+    <ClInclude Include="..\..\src\core\security\secure_endpoint.h" />
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h" />
     <ClInclude Include="..\..\src\core\security\security_context.h" />
     <ClInclude Include="..\..\src\core\tsi\fake_transport_security.h" />
@@ -163,6 +165,7 @@
     <ClInclude Include="..\..\src\core\surface\init.h" />
     <ClInclude Include="..\..\src\core\surface\server.h" />
     <ClInclude Include="..\..\src\core\surface\surface_trace.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame_data.h" />
@@ -355,6 +358,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\call_details.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters
index af38d8d..20dbe8c 100644
--- a/vsprojects/vs2013/grpc.vcxproj.filters
+++ b/vsprojects/vs2013/grpc.vcxproj.filters
@@ -253,6 +253,9 @@
     <ClCompile Include="..\..\src\core\surface\call_details.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -363,6 +366,9 @@
     <ClInclude Include="..\..\include\grpc\grpc.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\grpc_http.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -392,6 +398,9 @@
     <ClInclude Include="..\..\src\core\security\json_token.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\security\secure_endpoint.h">
+      <Filter>src\core\security</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\security\secure_transport_setup.h">
       <Filter>src\core\security</Filter>
     </ClInclude>
@@ -602,6 +611,9 @@
     <ClInclude Include="..\..\src\core\surface\surface_trace.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2013/grpc_test_util.vcxproj b/vsprojects/vs2013/grpc_test_util.vcxproj
index 7269671..4756f53 100644
--- a/vsprojects/vs2013/grpc_test_util.vcxproj
+++ b/vsprojects/vs2013/grpc_test_util.vcxproj
@@ -105,6 +105,9 @@
     <ProjectReference Include="gpr.vcxproj">
       <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
     </ProjectReference>
+    <ProjectReference Include="gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
     <ProjectReference Include="grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj
index ad7bf47..98c14c2 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj
@@ -81,6 +81,7 @@
     <ClInclude Include="..\..\include\grpc\byte_buffer.h" />
     <ClInclude Include="..\..\include\grpc\byte_buffer_reader.h" />
     <ClInclude Include="..\..\include\grpc\grpc.h" />
+    <ClInclude Include="..\..\include\grpc\grpc_http.h" />
     <ClInclude Include="..\..\include\grpc\status.h" />
   </ItemGroup>
   <ItemGroup>
@@ -148,6 +149,7 @@
     <ClInclude Include="..\..\src\core\surface\init.h" />
     <ClInclude Include="..\..\src\core\surface\server.h" />
     <ClInclude Include="..\..\src\core\surface\surface_trace.h" />
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame.h" />
     <ClInclude Include="..\..\src\core\transport\chttp2\frame_data.h" />
@@ -300,6 +302,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\call_details.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel_create.c">
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
index 205942a..4b758d6 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
@@ -193,6 +193,9 @@
     <ClCompile Include="..\..\src\core\surface\call_details.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\call_log_batch.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\surface\channel.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -300,6 +303,9 @@
     <ClInclude Include="..\..\include\grpc\grpc.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\grpc_http.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -497,6 +503,9 @@
     <ClInclude Include="..\..\src\core\surface\surface_trace.h">
       <Filter>src\core\surface</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\transport\chttp2\alpn.h">
+      <Filter>src\core\transport\chttp2</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\transport\chttp2\bin_encoder.h">
       <Filter>src\core\transport\chttp2</Filter>
     </ClInclude>