Merge pull request #2977 from ctiller/shutdown-c++

Add a deadline to Server::Shutdown
diff --git a/INSTALL b/INSTALL
index 808166d..d183fce 100644
--- a/INSTALL
+++ b/INSTALL
@@ -9,25 +9,40 @@
 * If you are in a hurry *
 *************************
 
+On Linux (Debian):
+
+ Note: you will need to add the Debian 'unstable' distribution to your sources
+ file first.
+
+ Add the following line to your `/etc/apt/sources.list` file:
+
+   deb http://ftp.us.debian.org/debian unstable main contrib non-free
+
+ Install the gRPC library:
+
+ $ [sudo] apt-get install libgrpc-dev
+
+OR
+
  $ git clone https://github.com/grpc/grpc.git
  $ cd grpc
  $ git submodule update --init
  $ make 
- $ sudo make install
+ $ [sudo] make install
 
 You don't need anything else than GNU Make, gcc and autotools. Under a Debian
 or Ubuntu system, this should boil down to the following packages:
 
-  $ apt-get install build-essential autoconf libtool
+ $ [sudo] apt-get install build-essential autoconf libtool
 
 Building the python wrapper requires the following:
 
-  # apt-get install python-all-dev python-virtualenv
+ $ [sudo] apt-get install python-all-dev python-virtualenv
 
 If you want to install in a different directory than the default /usr/lib, you can
 override it on the command line:
 
-  # make install prefix=/opt
+ $ [sudo] make install prefix=/opt
 
 
 *******************************
diff --git a/build.json b/build.json
index 547288a..0592728 100644
--- a/build.json
+++ b/build.json
@@ -592,8 +592,7 @@
       "external_deps": [
         "zookeeper"
       ],
-      "secure": "no",
-      "vs_project_guid": "{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}"
+      "secure": "no"
     },
     {
       "name": "reconnect_server",
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index a734588..2e25033 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -505,13 +505,13 @@
   if (iomgr_success && chand->resolver) {
     grpc_resolver *resolver = chand->resolver;
     GRPC_RESOLVER_REF(resolver, "channel-next");
+    grpc_connectivity_state_set(&chand->state_tracker, state,
+                                "new_lb+resolver");
     gpr_mu_unlock(&chand->mu_config);
     GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
     grpc_resolver_next(resolver, &chand->incoming_configuration,
                        &chand->on_config_changed);
     GRPC_RESOLVER_UNREF(resolver, "channel-next");
-    grpc_connectivity_state_set(&chand->state_tracker, state,
-                                "new_lb+resolver");
     if (lb_policy != NULL) {
       watch_lb_policy(chand, lb_policy, state);
     }
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index a6153b4..33f277d 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -1573,7 +1573,8 @@
   const grpc_op *op;
   grpc_ioreq *req;
   void (*finish_func)(grpc_call *, int, void *) = finish_batch;
-  GPR_ASSERT(!reserved);
+
+  if (reserved != NULL) return GRPC_CALL_ERROR;
 
   GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
 
@@ -1588,6 +1589,7 @@
   /* rewrite batch ops into ioreq ops */
   for (in = 0, out = 0; in < nops; in++) {
     op = &ops[in];
+    if (op->reserved != NULL) return GRPC_CALL_ERROR;
     switch (op->op) {
       case GRPC_OP_SEND_INITIAL_METADATA:
         /* Flag validation: currently allow no flags */
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index f399aa6..1c40241 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -975,6 +975,11 @@
   grpc_transport_perform_op(transport, &op);
 }
 
+void done_published_shutdown(void *done_arg, grpc_cq_completion *storage) {
+  (void) done_arg;
+  gpr_free(storage);
+}
+
 void grpc_server_shutdown_and_notify(grpc_server *server,
                                      grpc_completion_queue *cq, void *tag) {
   listener *l;
@@ -986,6 +991,12 @@
   /* lock, and gather up some stuff to do */
   gpr_mu_lock(&server->mu_global);
   grpc_cq_begin_op(cq);
+  if (server->shutdown_published) {
+    grpc_cq_end_op(cq, tag, 1, done_published_shutdown, NULL,
+                   gpr_malloc(sizeof(grpc_cq_completion)));
+    gpr_mu_unlock(&server->mu_global);
+    return;
+  }
   server->shutdown_tags =
       gpr_realloc(server->shutdown_tags,
                   sizeof(shutdown_tag) * (server->num_shutdown_tags + 1));
@@ -1135,6 +1146,7 @@
     return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
   }
   grpc_cq_begin_op(cq_for_notification);
+  details->reserved = NULL;
   rc->type = BATCH_CALL;
   rc->server = server;
   rc->tag = tag;
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 9695a0f..17f31c2 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -71,7 +71,7 @@
   } else {
     const char* host_str = NULL;
     if (!context->authority().empty()) {
-      host_str = context->authority().c_str();
+      host_str = context->authority_.c_str();
     } else if (!host_.empty()) {
       host_str = host_.c_str();
     }
diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/AuthInterceptors.cs
new file mode 100644
index 0000000..61338f7
--- /dev/null
+++ b/src/csharp/Grpc.Auth/AuthInterceptors.cs
@@ -0,0 +1,84 @@
+#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.Threading;
+
+using Google.Apis.Auth.OAuth2;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Auth
+{
+    /// <summary>
+    /// Factory methods to create authorization interceptors.
+    /// </summary>
+    public static class AuthInterceptors
+    {
+        private const string AuthorizationHeader = "Authorization";
+        private const string Schema = "Bearer";
+
+        /// <summary>
+        /// Creates interceptor that will obtain access token from any credential type that implements
+        /// <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
+        /// </summary>
+        public static HeaderInterceptor FromCredential(ITokenAccess credential)
+        {
+            return new HeaderInterceptor((method, authUri, metadata) =>
+            {
+                // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
+                var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None)
+                        .ConfigureAwait(false).GetAwaiter().GetResult();
+                metadata.Add(CreateBearerTokenHeader(accessToken));
+            });
+        }
+
+        /// <summary>
+        /// Creates OAuth2 interceptor that will use given access token as authorization.
+        /// </summary>
+        /// <param name="accessToken">OAuth2 access token.</param>
+        public static HeaderInterceptor FromAccessToken(string accessToken)
+        {
+            Preconditions.CheckNotNull(accessToken);
+            return new HeaderInterceptor((method, authUri, metadata) =>
+            {
+                metadata.Add(CreateBearerTokenHeader(accessToken));
+            });
+        }
+
+        private static Metadata.Entry CreateBearerTokenHeader(string accessToken)
+        {
+            return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 930a34b..4fb087d 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -3,8 +3,6 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>10.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</ProjectGuid>
     <OutputType>Library</OutputType>
     <RootNamespace>Grpc.Auth</RootNamespace>
@@ -41,57 +39,47 @@
     <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Threading.Tasks.Extensions, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
+    <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http.Extensions">
       <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
     </Reference>
-    <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
+    <Reference Include="System.Net.Http.Primitives">
       <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
     </Reference>
-    <Reference Include="System.Net.Http.WebRequest" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\Grpc.Core\Version.cs">
       <Link>Version.cs</Link>
     </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="OAuth2Interceptors.cs" />
+    <Compile Include="AuthInterceptors.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
deleted file mode 100644
index d628a83..0000000
--- a/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-#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.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Security.Cryptography.X509Certificates;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-
-using Google.Apis.Auth.OAuth2;
-using Google.Apis.Util;
-using Grpc.Core;
-using Grpc.Core.Utils;
-
-namespace Grpc.Auth
-{
-    public static class OAuth2Interceptors
-    {
-        /// <summary>
-        /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials.
-        /// </summary>
-        public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential)
-        {
-            var interceptor = new OAuth2Interceptor(googleCredential, SystemClock.Default);
-            return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
-        }
-
-        /// <summary>
-        /// Creates OAuth2 interceptor that will use given OAuth2 token.
-        /// </summary>
-        /// <param name="oauth2Token"></param>
-        /// <returns></returns>
-        public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token)
-        {
-            Preconditions.CheckNotNull(oauth2Token);
-            return new MetadataInterceptorDelegate((authUri, metadata) =>
-            {
-                metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token));
-            });
-        }
-
-        /// <summary>
-        /// Injects OAuth2 authorization header into initial metadata (= request headers).
-        /// </summary>
-        private class OAuth2Interceptor
-        {
-            private const string AuthorizationHeader = "Authorization";
-            private const string Schema = "Bearer";
-
-            private ITokenAccess credential;
-            private IClock clock;
-
-            public OAuth2Interceptor(ITokenAccess credential, IClock clock)
-            {
-                this.credential = credential;
-                this.clock = clock;
-            }
-
-            /// <summary>
-            /// Gets access token and requests refreshing it if is going to expire soon.
-            /// </summary>
-            /// <param name="cancellationToken"></param>
-            /// <returns></returns>
-            public string GetAccessToken(string authUri, CancellationToken cancellationToken)
-            {
-                // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
-                return credential.GetAccessTokenForRequestAsync(authUri, cancellationToken: cancellationToken).GetAwaiter().GetResult();
-            }
-
-            public void InterceptHeaders(string authUri, Metadata metadata)
-            {
-                var accessToken = GetAccessToken(authUri, CancellationToken.None);
-                metadata.Add(CreateBearerTokenHeader(accessToken));
-            }
-
-            public static Metadata.Entry CreateBearerTokenHeader(string accessToken)
-            {
-                return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
-            }
-        }
-    }
-}
diff --git a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
index bf020cd..fb9b562 100644
--- a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
@@ -89,6 +89,24 @@
         }
 
         /// <summary>
+        /// Gets the call status if the call has already finished.
+        /// Throws InvalidOperationException otherwise.
+        /// </summary>
+        public Status GetStatus()
+        {
+            return getStatusFunc();
+        }
+
+        /// <summary>
+        /// Gets the call trailing metadata if the call has already finished.
+        /// Throws InvalidOperationException otherwise.
+        /// </summary>
+        public Metadata GetTrailers()
+        {
+            return getTrailersFunc();
+        }
+
+        /// <summary>
         /// Provides means to cleanup after the call.
         /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything.
         /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
diff --git a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
index 0979de6..183c842 100644
--- a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
@@ -32,8 +32,6 @@
 #endregion
 
 using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
 
 namespace Grpc.Core
 {
diff --git a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
index 380efcd..ab2049f 100644
--- a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
@@ -32,8 +32,6 @@
 #endregion
 
 using System;
-using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
 
 namespace Grpc.Core
 {
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index 0cb2953..ad54b46 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -71,7 +71,7 @@
         /// Creates a channel option with an integer value.
         /// </summary>
         /// <param name="name">Name.</param>
-        /// <param name="stringValue">String value.</param>
+        /// <param name="intValue">Integer value.</param>
         public ChannelOption(string name, int intValue)
         {
             this.type = OptionType.Integer;
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index f240d77..7bc100c 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -32,15 +32,15 @@
 #endregion
 
 using System;
-using System.Collections.Generic;
 using System.Text.RegularExpressions;
-
-using Grpc.Core.Internal;
-using Grpc.Core.Utils;
+using System.Threading.Tasks;
 
 namespace Grpc.Core
 {
-    public delegate void MetadataInterceptorDelegate(string authUri, Metadata metadata);
+    /// <summary>
+    /// Interceptor for call headers.
+    /// </summary>
+    public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata);
 
     /// <summary>
     /// Base class for client-side stubs.
@@ -60,10 +60,10 @@
         }
 
         /// <summary>
-        /// Can be used to register a custom header (initial metadata) interceptor.
-        /// The delegate each time before a new call on this client is started.
+        /// Can be used to register a custom header (request metadata) interceptor.
+        /// The interceptor is invoked each time a new call on this client is started.
         /// </summary>
-        public MetadataInterceptorDelegate HeaderInterceptor
+        public HeaderInterceptor HeaderInterceptor
         {
             get;
             set;
@@ -107,7 +107,7 @@
                     options = options.WithHeaders(new Metadata());
                 }
                 var authUri = authUriBase != null ? authUriBase + method.ServiceName : null;
-                interceptor(authUri, options.Headers);
+                interceptor(method, authUri, options.Headers);
             }
             return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
         }
diff --git a/src/csharp/Grpc.Core/Method.cs b/src/csharp/Grpc.Core/Method.cs
index 4c208b4..4c53285 100644
--- a/src/csharp/Grpc.Core/Method.cs
+++ b/src/csharp/Grpc.Core/Method.cs
@@ -55,9 +55,36 @@
     }
 
     /// <summary>
+    /// A non-generic representation of a remote method.
+    /// </summary>
+    public interface IMethod
+    {
+        /// <summary>
+        /// Gets the type of the method.
+        /// </summary>
+        MethodType Type { get; }
+
+        /// <summary>
+        /// Gets the name of the service to which this method belongs.
+        /// </summary>
+        string ServiceName { get; }
+
+        /// <summary>
+        /// Gets the unqualified name of the method.
+        /// </summary>
+        string Name { get; }
+
+        /// <summary>
+        /// Gets the fully qualified name of the method. On the server side, methods are dispatched
+        /// based on this name.
+        /// </summary>
+        string FullName { get; }
+    }
+
+    /// <summary>
     /// A description of a remote method.
     /// </summary>
-    public class Method<TRequest, TResponse>
+    public class Method<TRequest, TResponse> : IMethod
     {
         readonly MethodType type;
         readonly string serviceName;
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 385ca92..f4b0a10 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -308,7 +308,7 @@
             Console.WriteLine("running service_account_creds");
             var credential = await GoogleCredential.GetApplicationDefaultAsync();
             credential = credential.CreateScoped(new[] { AuthScope });
-            client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+            client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetResponseType(PayloadType.COMPRESSABLE)
@@ -332,7 +332,7 @@
             Console.WriteLine("running compute_engine_creds");
             var credential = await GoogleCredential.GetApplicationDefaultAsync();
             Assert.IsFalse(credential.IsCreateScopedRequired);
-            client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+            client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
             
             var request = SimpleRequest.CreateBuilder()
                 .SetResponseType(PayloadType.COMPRESSABLE)
@@ -357,7 +357,7 @@
             var credential = await GoogleCredential.GetApplicationDefaultAsync();
             // check this a credential with scope support, but don't add the scope.
             Assert.IsTrue(credential.IsCreateScopedRequired);
-            client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
+            client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetResponseType(PayloadType.COMPRESSABLE)
@@ -381,7 +381,7 @@
             ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
             string oauth2Token = await credential.GetAccessTokenForRequestAsync();
 
-            client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
+            client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetFillUsername(true)
@@ -401,7 +401,7 @@
 
             ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
             string oauth2Token = await credential.GetAccessTokenForRequestAsync();
-            var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
+            var headerInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetFillUsername(true)
@@ -409,7 +409,7 @@
                 .Build();
 
             var headers = new Metadata();
-            headerInterceptor("", headers);
+            headerInterceptor(null, "", headers);
             var response = client.UnaryCall(request, headers: headers);
 
             Assert.AreEqual(AuthScopeResponse, response.OauthScope);
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index bf2bbd8..fc9470f 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -510,22 +510,27 @@
   ops[0].data.send_initial_metadata.metadata =
       ctx->send_initial_metadata.metadata;
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
 
   ops[1].op = GRPC_OP_SEND_MESSAGE;
   ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
   ops[1].data.send_message = ctx->send_message;
   ops[1].flags = write_flags;
+  ops[1].reserved = NULL;
 
   ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   ops[2].flags = 0;
+  ops[2].reserved = NULL;
 
   ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
   ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
   ops[3].flags = 0;
+  ops[3].reserved = NULL;
 
   ops[4].op = GRPC_OP_RECV_MESSAGE;
   ops[4].data.recv_message = &(ctx->recv_message);
   ops[4].flags = 0;
+  ops[4].reserved = NULL;
 
   ops[5].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   ops[5].data.recv_status_on_client.trailing_metadata =
@@ -538,6 +543,7 @@
   ops[5].data.recv_status_on_client.status_details_capacity =
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[5].flags = 0;
+  ops[5].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
@@ -556,14 +562,17 @@
   ops[0].data.send_initial_metadata.metadata =
       ctx->send_initial_metadata.metadata;
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
 
   ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
   ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
   ops[1].flags = 0;
+  ops[1].reserved = NULL;
 
   ops[2].op = GRPC_OP_RECV_MESSAGE;
   ops[2].data.recv_message = &(ctx->recv_message);
   ops[2].flags = 0;
+  ops[2].reserved = NULL;
 
   ops[3].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   ops[3].data.recv_status_on_client.trailing_metadata =
@@ -576,6 +585,7 @@
   ops[3].data.recv_status_on_client.status_details_capacity =
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[3].flags = 0;
+  ops[3].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
@@ -593,18 +603,22 @@
   ops[0].data.send_initial_metadata.metadata =
       ctx->send_initial_metadata.metadata;
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
 
   ops[1].op = GRPC_OP_SEND_MESSAGE;
   ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
   ops[1].data.send_message = ctx->send_message;
   ops[1].flags = write_flags;
+  ops[1].reserved = NULL;
 
   ops[2].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   ops[2].flags = 0;
+  ops[2].reserved = NULL;
 
   ops[3].op = GRPC_OP_RECV_INITIAL_METADATA;
   ops[3].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
   ops[3].flags = 0;
+  ops[3].reserved = NULL;
 
   ops[4].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   ops[4].data.recv_status_on_client.trailing_metadata =
@@ -617,6 +631,7 @@
   ops[4].data.recv_status_on_client.status_details_capacity =
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[4].flags = 0;
+  ops[4].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
@@ -635,10 +650,12 @@
   ops[0].data.send_initial_metadata.metadata =
       ctx->send_initial_metadata.metadata;
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
 
   ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
   ops[1].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
   ops[1].flags = 0;
+  ops[1].reserved = NULL;
 
   ops[2].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   ops[2].data.recv_status_on_client.trailing_metadata =
@@ -651,6 +668,7 @@
   ops[2].data.recv_status_on_client.status_details_capacity =
       &(ctx->recv_status_on_client.status_details_capacity);
   ops[2].flags = 0;
+  ops[2].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
@@ -668,10 +686,12 @@
   ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
   ops[0].data.send_message = ctx->send_message;
   ops[0].flags = write_flags;
+  ops[0].reserved = NULL;
   ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
   ops[1].data.send_initial_metadata.count = 0;
   ops[1].data.send_initial_metadata.metadata = NULL;
   ops[1].flags = 0;
+  ops[1].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, nops, ctx, NULL);
 }
@@ -683,6 +703,7 @@
   grpc_op ops[1];
   ops[0].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
@@ -706,10 +727,12 @@
   ops[0].data.send_status_from_server.trailing_metadata =
       ctx->send_status_from_server.trailing_metadata.metadata;
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
   ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
   ops[1].data.send_initial_metadata.count = 0;
   ops[1].data.send_initial_metadata.metadata = NULL;
   ops[1].flags = 0;
+  ops[1].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, nops, ctx, NULL);
 }
@@ -721,6 +744,7 @@
   ops[0].op = GRPC_OP_RECV_MESSAGE;
   ops[0].data.recv_message = &(ctx->recv_message);
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
 }
@@ -733,6 +757,7 @@
   ops[0].data.recv_close_on_server.cancelled =
       (&ctx->recv_close_on_server_cancelled);
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
@@ -751,6 +776,7 @@
   ops[0].data.send_initial_metadata.metadata =
       ctx->send_initial_metadata.metadata;
   ops[0].flags = 0;
+  ops[0].reserved = NULL;
 
   return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
                                NULL);
diff --git a/src/node/README.md b/src/node/README.md
index 7d3d8c7..b641153 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -5,11 +5,35 @@
 
 ## PREREQUISITES
 - `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
-- [homebrew][] on Mac OS X, [linuxbrew][] on Linux.  These simplify the installation of the gRPC C core.
+- [homebrew][] on Mac OS X.  These simplify the installation of the gRPC C core.
 
 ## INSTALLATION
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
-Run the following command to install gRPC Node.js.
+
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC NPM package
+
+```sh
+npm install grpc
+```
+
+**Mac OS X**
+
+Install [homebrew][]. Run the following command to install gRPC Node.js.
 ```sh
 $ curl -fsSL https://goo.gl/getgrpc | bash -s nodejs
 ```
@@ -88,5 +112,5 @@
 An object with factory methods for creating credential objects for servers.
 
 [homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
 [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 705c80f..18858fa 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -207,6 +207,13 @@
     if (!::node::Buffer::HasInstance(value)) {
       return false;
     }
+    Handle<Object> object_value = value->ToObject();
+    if (object_value->HasOwnProperty(NanNew("grpcWriteFlags"))) {
+      Handle<Value> flag_value = object_value->Get(NanNew("grpcWriteFlags"));
+      if (flag_value->IsUint32()) {
+        out->flags = flag_value->Uint32Value() & GRPC_WRITE_USED_MASK;
+      }
+    }
     out->data.send_message = BufferToByteBuffer(value);
     Persistent<Value> *handle = new Persistent<Value>();
     NanAssignPersistent(*handle, value);
@@ -457,10 +464,6 @@
                           NanNew<FunctionTemplate>(GetPeer)->GetFunction());
   NanAssignPersistent(fun_tpl, tpl);
   Handle<Function> ctr = tpl->GetFunction();
-  ctr->Set(NanNew("WRITE_BUFFER_HINT"),
-           NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
-  ctr->Set(NanNew("WRITE_NO_COMPRESS"),
-           NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
   exports->Set(NanNew("Call"), ctr);
   constructor = new NanCallback(ctr);
 }
@@ -581,6 +584,7 @@
     uint32_t type = keys->Get(i)->Uint32Value();
     ops[i].op = static_cast<grpc_op_type>(type);
     ops[i].flags = 0;
+    ops[i].reserved = NULL;
     switch (type) {
       case GRPC_OP_SEND_INITIAL_METADATA:
         op.reset(new SendMetadataOp());
@@ -619,7 +623,7 @@
       call->wrapped_call, &ops[0], nops, new struct tag(
           callback, op_vector.release(), resources), NULL);
   if (error != GRPC_CALL_OK) {
-    return NanThrowError("startBatch failed", error);
+    return NanThrowError(nanErrorWithCode("startBatch failed", error));
   }
   CompletionQueueAsyncWorker::Next();
   NanReturnUndefined();
@@ -633,7 +637,7 @@
   Call *call = ObjectWrap::Unwrap<Call>(args.This());
   grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL);
   if (error != GRPC_CALL_OK) {
-    return NanThrowError("cancel failed", error);
+    return NanThrowError(nanErrorWithCode("cancel failed", error));
   }
   NanReturnUndefined();
 }
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index 6acda76..ef6e5fc 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -51,6 +51,19 @@
 using std::unique_ptr;
 using std::shared_ptr;
 
+/**
+ * Helper function for throwing errors with a grpc_call_error value.
+ * Modified from the answer by Gus Goose to
+ * http://stackoverflow.com/questions/31794200.
+ */
+inline v8::Local<v8::Value> nanErrorWithCode(const char *msg,
+                                             grpc_call_error code) {
+    NanEscapableScope();
+    v8::Local<v8::Object> err = NanError(msg).As<v8::Object>();
+    err->Set(NanNew("code"), NanNew<v8::Uint32>(code));
+    return NanEscapeScope(err);
+}
+
 v8::Handle<v8::Value> ParseMetadata(const grpc_metadata_array *metadata_array);
 
 class PersistentHolder {
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index d93dafd..0cf30da 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -196,6 +196,16 @@
   channel_state->Set(NanNew("FATAL_FAILURE"), FATAL_FAILURE);
 }
 
+void InitWriteFlags(Handle<Object> exports) {
+  NanScope();
+  Handle<Object> write_flags = NanNew<Object>();
+  exports->Set(NanNew("writeFlags"), write_flags);
+  Handle<Value> BUFFER_HINT(NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
+  write_flags->Set(NanNew("BUFFER_HINT"), BUFFER_HINT);
+  Handle<Value> NO_COMPRESS(NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
+  write_flags->Set(NanNew("NO_COMPRESS"), NO_COMPRESS);
+}
+
 void init(Handle<Object> exports) {
   NanScope();
   grpc_init();
@@ -204,6 +214,7 @@
   InitOpTypeConstants(exports);
   InitPropagateConstants(exports);
   InitConnectivityStateConstants(exports);
+  InitWriteFlags(exports);
 
   grpc::node::Call::Init(exports);
   grpc::node::Channel::Init(exports);
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 8e39644..01217bc 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -235,7 +235,7 @@
       new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
                      shared_ptr<Resources>(nullptr)));
   if (error != GRPC_CALL_OK) {
-    return NanThrowError("requestCall failed", error);
+    return NanThrowError(nanErrorWithCode("requestCall failed", error));
   }
   CompletionQueueAsyncWorker::Next();
   NanReturnUndefined();
diff --git a/src/node/index.js b/src/node/index.js
index 93c65ac..889b0ac 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -145,6 +145,11 @@
 exports.callError = grpc.callError;
 
 /**
+ * Write flag name to code number mapping
+ */
+exports.writeFlags = grpc.writeFlags;
+
+/**
  * Credentials factories
  */
 exports.Credentials = grpc.Credentials;
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 6d6f9a3..612dcf0 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -264,7 +264,9 @@
     payload: {body: zeroBuffer(27182)}
   });
   call.on('error', function(error) {
-    assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED);
+
+    assert(error.code === grpc.status.DEADLINE_EXCEEDED ||
+        error.code === grpc.status.INTERNAL);
     done();
   });
 }
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 50cbf4a..48fe0dd 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -79,13 +79,19 @@
  * implementation of a method needed for implementing stream.Writable.
  * @access private
  * @param {Buffer} chunk The chunk to write
- * @param {string} encoding Ignored
+ * @param {string} encoding Used to pass write flags
  * @param {function(Error=)} callback Called when the write is complete
  */
 function _write(chunk, encoding, callback) {
   /* jshint validthis: true */
   var batch = {};
-  batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+  var message = this.serialize(chunk);
+  if (_.isFinite(encoding)) {
+    /* Attach the encoding if it is a finite number. This is the closest we
+     * can get to checking that it is valid flags */
+    message.grpcWriteFlags = encoding;
+  }
+  batch[grpc.opType.SEND_MESSAGE] = message;
   this.call.startBatch(batch, function(err, event) {
     if (err) {
       // Something has gone wrong. Stop writing by failing to call callback
@@ -273,8 +279,10 @@
         return;
       }
       var client_batch = {};
+      var message = serialize(argument);
+      message.grpcWriteFlags = options.flags;
       client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
-      client_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+      client_batch[grpc.opType.SEND_MESSAGE] = message;
       client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
       client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
       client_batch[grpc.opType.RECV_MESSAGE] = true;
@@ -407,9 +415,11 @@
         return;
       }
       var start_batch = {};
+      var message = serialize(argument);
+      message.grpcWriteFlags = options.flags;
       start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
       start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
-      start_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
+      start_batch[grpc.opType.SEND_MESSAGE] = message;
       start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
       call.startBatch(start_batch, function(err, response) {
         if (err) {
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 8b86173..5037aba 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -115,8 +115,10 @@
  * @param {function(*):Buffer=} serialize Serialization function for the
  *     response
  * @param {Object=} metadata Optional trailing metadata to send with status
+ * @param {number=} flags Flags for modifying how the message is sent.
+ *     Defaults to 0.
  */
-function sendUnaryResponse(call, value, serialize, metadata) {
+function sendUnaryResponse(call, value, serialize, metadata, flags) {
   var end_batch = {};
   var status = {
     code: grpc.status.OK,
@@ -130,7 +132,9 @@
     end_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
     call.metadataSent = true;
   }
-  end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
+  var message = serialize(value);
+  message.grpcWriteFlags = flags;
+  end_batch[grpc.opType.SEND_MESSAGE] = message;
   end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
   call.startBatch(end_batch, function (){});
 }
@@ -254,7 +258,7 @@
  * for implementing stream.Writable.
  * @access private
  * @param {Buffer} chunk The chunk of data to write
- * @param {string} encoding Ignored
+ * @param {string} encoding Used to pass write flags
  * @param {function(Error=)} callback Callback to indicate that the write is
  *     complete
  */
@@ -265,7 +269,13 @@
     batch[grpc.opType.SEND_INITIAL_METADATA] = {};
     this.call.metadataSent = true;
   }
-  batch[grpc.opType.SEND_MESSAGE] = this.serialize(chunk);
+  var message = this.serialize(chunk);
+  if (_.isFinite(encoding)) {
+    /* Attach the encoding if it is a finite number. This is the closest we
+     * can get to checking that it is valid flags */
+    message.grpcWriteFlags = encoding;
+  }
+  batch[grpc.opType.SEND_MESSAGE] = message;
   this.call.startBatch(batch, function(err, value) {
     if (err) {
       this.emit('error', err);
@@ -450,14 +460,14 @@
     if (emitter.cancelled) {
       return;
     }
-    handler.func(emitter, function sendUnaryData(err, value, trailer) {
+    handler.func(emitter, function sendUnaryData(err, value, trailer, flags) {
       if (err) {
         if (trailer) {
           err.metadata = trailer;
         }
         handleError(call, err);
       } else {
-        sendUnaryResponse(call, value, handler.serialize, trailer);
+        sendUnaryResponse(call, value, handler.serialize, trailer, flags);
       }
     });
   });
@@ -514,7 +524,7 @@
   });
   waitForCancel(call, stream);
   stream.metadata = metadata;
-  handler.func(stream, function(err, value, trailer) {
+  handler.func(stream, function(err, value, trailer, flags) {
     stream.terminate();
     if (err) {
       if (trailer) {
@@ -522,7 +532,7 @@
       }
       handleError(call, err);
     } else {
-      sendUnaryResponse(call, value, handler.serialize, trailer);
+      sendUnaryResponse(call, value, handler.serialize, trailer, flags);
     }
   });
 }
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 52515cc..ec7ed87 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -784,7 +784,8 @@
           client.clientStream(function(err, value) {
             try {
               assert(err);
-              assert.strictEqual(err.code, grpc.status.DEADLINE_EXCEEDED);
+              assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
+                  err.code === grpc.status.INTERNAL);
             } finally {
               callback(err, value);
               done();
@@ -809,7 +810,8 @@
               null, {parent: parent, propagate_flags: deadline_flags});
           child.on('error', function(err) {
             assert(err);
-            assert.strictEqual(err.code, grpc.status.DEADLINE_EXCEEDED);
+            assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
+                err.code === grpc.status.INTERNAL);
             done();
           });
         };
diff --git a/src/php/README.md b/src/php/README.md
index 1804606..f432935 100644
--- a/src/php/README.md
+++ b/src/php/README.md
@@ -7,17 +7,17 @@
 
 Alpha : Ready for early adopters
 
-## ENVIRONMENT
+## Environment
 
 Prerequisite: PHP 5.5 or later, `phpunit`, `pecl`
 
-Linux:
+**Linux:**
 
 ```sh
 $ sudo apt-get install php5 php5-dev phpunit php-pear
 ```
 
-OS X:
+**Mac OS X:**
 
 ```sh
 $ curl https://phar.phpunit.de/phpunit.phar -o phpunit.phar
@@ -28,10 +28,39 @@
 $ sudo php -d detect_unicode=0 go-pear.phar
 ```
 
-## Build from Homebrew
+## Quick Install
 
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to
-install gRPC.
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC PHP extension
+
+```sh
+sudo pecl install grpc-alpha
+```
+
+**Mac OS X:**
+
+Install [homebrew][]. Example:
+
+```sh
+ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
+```
+
+Install the gRPC core library and the PHP extension in one step
 
 ```sh
 $ curl -fsSL https://goo.gl/getgrpc | bash -s php
@@ -39,6 +68,7 @@
 
 This will download and run the [gRPC install script][] and compile the gRPC PHP extension.
 
+
 ## Build from Source
 
 Clone this repository
@@ -71,7 +101,7 @@
 Install the gRPC PHP extension
 
 ```sh
-$ sudo pecl install grpc
+$ sudo pecl install grpc-alpha
 ```
 
 OR
@@ -140,6 +170,6 @@
 ```
 
 [homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
 [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
 [Node]:https://github.com/grpc/grpc/tree/master/src/node/examples
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 1cf766c..6009a8d 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -273,7 +273,6 @@
   grpc_byte_buffer *message;
   int cancelled;
   grpc_call_error error;
-  grpc_event event;
   zval *result;
   char *message_str;
   size_t message_len;
@@ -398,6 +397,7 @@
     }
     ops[op_num].op = (grpc_op_type)index;
     ops[op_num].flags = 0;
+    ops[op_num].reserved = NULL;
     op_num++;
   }
   error = grpc_call_start_batch(call->wrapped, ops, op_num, call->wrapped,
@@ -408,14 +408,8 @@
                          (long)error TSRMLS_CC);
     goto cleanup;
   }
-  event = grpc_completion_queue_pluck(completion_queue, call->wrapped,
-                                      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-  if (!event.success) {
-    zend_throw_exception(spl_ce_LogicException,
-                         "The batch failed for some reason",
-                         1 TSRMLS_CC);
-    goto cleanup;
-  }
+  grpc_completion_queue_pluck(completion_queue, call->wrapped,
+                              gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
   for (int i = 0; i < op_num; i++) {
     switch(ops[i].op) {
       case GRPC_OP_SEND_INITIAL_METADATA:
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 44e6242..376d306 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -271,7 +271,7 @@
 }
 
 function timeoutOnSleepingServer($stub) {
-  $call = $stub->FullDuplexCall(array('timeout' => 500000));
+  $call = $stub->FullDuplexCall(array('timeout' => 1000));
   $request = new grpc\testing\StreamingOutputCallRequest();
   $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE);
   $response_parameters = new grpc\testing\ResponseParameters();
diff --git a/src/python/README.md b/src/python/README.md
index 2beb3a9..de0142d 100644
--- a/src/python/README.md
+++ b/src/python/README.md
@@ -9,12 +9,36 @@
 PREREQUISITES
 -------------
 - Python 2.7, virtualenv, pip
-- [homebrew][] on Mac OS X, [linuxbrew][] on Linux.  These simplify the installation of the gRPC C core.
+- [homebrew][] on Mac OS X.  These simplify the installation of the gRPC C core.
 
 INSTALLATION
 -------------
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
-Run the following command to install gRPC Python.
+
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC Python module
+
+```sh
+sudo pip install grpcio
+```
+
+**Mac OS X**
+
+Install [homebrew][]. Run the following command to install gRPC Python.
 ```sh
 $ curl -fsSL https://goo.gl/getgrpc | bash -s python
 ```
@@ -27,11 +51,6 @@
 BUILDING FROM SOURCE
 ---------------------
 - Clone this repository
-- Build the gRPC core from the root of the
-  [gRPC Git repository](https://github.com/grpc/grpc)
-```
-$ make shared_c static_c
-```
 
 - Use build_python.sh to build the Python code and install it into a virtual environment
 ```
@@ -60,7 +79,7 @@
 ```
 
 [homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
 [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
 [Quick Start]:http://www.grpc.io/docs/tutorials/basic/python.html
 [detailed example]:http://www.grpc.io/docs/installation/python.html
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index 00bdecf..c7b5a3b 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -6,7 +6,7 @@
 Dependencies
 ------------
 
-Ensure you have installed the gRPC core.  On Mac OS X, install homebrew_. On Linux, install linuxbrew_.
+Ensure you have installed the gRPC core.  On Mac OS X, install homebrew_.
 Run the following command to install gRPC Python.
 
 ::
@@ -19,5 +19,4 @@
 
 .. _`install from source`: https://github.com/grpc/grpc/blob/master/src/python/README.md#building-from-source
 .. _homebrew: http://brew.sh
-.. _linuxbrew: https://github.com/Homebrew/linuxbrew#installation
 .. _`gRPC install script`: https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
diff --git a/src/python/grpcio/grpc/_adapter/_c/utility.c b/src/python/grpcio/grpc/_adapter/_c/utility.c
index 2eea0e1..590f7e0 100644
--- a/src/python/grpcio/grpc/_adapter/_c/utility.c
+++ b/src/python/grpcio/grpc/_adapter/_c/utility.c
@@ -184,6 +184,7 @@
     return 0;
   }
   c_op.op = type;
+  c_op.reserved = NULL;
   c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX));
   if (PyErr_Occurred()) {
     return 0;
diff --git a/src/python/grpcio/grpc/early_adopter/implementations.py b/src/python/grpcio/grpc/early_adopter/implementations.py
index 10919fa..9c396aa 100644
--- a/src/python/grpcio/grpc/early_adopter/implementations.py
+++ b/src/python/grpcio/grpc/early_adopter/implementations.py
@@ -41,13 +41,15 @@
 from grpc.framework.face import implementations as _face_implementations
 from grpc.framework.foundation import logging_pool
 
-_THREAD_POOL_SIZE = 8
+_DEFAULT_THREAD_POOL_SIZE = 8
 _ONE_DAY_IN_SECONDS = 24 * 60 * 60
 
 
 class _Server(interfaces.Server):
 
-  def __init__(self, breakdown, port, private_key, certificate_chain):
+  def __init__(
+        self, breakdown, port, private_key, certificate_chain,
+        thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
     self._lock = threading.Lock()
     self._breakdown = breakdown
     self._port = port
@@ -56,6 +58,7 @@
     else:
       self._key_chain_pairs = ((private_key, certificate_chain),)
 
+    self._pool_size = thread_pool_size
     self._pool = None
     self._back = None
     self._fore_link = None
@@ -63,7 +66,7 @@
   def _start(self):
     with self._lock:
       if self._pool is None:
-        self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+        self._pool = logging_pool.pool(self._pool_size)
         servicer = _face_implementations.servicer(
             self._pool, self._breakdown.implementations, None)
         self._back = _base_implementations.back_link(
@@ -114,7 +117,8 @@
 
   def __init__(
       self, breakdown, host, port, secure, root_certificates, private_key,
-      certificate_chain, metadata_transformer=None, server_host_override=None):
+      certificate_chain, metadata_transformer=None, server_host_override=None,
+      thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
     self._lock = threading.Lock()
     self._breakdown = breakdown
     self._host = host
@@ -126,6 +130,7 @@
     self._metadata_transformer = metadata_transformer
     self._server_host_override = server_host_override
 
+    self._pool_size = thread_pool_size
     self._pool = None
     self._front = None
     self._rear_link = None
@@ -134,7 +139,7 @@
   def __enter__(self):
     with self._lock:
       if self._pool is None:
-        self._pool = logging_pool.pool(_THREAD_POOL_SIZE)
+        self._pool = logging_pool.pool(self._pool_size)
         self._front = _base_implementations.front_link(
             self._pool, self._pool, self._pool)
         self._rear_link = _rear.RearLink(
@@ -193,7 +198,7 @@
 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):
+    server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
   """Constructs an interfaces.Stub.
 
   Args:
@@ -216,6 +221,8 @@
       certificate chain should be used.
     server_host_override: (For testing only) the target name used for SSL
       host name checking.
+    thread_pool_size: The maximum number of threads to allow in the backing
+      thread pool.
 
   Returns:
     An interfaces.Stub affording RPC invocation.
@@ -224,11 +231,13 @@
   return _Stub(
       breakdown, host, port, secure, root_certificates, private_key,
       certificate_chain, server_host_override=server_host_override,
-      metadata_transformer=metadata_transformer)
+      metadata_transformer=metadata_transformer,
+      thread_pool_size=thread_pool_size)
 
 
 def server(
-    service_name, methods, port, private_key=None, certificate_chain=None):
+    service_name, methods, port, private_key=None, certificate_chain=None,
+    thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
   """Constructs an interfaces.Server.
 
   Args:
@@ -242,9 +251,12 @@
     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.
+    thread_pool_size: The maximum number of threads to allow in the backing
+      thread pool.
 
   Returns:
     An interfaces.Server that will serve secure traffic.
   """
   breakdown = _face_utilities.break_down_service(service_name, methods)
-  return _Server(breakdown, port, private_key, certificate_chain)
+  return _Server(breakdown, port, private_key, certificate_chain,
+      thread_pool_size=thread_pool_size)
diff --git a/src/ruby/README.md b/src/ruby/README.md
index 4b657c0..f8902e3 100644
--- a/src/ruby/README.md
+++ b/src/ruby/README.md
@@ -12,12 +12,36 @@
 -------------
 
 - Ruby 2.x. The gRPC API uses keyword args.
-- [homebrew][] on Mac OS X, [linuxbrew][] on Linux.  These simplify the installation of the gRPC C core.
+- [homebrew][] on Mac OS X.  These simplify the installation of the gRPC C core.
 
 INSTALLATION
 ---------------
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
-Run the following command to install gRPC Ruby.
+
+**Linux (Debian):**
+
+Add [Debian unstable][] to your `sources.list` file. Example:
+
+```sh
+echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+sudo tee -a /etc/apt/sources.list
+```
+
+Install the gRPC Debian package
+
+```sh
+sudo apt-get update
+sudo apt-get install libgrpc-dev
+```
+
+Install the gRPC Ruby package
+
+```sh
+gem install grpc
+```
+
+**Mac OS X**
+
+Install [homebrew][]. Run the following command to install gRPC Ruby.
 ```sh
 $ curl -fsSL https://goo.gl/getgrpc | bash -s ruby
 ```
@@ -26,12 +50,6 @@
 BUILD FROM SOURCE
 ---------------------
 - Clone this repository
-- Build the gRPC C core
-E.g, from the root of the gRPC [Git repository](https://github.com/google/grpc)
-```sh
-$ cd ../..
-$ make && sudo make install
-```
 
 - Install Ruby 2.x. Consider doing this with [RVM](http://rvm.io), it's a nice way of controlling
   the exact ruby version that's used.
@@ -77,8 +95,8 @@
   GRPC.logger.info("Answer: #{resp.inspect}")
   ```
 [homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation
 [gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
 [ruby extensions]:http://guides.rubygems.org/gems-with-extensions/
 [rubydoc]: http://www.rubydoc.info/gems/grpc
 [grpc.io]: http://www.grpc.io/docs/installation/ruby.html
+[Debian unstable]:https://www.debian.org/releases/sid/
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index b09d4e2..36c6818 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -526,6 +526,7 @@
     };
     st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op);
     st->ops[st->op_num].flags = 0;
+    st->ops[st->op_num].reserved = NULL;
     st->op_num++;
   }
 }
diff --git a/src/ruby/lib/grpc/logconfig.rb b/src/ruby/lib/grpc/logconfig.rb
index 2bb7c86..6b442fe 100644
--- a/src/ruby/lib/grpc/logconfig.rb
+++ b/src/ruby/lib/grpc/logconfig.rb
@@ -54,5 +54,6 @@
     LOGGER = NoopLogger.new
   end
 
-  include DefaultLogger unless method_defined?(:logger)
+  # Inject the noop #logger if no module-level logger method has been injected.
+  extend DefaultLogger unless methods.include?(:logger)
 end
diff --git a/test/core/end2end/fixtures/proxy.c b/test/core/end2end/fixtures/proxy.c
index 8ae9e0e..0090cf4 100644
--- a/test/core/end2end/fixtures/proxy.c
+++ b/test/core/end2end/fixtures/proxy.c
@@ -174,6 +174,7 @@
   if (!pc->proxy->shutdown) {
     op.op = GRPC_OP_SEND_INITIAL_METADATA;
     op.flags = 0;
+    op.reserved = NULL;
     op.data.send_initial_metadata.count = pc->p2s_initial_metadata.count;
     op.data.send_initial_metadata.metadata = pc->p2s_initial_metadata.metadata;
     refpc(pc, "on_c2p_sent_initial_metadata");
@@ -201,6 +202,7 @@
   if (!pc->proxy->shutdown && success) {
     op.op = GRPC_OP_RECV_MESSAGE;
     op.flags = 0;
+    op.reserved = NULL;
     op.data.recv_message = &pc->c2p_msg;
     refpc(pc, "on_c2p_recv_msg");
     err = grpc_call_start_batch(pc->c2p, &op, 1,
@@ -225,6 +227,7 @@
     if (pc->c2p_msg != NULL) {
       op.op = GRPC_OP_SEND_MESSAGE;
       op.flags = 0;
+      op.reserved = NULL;
       op.data.send_message = pc->c2p_msg;
       refpc(pc, "on_p2s_sent_message");
       err = grpc_call_start_batch(pc->p2s, &op, 1,
@@ -233,6 +236,7 @@
     } else {
       op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
       op.flags = 0;
+      op.reserved = NULL;
       refpc(pc, "on_p2s_sent_close");
       err = grpc_call_start_batch(pc->p2s, &op, 1,
                                   new_closure(on_p2s_sent_close, pc), NULL);
@@ -254,6 +258,7 @@
   if (!pc->proxy->shutdown && success) {
     op.op = GRPC_OP_RECV_MESSAGE;
     op.flags = 0;
+    op.reserved = NULL;
     op.data.recv_message = &pc->p2s_msg;
     refpc(pc, "on_p2s_recv_msg");
     err = grpc_call_start_batch(pc->p2s, &op, 1,
@@ -272,6 +277,7 @@
   if (!pc->proxy->shutdown && success && pc->p2s_msg) {
     op.op = GRPC_OP_SEND_MESSAGE;
     op.flags = 0;
+    op.reserved = NULL;
     op.data.send_message = pc->p2s_msg;
     refpc(pc, "on_c2p_sent_message");
     err = grpc_call_start_batch(pc->c2p, &op, 1,
@@ -295,6 +301,7 @@
     GPR_ASSERT(success);
     op.op = GRPC_OP_SEND_STATUS_FROM_SERVER;
     op.flags = 0;
+    op.reserved = NULL;
     op.data.send_status_from_server.trailing_metadata_count =
         pc->p2s_trailing_metadata.count;
     op.data.send_status_from_server.trailing_metadata =
@@ -334,6 +341,7 @@
     gpr_ref_init(&pc->refs, 1);
 
     op.flags = 0;
+    op.reserved = NULL;
 
     op.op = GRPC_OP_RECV_INITIAL_METADATA;
     op.data.recv_initial_metadata = &pc->p2s_initial_metadata;
diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c
index 91330c7..97c19db 100644
--- a/test/core/end2end/tests/default_host.c
+++ b/test/core/end2end/tests/default_host.c
@@ -135,13 +135,16 @@
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_INITIAL_METADATA;
   op->data.recv_initial_metadata = &initial_metadata_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
   op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
@@ -149,6 +152,7 @@
   op->data.recv_status_on_client.status_details = &details;
   op->data.recv_status_on_client.status_details_capacity = &details_capacity;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
   GPR_ASSERT(error == GRPC_CALL_OK);
@@ -173,16 +177,19 @@
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
   op->data.send_status_from_server.trailing_metadata_count = 0;
   op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
   op->data.send_status_from_server.status_details = "xyz";
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
   op->data.recv_close_on_server.cancelled = &was_cancelled;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   error = grpc_call_start_batch(s, ops, op - ops, tag(102), NULL);
   GPR_ASSERT(error == GRPC_CALL_OK);
diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c
index 9bb3abb..d862274 100644
--- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c
+++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c
@@ -438,25 +438,31 @@
   op->data.recv_status_on_client.status_details = &details;
   op->data.recv_status_on_client.status_details_capacity = &details_capacity;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_INITIAL_METADATA;
   op->data.send_initial_metadata.count = 0;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_MESSAGE;
   op->data.send_message = request_payload;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_INITIAL_METADATA;
   op->data.recv_initial_metadata = &initial_metadata_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   op->op = GRPC_OP_RECV_MESSAGE;
   op->data.recv_message = &response_payload_recv;
   op->flags = 0;
+  op->reserved = NULL;
   op++;
   error = grpc_call_start_batch(c, ops, op - ops, tag(1), NULL);
   GPR_ASSERT(error == GRPC_CALL_OK);
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
index 65fdc63..da5627d 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -52,7 +52,6 @@
 #include "test/core/security/oauth2_utils.h"
 #include "test/cpp/util/create_test_channel.h"
 
-#include "src/core/surface/call.h"
 #include "src/cpp/client/secure_credentials.h"
 
 DECLARE_bool(enable_ssl);
@@ -65,8 +64,6 @@
 DECLARE_string(service_account_key_file);
 DECLARE_string(oauth_scope);
 
-using grpc::testing::CompressionType;
-
 namespace grpc {
 namespace testing {
 
@@ -143,32 +140,5 @@
   }
 }
 
-CompressionType GetInteropCompressionTypeFromCompressionAlgorithm(
-    grpc_compression_algorithm algorithm) {
-  switch (algorithm) {
-    case GRPC_COMPRESS_NONE:
-      return CompressionType::NONE;
-    case GRPC_COMPRESS_GZIP:
-      return CompressionType::GZIP;
-    case GRPC_COMPRESS_DEFLATE:
-      return CompressionType::DEFLATE;
-    default:
-      GPR_ASSERT(false);
-  }
-}
-
-InteropClientContextInspector::InteropClientContextInspector(
-    const ::grpc::ClientContext& context)
-    : context_(context) {}
-
-grpc_compression_algorithm
-InteropClientContextInspector::GetCallCompressionAlgorithm() const {
-  return grpc_call_get_compression_algorithm(context_.call_);
-}
-
-gpr_uint32 InteropClientContextInspector::GetMessageFlags() const {
-  return grpc_call_get_message_flags(context_.call_);
-}
-
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/interop/client_helper.h b/test/cpp/interop/client_helper.h
index 28fca32..edc69e9 100644
--- a/test/cpp/interop/client_helper.h
+++ b/test/cpp/interop/client_helper.h
@@ -39,7 +39,7 @@
 #include <grpc++/config.h>
 #include <grpc++/channel_interface.h>
 
-#include "test/proto/messages.grpc.pb.h"
+#include "src/core/surface/call.h"
 
 namespace grpc {
 namespace testing {
@@ -51,17 +51,19 @@
 std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
     const grpc::string& test_case);
 
-grpc::testing::CompressionType
-GetInteropCompressionTypeFromCompressionAlgorithm(
-    grpc_compression_algorithm algorithm);
-
 class InteropClientContextInspector {
  public:
-  InteropClientContextInspector(const ::grpc::ClientContext& context);
+  InteropClientContextInspector(const ::grpc::ClientContext& context)
+    : context_(context) {}
 
   // Inspector methods, able to peek inside ClientContext, follow.
-  grpc_compression_algorithm GetCallCompressionAlgorithm() const;
-  gpr_uint32 GetMessageFlags() const;
+  grpc_compression_algorithm GetCallCompressionAlgorithm() const {
+    return grpc_call_get_compression_algorithm(context_.call_);
+  }
+
+  gpr_uint32 GetMessageFlags() const {
+    return grpc_call_get_message_flags(context_.call_);
+  }
 
  private:
   const ::grpc::ClientContext& context_;
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index ddf91aa..5ed14d5 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -41,6 +41,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
 #include <grpc++/channel_interface.h>
 #include <grpc++/client_context.h>
 #include <grpc++/credentials.h>
@@ -67,6 +68,20 @@
 const int kReceiveDelayMilliSeconds = 20;
 const int kLargeRequestSize = 271828;
 const int kLargeResponseSize = 314159;
+
+CompressionType GetInteropCompressionTypeFromCompressionAlgorithm(
+    grpc_compression_algorithm algorithm) {
+  switch (algorithm) {
+    case GRPC_COMPRESS_NONE:
+      return CompressionType::NONE;
+    case GRPC_COMPRESS_GZIP:
+      return CompressionType::GZIP;
+    case GRPC_COMPRESS_DEFLATE:
+      return CompressionType::DEFLATE;
+    default:
+      GPR_ASSERT(false);
+  }
+}
 }  // namespace
 
 InteropClient::InteropClient(std::shared_ptr<ChannelInterface> channel)
@@ -257,18 +272,18 @@
 void InteropClient::DoLargeCompressedUnary() {
   const CompressionType compression_types[] = {NONE, GZIP, DEFLATE};
   const PayloadType payload_types[] = {COMPRESSABLE, UNCOMPRESSABLE, RANDOM};
-  for (const auto payload_type : payload_types) {
-    for (const auto compression_type : compression_types) {
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(payload_types); i++) {
+    for (size_t j = 0; j < GPR_ARRAY_SIZE(compression_types); j++) {
       char* log_suffix;
       gpr_asprintf(&log_suffix, "(compression=%s; payload=%s)",
-                   CompressionType_Name(compression_type).c_str(),
-                   PayloadType_Name(payload_type).c_str());
+                   CompressionType_Name(compression_types[j]).c_str(),
+                   PayloadType_Name(payload_types[i]).c_str());
 
       gpr_log(GPR_INFO, "Sending a large compressed unary rpc %s.", log_suffix);
       SimpleRequest request;
       SimpleResponse response;
-      request.set_response_type(payload_type);
-      request.set_response_compression(compression_type);
+      request.set_response_type(payload_types[i]);
+      request.set_response_compression(compression_types[j]);
       PerformLargeUnary(&request, &response);
       gpr_log(GPR_INFO, "Large compressed unary done %s.", log_suffix);
       gpr_free(log_suffix);
@@ -333,21 +348,21 @@
 
   const CompressionType compression_types[] = {NONE, GZIP, DEFLATE};
   const PayloadType payload_types[] = {COMPRESSABLE, UNCOMPRESSABLE, RANDOM};
-  for (const auto payload_type : payload_types) {
-    for (const auto compression_type : compression_types) {
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(payload_types); i++) {
+    for (size_t j = 0; j < GPR_ARRAY_SIZE(compression_types); j++) {
       ClientContext context;
       InteropClientContextInspector inspector(context);
       StreamingOutputCallRequest request;
 
       char* log_suffix;
       gpr_asprintf(&log_suffix, "(compression=%s; payload=%s)",
-                   CompressionType_Name(compression_type).c_str(),
-                   PayloadType_Name(payload_type).c_str());
+                   CompressionType_Name(compression_types[j]).c_str(),
+                   PayloadType_Name(payload_types[i]).c_str());
 
       gpr_log(GPR_INFO, "Receiving response steaming rpc %s.", log_suffix);
 
-      request.set_response_type(payload_type);
-      request.set_response_compression(compression_type);
+      request.set_response_type(payload_types[i]);
+      request.set_response_compression(compression_types[j]);
 
       for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
         ResponseParameters* response_parameter =
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 1a6752c..eaba699 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -143,7 +143,10 @@
         binary = 'vsprojects/test_bin/%s.exe' % (target['name'])
       else:
         binary = 'bins/%s/%s' % (config.build_config, target['name'])
-      out.append(config.job_spec([binary], [binary]))
+      if os.path.isfile(binary):
+        out.append(config.job_spec([binary], [binary]))
+      else:
+        print "\nWARNING: binary not found, skipping", binary
     return sorted(out)
 
   def make_targets(self):
@@ -482,12 +485,6 @@
                    for cfg in build_configs
                    for l in languages
                    for cmdline in l.build_steps()))
-one_run = set(
-    spec
-    for config in run_configs
-    for language in languages
-    for spec in language.test_specs(config, args.travis)
-    if re.search(args.regex, spec.shortname))
 
 runs_per_test = args.runs_per_test
 forever = args.forever
@@ -583,6 +580,12 @@
   _start_port_server(port_server_port)
   try:
     infinite_runs = runs_per_test == 0
+    one_run = set(
+      spec
+      for config in run_configs
+      for language in languages
+      for spec in language.test_specs(config, args.travis)
+      if re.search(args.regex, spec.shortname))
     # When running on travis, we want out test runs to be as similar as possible
     # for reproducibility purposes.
     if travis:
diff --git a/vsprojects/grpc.sln b/vsprojects/grpc.sln
index 0a9b5c2..42ddef4 100644
--- a/vsprojects/grpc.sln
+++ b/vsprojects/grpc.sln
@@ -52,15 +52,6 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_zookeeper", "grpc_zookeeper\grpc_zookeeper.vcxproj", "{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}"
-	ProjectSection(myProperties) = preProject
-        	lib = "True"
-	EndProjectSection
-	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++", "grpc++\grpc++.vcxproj", "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
@@ -187,22 +178,6 @@
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release-DLL|Win32.Build.0 = Release-DLL|Win32
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release-DLL|x64.ActiveCfg = Release-DLL|x64
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release-DLL|x64.Build.0 = Release-DLL|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.ActiveCfg = Debug|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.ActiveCfg = Debug|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.ActiveCfg = Release|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.ActiveCfg = Release|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.Build.0 = Debug|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.Build.0 = Debug|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.Build.0 = Release|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.Build.0 = Release|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug-DLL|x64.Build.0 = Debug|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|Win32.Build.0 = Release|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|x64.ActiveCfg = Release|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release-DLL|x64.Build.0 = Release|x64
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Debug|Win32.ActiveCfg = Debug|Win32
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Debug|x64.ActiveCfg = Debug|x64
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/grpc_csharp_ext.sln b/vsprojects/grpc_csharp_ext.sln
index aa41d87..df84f3d 100644
--- a/vsprojects/grpc_csharp_ext.sln
+++ b/vsprojects/grpc_csharp_ext.sln
@@ -24,15 +24,6 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_zookeeper", "grpc_zookeeper\grpc_zookeeper.vcxproj", "{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}"
-	ProjectSection(myProperties) = preProject
-        	lib = "True"
-	EndProjectSection
-	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\grpc_csharp_ext.vcxproj", "{D64C6D63-4458-4A88-AB38-35678384A7E4}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
@@ -74,14 +65,6 @@
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|Win32.Build.0 = Release-DLL|Win32
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|x64.ActiveCfg = Release-DLL|x64
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}.Release|x64.Build.0 = Release-DLL|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.ActiveCfg = Debug|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|Win32.Build.0 = Debug|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.ActiveCfg = Debug|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Debug|x64.Build.0 = Debug|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.ActiveCfg = Release|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|Win32.Build.0 = Release|Win32
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.ActiveCfg = Release|x64
-		{F14EBEC1-DC43-45D3-8A7D-1A47072EFE50}.Release|x64.Build.0 = Release|x64
 		{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}.Debug|x64.ActiveCfg = Debug|x64