Merge pull request #9456 from jtattermusch/cmake_convenience_targets

Big improvements to CMake build
diff --git a/doc/environment_variables.md b/doc/environment_variables.md
index 832762a..2c83972 100644
--- a/doc/environment_variables.md
+++ b/doc/environment_variables.md
@@ -35,6 +35,7 @@
   A comma separated list of tracers that provide additional insight into how
   gRPC C core is processing requests via debug logs. Available tracers include:
   - api - traces api calls to the C core
+  - call_error - traces the possible errors contributing to final call status
   - channel - traces operations on the C core channel stack
   - combiner - traces combiner lock state
   - compression - traces compression operations
@@ -55,10 +56,10 @@
   - secure_endpoint - traces bytes flowing through encrypted channels
   - transport_security - traces metadata about secure channel establishment
   - tcp - traces bytes in and out of a channel
-  
+
   'all' can additionally be used to turn all traces on.
   Individual traces can be disabled by prefixing them with '-'.
- 
+
   Example:
   export GRPC_TRACE=all,-pending_tags
 
diff --git a/examples/csharp/helloworld/generate_protos.bat b/examples/csharp/helloworld/generate_protos.bat
index 28b7395..0afa129 100644
--- a/examples/csharp/helloworld/generate_protos.bat
+++ b/examples/csharp/helloworld/generate_protos.bat
@@ -34,7 +34,7 @@
 @rem enter this directory
 cd /d %~dp0
 
-set TOOLS_PATH=packages\Grpc.Tools.1.0.0\tools\windows_x86
+set TOOLS_PATH=packages\Grpc.Tools.1.0.1\tools\windows_x86
 
 %TOOLS_PATH%\protoc.exe -I../../protos --csharp_out Greeter  ../../protos/helloworld.proto --grpc_out Greeter --plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe
 
diff --git a/examples/php/composer.json b/examples/php/composer.json
index 3d1a95d..f0b9977 100644
--- a/examples/php/composer.json
+++ b/examples/php/composer.json
@@ -2,7 +2,11 @@
   "name": "grpc/grpc-demo",
   "description": "gRPC example for PHP",
   "require": {
-    "ext-grpc": "*",
-    "grpc/grpc": "v1.0.0"
+    "grpc/grpc": "v1.1.0"
+  },
+  "autoload": {
+    "psr-4": {
+      "": "route_guide/"
+    }
   }
 }
diff --git a/examples/php/greeter_client.php b/examples/php/greeter_client.php
index a5c0865..986a4bb 100644
--- a/examples/php/greeter_client.php
+++ b/examples/php/greeter_client.php
@@ -33,14 +33,18 @@
  */
 
 require dirname(__FILE__).'/vendor/autoload.php';
-require dirname(__FILE__).'/helloworld.php';
+
+// The following includes are needed when using protobuf 3.1.0
+// and will suppress warnings when using protobuf 3.2.0+
+@include_once dirname(__FILE__).'/helloworld.pb.php';
+@include_once dirname(__FILE__).'/helloworld_grpc_pb.php';
 
 function greet($name)
 {
-    $client = new helloworld\GreeterClient('localhost:50051', [
+    $client = new Helloworld\GreeterClient('localhost:50051', [
         'credentials' => Grpc\ChannelCredentials::createInsecure(),
     ]);
-    $request = new helloworld\HelloRequest();
+    $request = new Helloworld\HelloRequest();
     $request->setName($name);
     list($reply, $status) = $client->SayHello($request)->wait();
     $message = $reply->getMessage();
diff --git a/examples/php/helloworld.pb.php b/examples/php/helloworld.pb.php
new file mode 100644
index 0000000..757a4a5
--- /dev/null
+++ b/examples/php/helloworld.pb.php
@@ -0,0 +1,58 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: helloworld.proto
+
+namespace Helloworld;
+
+use Google\Protobuf\Internal\DescriptorPool;
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+class HelloRequest extends \Google\Protobuf\Internal\Message
+{
+    private $name = '';
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function setName($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->name = $var;
+    }
+
+}
+
+class HelloReply extends \Google\Protobuf\Internal\Message
+{
+    private $message = '';
+
+    public function getMessage()
+    {
+        return $this->message;
+    }
+
+    public function setMessage($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->message = $var;
+    }
+
+}
+
+$pool = DescriptorPool::getGeneratedPool();
+
+$pool->internalAddGeneratedFile(hex2bin(
+    "0ae6010a1068656c6c6f776f726c642e70726f746f120a68656c6c6f776f" .
+    "726c64221c0a0c48656c6c6f52657175657374120c0a046e616d65180120" .
+    "012809221d0a0a48656c6c6f5265706c79120f0a076d6573736167651801" .
+    "2001280932490a0747726565746572123e0a0853617948656c6c6f12182e" .
+    "68656c6c6f776f726c642e48656c6c6f526571756573741a162e68656c6c" .
+    "6f776f726c642e48656c6c6f5265706c79220042360a1b696f2e67727063" .
+    "2e6578616d706c65732e68656c6c6f776f726c64420f48656c6c6f576f72" .
+    "6c6450726f746f5001a20203484c57620670726f746f33"
+));
+
diff --git a/examples/php/helloworld.php b/examples/php/helloworld.php
deleted file mode 100644
index 697f52a..0000000
--- a/examples/php/helloworld.php
+++ /dev/null
@@ -1,168 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: helloworld.proto
-//   Date: 2015-09-24 20:40:14
-
-namespace helloworld {
-
-  class HelloRequest extends \DrSlump\Protobuf\Message
-  {
-      /**  @var string */
-    public $name = null;
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-      public static function descriptor()
-      {
-          $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'helloworld.HelloRequest');
-
-      // OPTIONAL STRING name = 1
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 1;
-          $f->name = 'name';
-          $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 <name> has a value.
-     *
-     * @return bool
-     */
-    public function hasName()
-    {
-        return $this->_has(1);
-    }
-
-    /**
-     * Clear <name> value.
-     *
-     * @return \helloworld\HelloRequest
-     */
-    public function clearName()
-    {
-        return $this->_clear(1);
-    }
-
-    /**
-     * Get <name> value.
-     *
-     * @return string
-     */
-    public function getName()
-    {
-        return $this->_get(1);
-    }
-
-    /**
-     * Set <name> value.
-     *
-     * @param string $value
-     *
-     * @return \helloworld\HelloRequest
-     */
-    public function setName($value)
-    {
-        return $this->_set(1, $value);
-    }
-  }
-}
-
-namespace helloworld {
-
-  class HelloReply extends \DrSlump\Protobuf\Message
-  {
-      /**  @var string */
-    public $message = null;
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-      public static function descriptor()
-      {
-          $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'helloworld.HelloReply');
-
-      // OPTIONAL STRING message = 1
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 1;
-          $f->name = 'message';
-          $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 <message> has a value.
-     *
-     * @return bool
-     */
-    public function hasMessage()
-    {
-        return $this->_has(1);
-    }
-
-    /**
-     * Clear <message> value.
-     *
-     * @return \helloworld\HelloReply
-     */
-    public function clearMessage()
-    {
-        return $this->_clear(1);
-    }
-
-    /**
-     * Get <message> value.
-     *
-     * @return string
-     */
-    public function getMessage()
-    {
-        return $this->_get(1);
-    }
-
-    /**
-     * Set <message> value.
-     *
-     * @param string $value
-     *
-     * @return \helloworld\HelloReply
-     */
-    public function setMessage($value)
-    {
-        return $this->_set(1, $value);
-    }
-  }
-}
-
-namespace helloworld {
-
-  class GreeterClient extends \Grpc\BaseStub
-  {
-      public function __construct($hostname, $opts)
-      {
-          parent::__construct($hostname, $opts);
-      }
-    /**
-     * @param helloworld\HelloRequest $input
-     */
-    public function SayHello(\helloworld\HelloRequest $argument, $metadata = array(), $options = array())
-    {
-        return $this->_simpleRequest('/helloworld.Greeter/SayHello', $argument, '\helloworld\HelloReply::deserialize', $metadata, $options);
-    }
-  }
-}
diff --git a/examples/php/helloworld.proto b/examples/php/helloworld_grpc_pb.php
similarity index 62%
copy from examples/php/helloworld.proto
copy to examples/php/helloworld_grpc_pb.php
index ad8f7a1..cae48bc 100644
--- a/examples/php/helloworld.proto
+++ b/examples/php/helloworld_grpc_pb.php
@@ -1,3 +1,7 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
 // Copyright 2015, Google Inc.
 // All rights reserved.
 //
@@ -26,25 +30,35 @@
 // 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 Helloworld {
 
-syntax = "proto2";
+  // The greeting service definition.
+  class GreeterClient extends \Grpc\BaseStub {
 
-option java_package = "ex.grpc";
+    /**
+     * @param string $hostname hostname
+     * @param array $opts channel options
+     * @param Grpc\Channel $channel (optional) re-use channel object
+     */
+    public function __construct($hostname, $opts, $channel = null) {
+      parent::__construct($hostname, $opts, $channel);
+    }
 
-package helloworld;
+    /**
+     * Sends a greeting
+     * @param \Helloworld\HelloRequest $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function SayHello(\Helloworld\HelloRequest $argument,
+      $metadata = [], $options = []) {
+      return $this->_simpleRequest('/helloworld.Greeter/SayHello',
+      $argument,
+      ['\Helloworld\HelloReply', 'decode'],
+      $metadata, $options);
+    }
 
-// The greeting service definition.
-service Greeter {
-  // Sends a greeting
-  rpc SayHello (HelloRequest) returns (HelloReply) {}
-}
+  }
 
-// The request message containing the user's name.
-message HelloRequest {
-  optional string name = 1;
-}
-
-// The response message containing the greetings
-message HelloReply {
-  optional string message = 1;
 }
diff --git a/examples/php/route_guide/route_guide.pb.php b/examples/php/route_guide/route_guide.pb.php
new file mode 100644
index 0000000..78f3ea6
--- /dev/null
+++ b/examples/php/route_guide/route_guide.pb.php
@@ -0,0 +1,209 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: route_guide.proto
+
+namespace Routeguide;
+
+use Google\Protobuf\Internal\DescriptorPool;
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+class Point extends \Google\Protobuf\Internal\Message
+{
+    private $latitude = 0;
+    private $longitude = 0;
+
+    public function getLatitude()
+    {
+        return $this->latitude;
+    }
+
+    public function setLatitude($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->latitude = $var;
+    }
+
+    public function getLongitude()
+    {
+        return $this->longitude;
+    }
+
+    public function setLongitude($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->longitude = $var;
+    }
+
+}
+
+class Rectangle extends \Google\Protobuf\Internal\Message
+{
+    private $lo = null;
+    private $hi = null;
+
+    public function getLo()
+    {
+        return $this->lo;
+    }
+
+    public function setLo(&$var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->lo = $var;
+    }
+
+    public function getHi()
+    {
+        return $this->hi;
+    }
+
+    public function setHi(&$var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->hi = $var;
+    }
+
+}
+
+class Feature extends \Google\Protobuf\Internal\Message
+{
+    private $name = '';
+    private $location = null;
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function setName($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->name = $var;
+    }
+
+    public function getLocation()
+    {
+        return $this->location;
+    }
+
+    public function setLocation(&$var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->location = $var;
+    }
+
+}
+
+class RouteNote extends \Google\Protobuf\Internal\Message
+{
+    private $location = null;
+    private $message = '';
+
+    public function getLocation()
+    {
+        return $this->location;
+    }
+
+    public function setLocation(&$var)
+    {
+        GPBUtil::checkMessage($var, \Routeguide\Point::class);
+        $this->location = $var;
+    }
+
+    public function getMessage()
+    {
+        return $this->message;
+    }
+
+    public function setMessage($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->message = $var;
+    }
+
+}
+
+class RouteSummary extends \Google\Protobuf\Internal\Message
+{
+    private $point_count = 0;
+    private $feature_count = 0;
+    private $distance = 0;
+    private $elapsed_time = 0;
+
+    public function getPointCount()
+    {
+        return $this->point_count;
+    }
+
+    public function setPointCount($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->point_count = $var;
+    }
+
+    public function getFeatureCount()
+    {
+        return $this->feature_count;
+    }
+
+    public function setFeatureCount($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->feature_count = $var;
+    }
+
+    public function getDistance()
+    {
+        return $this->distance;
+    }
+
+    public function setDistance($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->distance = $var;
+    }
+
+    public function getElapsedTime()
+    {
+        return $this->elapsed_time;
+    }
+
+    public function setElapsedTime($var)
+    {
+        GPBUtil::checkInt32($var);
+        $this->elapsed_time = $var;
+    }
+
+}
+
+$pool = DescriptorPool::getGeneratedPool();
+
+$pool->internalAddGeneratedFile(hex2bin(
+    "0ac5050a11726f7574655f67756964652e70726f746f120a726f75746567" .
+    "75696465222c0a05506f696e7412100a086c617469747564651801200128" .
+    "0512110a096c6f6e67697475646518022001280522490a0952656374616e" .
+    "676c65121d0a026c6f18012001280b32112e726f75746567756964652e50" .
+    "6f696e74121d0a02686918022001280b32112e726f75746567756964652e" .
+    "506f696e74223c0a0746656174757265120c0a046e616d65180120012809" .
+    "12230a086c6f636174696f6e18022001280b32112e726f75746567756964" .
+    "652e506f696e7422410a09526f7574654e6f746512230a086c6f63617469" .
+    "6f6e18012001280b32112e726f75746567756964652e506f696e74120f0a" .
+    "076d65737361676518022001280922620a0c526f75746553756d6d617279" .
+    "12130a0b706f696e745f636f756e7418012001280512150a0d6665617475" .
+    "72655f636f756e7418022001280512100a0864697374616e636518032001" .
+    "280512140a0c656c61707365645f74696d651804200128053285020a0a52" .
+    "6f757465477569646512360a0a4765744665617475726512112e726f7574" .
+    "6567756964652e506f696e741a132e726f75746567756964652e46656174" .
+    "7572652200123e0a0c4c697374466561747572657312152e726f75746567" .
+    "756964652e52656374616e676c651a132e726f75746567756964652e4665" .
+    "617475726522003001123e0a0b5265636f7264526f75746512112e726f75" .
+    "746567756964652e506f696e741a182e726f75746567756964652e526f75" .
+    "746553756d6d61727922002801123f0a09526f7574654368617412152e72" .
+    "6f75746567756964652e526f7574654e6f74651a152e726f757465677569" .
+    "64652e526f7574654e6f746522002801300142360a1b696f2e677270632e" .
+    "6578616d706c65732e726f7574656775696465420f526f75746547756964" .
+    "6550726f746f5001a20203525447620670726f746f33"
+));
+
diff --git a/examples/php/route_guide/route_guide.php b/examples/php/route_guide/route_guide.php
deleted file mode 100644
index 65045d0..0000000
--- a/examples/php/route_guide/route_guide.php
+++ /dev/null
@@ -1,789 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: route_guide.proto
-//   Date: 2015-09-24 21:21:51
-
-namespace routeguide {
-
-  class Point extends \DrSlump\Protobuf\Message
-  {
-      /**  @var int */
-    public $latitude = 0;
-
-    /**  @var int */
-    public $longitude = 0;
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-      public static function descriptor()
-      {
-          $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'routeguide.Point');
-
-      // OPTIONAL INT32 latitude = 1
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 1;
-          $f->name = 'latitude';
-          $f->type = \DrSlump\Protobuf::TYPE_INT32;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->default = 0;
-          $descriptor->addField($f);
-
-      // OPTIONAL INT32 longitude = 2
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 2;
-          $f->name = 'longitude';
-          $f->type = \DrSlump\Protobuf::TYPE_INT32;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->default = 0;
-          $descriptor->addField($f);
-
-          foreach (self::$__extensions as $cb) {
-              $descriptor->addField($cb(), true);
-          }
-
-          return $descriptor;
-      }
-
-    /**
-     * Check if <latitude> has a value.
-     *
-     * @return bool
-     */
-    public function hasLatitude()
-    {
-        return $this->_has(1);
-    }
-
-    /**
-     * Clear <latitude> value.
-     *
-     * @return \routeguide\Point
-     */
-    public function clearLatitude()
-    {
-        return $this->_clear(1);
-    }
-
-    /**
-     * Get <latitude> value.
-     *
-     * @return int
-     */
-    public function getLatitude()
-    {
-        return $this->_get(1);
-    }
-
-    /**
-     * Set <latitude> value.
-     *
-     * @param int $value
-     *
-     * @return \routeguide\Point
-     */
-    public function setLatitude($value)
-    {
-        return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <longitude> has a value.
-     *
-     * @return bool
-     */
-    public function hasLongitude()
-    {
-        return $this->_has(2);
-    }
-
-    /**
-     * Clear <longitude> value.
-     *
-     * @return \routeguide\Point
-     */
-    public function clearLongitude()
-    {
-        return $this->_clear(2);
-    }
-
-    /**
-     * Get <longitude> value.
-     *
-     * @return int
-     */
-    public function getLongitude()
-    {
-        return $this->_get(2);
-    }
-
-    /**
-     * Set <longitude> value.
-     *
-     * @param int $value
-     *
-     * @return \routeguide\Point
-     */
-    public function setLongitude($value)
-    {
-        return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace routeguide {
-
-  class Rectangle extends \DrSlump\Protobuf\Message
-  {
-      /**  @var \routeguide\Point */
-    public $lo = null;
-
-    /**  @var \routeguide\Point */
-    public $hi = null;
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-      public static function descriptor()
-      {
-          $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'routeguide.Rectangle');
-
-      // OPTIONAL MESSAGE lo = 1
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 1;
-          $f->name = 'lo';
-          $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->reference = '\routeguide\Point';
-          $descriptor->addField($f);
-
-      // OPTIONAL MESSAGE hi = 2
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 2;
-          $f->name = 'hi';
-          $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->reference = '\routeguide\Point';
-          $descriptor->addField($f);
-
-          foreach (self::$__extensions as $cb) {
-              $descriptor->addField($cb(), true);
-          }
-
-          return $descriptor;
-      }
-
-    /**
-     * Check if <lo> has a value.
-     *
-     * @return bool
-     */
-    public function hasLo()
-    {
-        return $this->_has(1);
-    }
-
-    /**
-     * Clear <lo> value.
-     *
-     * @return \routeguide\Rectangle
-     */
-    public function clearLo()
-    {
-        return $this->_clear(1);
-    }
-
-    /**
-     * Get <lo> value.
-     *
-     * @return \routeguide\Point
-     */
-    public function getLo()
-    {
-        return $this->_get(1);
-    }
-
-    /**
-     * Set <lo> value.
-     *
-     * @param \routeguide\Point $value
-     *
-     * @return \routeguide\Rectangle
-     */
-    public function setLo(\routeguide\Point $value)
-    {
-        return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <hi> has a value.
-     *
-     * @return bool
-     */
-    public function hasHi()
-    {
-        return $this->_has(2);
-    }
-
-    /**
-     * Clear <hi> value.
-     *
-     * @return \routeguide\Rectangle
-     */
-    public function clearHi()
-    {
-        return $this->_clear(2);
-    }
-
-    /**
-     * Get <hi> value.
-     *
-     * @return \routeguide\Point
-     */
-    public function getHi()
-    {
-        return $this->_get(2);
-    }
-
-    /**
-     * Set <hi> value.
-     *
-     * @param \routeguide\Point $value
-     *
-     * @return \routeguide\Rectangle
-     */
-    public function setHi(\routeguide\Point $value)
-    {
-        return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace routeguide {
-
-  class Feature extends \DrSlump\Protobuf\Message
-  {
-      /**  @var string */
-    public $name = null;
-
-    /**  @var \routeguide\Point */
-    public $location = null;
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-      public static function descriptor()
-      {
-          $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'routeguide.Feature');
-
-      // OPTIONAL STRING name = 1
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 1;
-          $f->name = 'name';
-          $f->type = \DrSlump\Protobuf::TYPE_STRING;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $descriptor->addField($f);
-
-      // OPTIONAL MESSAGE location = 2
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 2;
-          $f->name = 'location';
-          $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->reference = '\routeguide\Point';
-          $descriptor->addField($f);
-
-          foreach (self::$__extensions as $cb) {
-              $descriptor->addField($cb(), true);
-          }
-
-          return $descriptor;
-      }
-
-    /**
-     * Check if <name> has a value.
-     *
-     * @return bool
-     */
-    public function hasName()
-    {
-        return $this->_has(1);
-    }
-
-    /**
-     * Clear <name> value.
-     *
-     * @return \routeguide\Feature
-     */
-    public function clearName()
-    {
-        return $this->_clear(1);
-    }
-
-    /**
-     * Get <name> value.
-     *
-     * @return string
-     */
-    public function getName()
-    {
-        return $this->_get(1);
-    }
-
-    /**
-     * Set <name> value.
-     *
-     * @param string $value
-     *
-     * @return \routeguide\Feature
-     */
-    public function setName($value)
-    {
-        return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <location> has a value.
-     *
-     * @return bool
-     */
-    public function hasLocation()
-    {
-        return $this->_has(2);
-    }
-
-    /**
-     * Clear <location> value.
-     *
-     * @return \routeguide\Feature
-     */
-    public function clearLocation()
-    {
-        return $this->_clear(2);
-    }
-
-    /**
-     * Get <location> value.
-     *
-     * @return \routeguide\Point
-     */
-    public function getLocation()
-    {
-        return $this->_get(2);
-    }
-
-    /**
-     * Set <location> value.
-     *
-     * @param \routeguide\Point $value
-     *
-     * @return \routeguide\Feature
-     */
-    public function setLocation(\routeguide\Point $value)
-    {
-        return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace routeguide {
-
-  class RouteNote extends \DrSlump\Protobuf\Message
-  {
-      /**  @var \routeguide\Point */
-    public $location = null;
-
-    /**  @var string */
-    public $message = null;
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-      public static function descriptor()
-      {
-          $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'routeguide.RouteNote');
-
-      // OPTIONAL MESSAGE location = 1
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 1;
-          $f->name = 'location';
-          $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->reference = '\routeguide\Point';
-          $descriptor->addField($f);
-
-      // OPTIONAL STRING message = 2
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 2;
-          $f->name = 'message';
-          $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 <location> has a value.
-     *
-     * @return bool
-     */
-    public function hasLocation()
-    {
-        return $this->_has(1);
-    }
-
-    /**
-     * Clear <location> value.
-     *
-     * @return \routeguide\RouteNote
-     */
-    public function clearLocation()
-    {
-        return $this->_clear(1);
-    }
-
-    /**
-     * Get <location> value.
-     *
-     * @return \routeguide\Point
-     */
-    public function getLocation()
-    {
-        return $this->_get(1);
-    }
-
-    /**
-     * Set <location> value.
-     *
-     * @param \routeguide\Point $value
-     *
-     * @return \routeguide\RouteNote
-     */
-    public function setLocation(\routeguide\Point $value)
-    {
-        return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <message> has a value.
-     *
-     * @return bool
-     */
-    public function hasMessage()
-    {
-        return $this->_has(2);
-    }
-
-    /**
-     * Clear <message> value.
-     *
-     * @return \routeguide\RouteNote
-     */
-    public function clearMessage()
-    {
-        return $this->_clear(2);
-    }
-
-    /**
-     * Get <message> value.
-     *
-     * @return string
-     */
-    public function getMessage()
-    {
-        return $this->_get(2);
-    }
-
-    /**
-     * Set <message> value.
-     *
-     * @param string $value
-     *
-     * @return \routeguide\RouteNote
-     */
-    public function setMessage($value)
-    {
-        return $this->_set(2, $value);
-    }
-  }
-}
-
-namespace routeguide {
-
-  class RouteSummary extends \DrSlump\Protobuf\Message
-  {
-      /**  @var int */
-    public $point_count = 0;
-
-    /**  @var int */
-    public $feature_count = 0;
-
-    /**  @var int */
-    public $distance = 0;
-
-    /**  @var int */
-    public $elapsed_time = 0;
-
-    /** @var \Closure[] */
-    protected static $__extensions = array();
-
-      public static function descriptor()
-      {
-          $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'routeguide.RouteSummary');
-
-      // OPTIONAL INT32 point_count = 1
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 1;
-          $f->name = 'point_count';
-          $f->type = \DrSlump\Protobuf::TYPE_INT32;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->default = 0;
-          $descriptor->addField($f);
-
-      // OPTIONAL INT32 feature_count = 2
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 2;
-          $f->name = 'feature_count';
-          $f->type = \DrSlump\Protobuf::TYPE_INT32;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->default = 0;
-          $descriptor->addField($f);
-
-      // OPTIONAL INT32 distance = 3
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 3;
-          $f->name = 'distance';
-          $f->type = \DrSlump\Protobuf::TYPE_INT32;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->default = 0;
-          $descriptor->addField($f);
-
-      // OPTIONAL INT32 elapsed_time = 4
-      $f = new \DrSlump\Protobuf\Field();
-          $f->number = 4;
-          $f->name = 'elapsed_time';
-          $f->type = \DrSlump\Protobuf::TYPE_INT32;
-          $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
-          $f->default = 0;
-          $descriptor->addField($f);
-
-          foreach (self::$__extensions as $cb) {
-              $descriptor->addField($cb(), true);
-          }
-
-          return $descriptor;
-      }
-
-    /**
-     * Check if <point_count> has a value.
-     *
-     * @return bool
-     */
-    public function hasPointCount()
-    {
-        return $this->_has(1);
-    }
-
-    /**
-     * Clear <point_count> value.
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function clearPointCount()
-    {
-        return $this->_clear(1);
-    }
-
-    /**
-     * Get <point_count> value.
-     *
-     * @return int
-     */
-    public function getPointCount()
-    {
-        return $this->_get(1);
-    }
-
-    /**
-     * Set <point_count> value.
-     *
-     * @param int $value
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function setPointCount($value)
-    {
-        return $this->_set(1, $value);
-    }
-
-    /**
-     * Check if <feature_count> has a value.
-     *
-     * @return bool
-     */
-    public function hasFeatureCount()
-    {
-        return $this->_has(2);
-    }
-
-    /**
-     * Clear <feature_count> value.
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function clearFeatureCount()
-    {
-        return $this->_clear(2);
-    }
-
-    /**
-     * Get <feature_count> value.
-     *
-     * @return int
-     */
-    public function getFeatureCount()
-    {
-        return $this->_get(2);
-    }
-
-    /**
-     * Set <feature_count> value.
-     *
-     * @param int $value
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function setFeatureCount($value)
-    {
-        return $this->_set(2, $value);
-    }
-
-    /**
-     * Check if <distance> has a value.
-     *
-     * @return bool
-     */
-    public function hasDistance()
-    {
-        return $this->_has(3);
-    }
-
-    /**
-     * Clear <distance> value.
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function clearDistance()
-    {
-        return $this->_clear(3);
-    }
-
-    /**
-     * Get <distance> value.
-     *
-     * @return int
-     */
-    public function getDistance()
-    {
-        return $this->_get(3);
-    }
-
-    /**
-     * Set <distance> value.
-     *
-     * @param int $value
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function setDistance($value)
-    {
-        return $this->_set(3, $value);
-    }
-
-    /**
-     * Check if <elapsed_time> has a value.
-     *
-     * @return bool
-     */
-    public function hasElapsedTime()
-    {
-        return $this->_has(4);
-    }
-
-    /**
-     * Clear <elapsed_time> value.
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function clearElapsedTime()
-    {
-        return $this->_clear(4);
-    }
-
-    /**
-     * Get <elapsed_time> value.
-     *
-     * @return int
-     */
-    public function getElapsedTime()
-    {
-        return $this->_get(4);
-    }
-
-    /**
-     * Set <elapsed_time> value.
-     *
-     * @param int $value
-     *
-     * @return \routeguide\RouteSummary
-     */
-    public function setElapsedTime($value)
-    {
-        return $this->_set(4, $value);
-    }
-  }
-}
-
-namespace routeguide {
-
-  class RouteGuideClient extends \Grpc\BaseStub
-  {
-      public function __construct($hostname, $opts)
-      {
-          parent::__construct($hostname, $opts);
-      }
-    /**
-     * @param routeguide\Point $input
-     */
-    public function GetFeature(\routeguide\Point $argument, $metadata = array(), $options = array())
-    {
-        return $this->_simpleRequest('/routeguide.RouteGuide/GetFeature', $argument, '\routeguide\Feature::deserialize', $metadata, $options);
-    }
-    /**
-     * @param routeguide\Rectangle $input
-     */
-    public function ListFeatures($argument, $metadata = array(), $options = array())
-    {
-        return $this->_serverStreamRequest('/routeguide.RouteGuide/ListFeatures', $argument, '\routeguide\Feature::deserialize', $metadata, $options);
-    }
-    /**
-     * @param routeguide\Point $input
-     */
-    public function RecordRoute($metadata = array())
-    {
-        return $this->_clientStreamRequest('/routeguide.RouteGuide/RecordRoute', '\routeguide\RouteSummary::deserialize', $metadata);
-    }
-    /**
-     * @param routeguide\RouteNote $input
-     */
-    public function RouteChat($metadata = array())
-    {
-        return $this->_bidiRequest('/routeguide.RouteGuide/RouteChat', '\routeguide\RouteNote::deserialize', $metadata);
-    }
-  }
-}
diff --git a/examples/php/route_guide/route_guide.proto b/examples/php/route_guide/route_guide.proto
deleted file mode 100644
index d50f8a5..0000000
--- a/examples/php/route_guide/route_guide.proto
+++ /dev/null
@@ -1,120 +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.
-
-syntax = "proto2";
-
-option java_package = "io.grpc.examples";
-
-package routeguide;
-
-// Interface exported by the server.
-service RouteGuide {
-  // A simple RPC.
-  //
-  // Obtains the feature at a given position.
-  rpc GetFeature(Point) returns (Feature) {}
-
-  // A server-to-client streaming RPC.
-  //
-  // Obtains the Features available within the given Rectangle.  Results are
-  // streamed rather than returned at once (e.g. in a response message with a
-  // repeated field), as the rectangle may cover a large area and contain a
-  // huge number of features.
-  rpc ListFeatures(Rectangle) returns (stream Feature) {}
-
-  // A client-to-server streaming RPC.
-  //
-  // Accepts a stream of Points on a route being traversed, returning a
-  // RouteSummary when traversal is completed.
-  rpc RecordRoute(stream Point) returns (RouteSummary) {}
-
-  // A Bidirectional streaming RPC.
-  //
-  // Accepts a stream of RouteNotes sent while a route is being traversed,
-  // while receiving other RouteNotes (e.g. from other users).
-  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
-}
-
-// Points are represented as latitude-longitude pairs in the E7 representation
-// (degrees multiplied by 10**7 and rounded to the nearest integer).
-// Latitudes should be in the range +/- 90 degrees and longitude should be in
-// the range +/- 180 degrees (inclusive).
-message Point {
-  optional int32 latitude = 1 [default = 0];
-  optional int32 longitude = 2 [default = 0];
-}
-
-// A latitude-longitude rectangle, represented as two diagonally opposite
-// points "lo" and "hi".
-message Rectangle {
-  // One corner of the rectangle.
-  optional Point lo = 1;
-
-  // The other corner of the rectangle.
-  optional Point hi = 2;
-}
-
-// A feature names something at a given point.
-//
-// If a feature could not be named, the name is empty.
-message Feature {
-  // The name of the feature.
-  optional string name = 1;
-
-  // The point where the feature is detected.
-  optional Point location = 2;
-}
-
-// A RouteNote is a message sent while at a given point.
-message RouteNote {
-  // The location from which the message is sent.
-  optional Point location = 1;
-
-  // The message to be sent.
-  optional string message = 2;
-}
-
-// A RouteSummary is received in response to a RecordRoute rpc.
-//
-// It contains the number of individual points received, the number of
-// detected features, and the total distance covered as the cumulative sum of
-// the distance between each point.
-message RouteSummary {
-  // The number of points received.
-  optional int32 point_count = 1 [default = 0];
-
-  // The number of known features passed while traversing the route.
-  optional int32 feature_count = 2 [default = 0];
-
-  // The distance covered in metres.
-  optional int32 distance = 3 [default = 0];
-
-  // The duration of the traversal in seconds.
-  optional int32 elapsed_time = 4 [default = 0];
-}
diff --git a/examples/php/route_guide/route_guide_client.php b/examples/php/route_guide/route_guide_client.php
index b3cd606..3f38c26 100644
--- a/examples/php/route_guide/route_guide_client.php
+++ b/examples/php/route_guide/route_guide_client.php
@@ -33,11 +33,15 @@
  */
 
 require dirname(__FILE__).'/../vendor/autoload.php';
-require dirname(__FILE__).'/route_guide.php';
+
+// The following includes are needed when using protobuf 3.1.0
+// and will suppress warnings when using protobuf 3.2.0+
+@include_once dirname(__FILE__).'/route_guide.pb.php';
+@include_once dirname(__FILE__).'/route_guide_grpc_pb.php';
 
 define('COORD_FACTOR', 1e7);
 
-$client = new routeguide\RouteGuideClient('localhost:50051', [
+$client = new Routeguide\RouteGuideClient('localhost:50051', [
     'credentials' => Grpc\ChannelCredentials::createInsecure(),
 ]);
 
@@ -63,7 +67,7 @@
     echo "Running GetFeature...\n";
     global $client;
 
-    $point = new routeguide\Point();
+    $point = new Routeguide\Point();
     $points = array(
         array(409146138, -746188906),
         array(0, 0),
@@ -88,15 +92,15 @@
     echo "Running ListFeatures...\n";
     global $client;
 
-    $lo_point = new routeguide\Point();
-    $hi_point = new routeguide\Point();
+    $lo_point = new Routeguide\Point();
+    $hi_point = new Routeguide\Point();
 
     $lo_point->setLatitude(400000000);
     $lo_point->setLongitude(-750000000);
     $hi_point->setLatitude(420000000);
     $hi_point->setLongitude(-730000000);
 
-    $rectangle = new routeguide\Rectangle();
+    $rectangle = new Routeguide\Rectangle();
     $rectangle->setLo($lo_point);
     $rectangle->setHi($hi_point);
 
@@ -126,7 +130,7 @@
     $num_points_in_db = count($db);
     $num_points = 10;
     for ($i = 0; $i < $num_points; ++$i) {
-        $point = new routeguide\Point();
+        $point = new Routeguide\Point();
         $index = rand(0, $num_points_in_db - 1);
         $lat = $db[$index]['location']['latitude'];
         $long = $db[$index]['location']['longitude'];
@@ -169,11 +173,11 @@
     );
 
     foreach ($notes as $n) {
-        $point = new routeguide\Point();
+        $point = new Routeguide\Point();
         $point->setLatitude($lat = $n[0]);
         $point->setLongitude($long = $n[1]);
 
-        $route_note = new routeguide\RouteNote();
+        $route_note = new Routeguide\RouteNote();
         $route_note->setLocation($point);
         $route_note->setMessage($message = $n[2]);
 
diff --git a/examples/php/route_guide/route_guide_grpc_pb.php b/examples/php/route_guide/route_guide_grpc_pb.php
new file mode 100644
index 0000000..fdc55e6
--- /dev/null
+++ b/examples/php/route_guide/route_guide_grpc_pb.php
@@ -0,0 +1,116 @@
+<?php
+// GENERATED CODE -- DO NOT EDIT!
+
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+namespace Routeguide {
+
+  // Interface exported by the server.
+  class RouteGuideClient extends \Grpc\BaseStub {
+
+    /**
+     * @param string $hostname hostname
+     * @param array $opts channel options
+     * @param Grpc\Channel $channel (optional) re-use channel object
+     */
+    public function __construct($hostname, $opts, $channel = null) {
+      parent::__construct($hostname, $opts, $channel);
+    }
+
+    /**
+     * A simple RPC.
+     *
+     * Obtains the feature at a given position.
+     *
+     * A feature with an empty name is returned if there's no feature at the given
+     * position.
+     * @param \Routeguide\Point $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function GetFeature(\Routeguide\Point $argument,
+      $metadata = [], $options = []) {
+      return $this->_simpleRequest('/routeguide.RouteGuide/GetFeature',
+      $argument,
+      ['\Routeguide\Feature', 'decode'],
+      $metadata, $options);
+    }
+
+    /**
+     * A server-to-client streaming RPC.
+     *
+     * Obtains the Features available within the given Rectangle.  Results are
+     * streamed rather than returned at once (e.g. in a response message with a
+     * repeated field), as the rectangle may cover a large area and contain a
+     * huge number of features.
+     * @param \Routeguide\Rectangle $argument input argument
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function ListFeatures(\Routeguide\Rectangle $argument,
+      $metadata = [], $options = []) {
+      return $this->_serverStreamRequest('/routeguide.RouteGuide/ListFeatures',
+      $argument,
+      ['\Routeguide\Feature', 'decode'],
+      $metadata, $options);
+    }
+
+    /**
+     * A client-to-server streaming RPC.
+     *
+     * Accepts a stream of Points on a route being traversed, returning a
+     * RouteSummary when traversal is completed.
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function RecordRoute($metadata = [], $options = []) {
+      return $this->_clientStreamRequest('/routeguide.RouteGuide/RecordRoute',
+      ['\Routeguide\RouteSummary','decode'],
+      $metadata, $options);
+    }
+
+    /**
+     * A Bidirectional streaming RPC.
+     *
+     * Accepts a stream of RouteNotes sent while a route is being traversed,
+     * while receiving other RouteNotes (e.g. from other users).
+     * @param array $metadata metadata
+     * @param array $options call options
+     */
+    public function RouteChat($metadata = [], $options = []) {
+      return $this->_bidiRequest('/routeguide.RouteGuide/RouteChat',
+      ['\Routeguide\RouteNote','decode'],
+      $metadata, $options);
+    }
+
+  }
+
+}
diff --git a/include/grpc/census.h b/include/grpc/census.h
index 62ff45d..822c42c 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -156,7 +156,7 @@
 CENSUSAPI const census_context_status *census_context_get_status(
     const census_context *context);
 
-/* Structure used for iterating over the tegs in a context. API clients should
+/* Structure used for iterating over the tags in a context. API clients should
    not use or reference internal fields - neither their contents or
    presence/absence are guaranteed. */
 typedef struct {
@@ -180,7 +180,7 @@
 CENSUSAPI int census_context_get_tag(const census_context *context,
                                      const char *key, census_tag *tag);
 
-/* Tag set encode/decode functionality. These functionas are intended
+/* Tag set encode/decode functionality. These functions are intended
    for use by RPC systems only, for purposes of transmitting/receiving contexts.
    */
 
@@ -205,14 +205,14 @@
 };
 
 /** Get the current trace mask associated with this context. The value returned
-    will be the logical or of census_trace_mask_values values. */
+    will be the logical OR of census_trace_mask_values values. */
 CENSUSAPI int census_trace_mask(const census_context *context);
 
 /** Set the trace mask associated with a context. */
 CENSUSAPI void census_set_trace_mask(int trace_mask);
 
 /* The concept of "operation" is a fundamental concept for Census. In an RPC
-   system, and operation typcially represents a single RPC, or a significant
+   system, an operation typically represents a single RPC, or a significant
    sub-part thereof (e.g. a single logical "read" RPC to a distributed storage
    system might do several other actions in parallel, from looking up metadata
    indices to making requests of other services - each of these could be a
@@ -362,7 +362,7 @@
 
    @param context The base context. Can be NULL.
    @param family Family name to associate with the trace
-   @param name Name within family to associated with traces/stats
+   @param name Name within family to associate with traces/stats
    @param trace_mask An OR of census_trace_mask_values values. Only used if
                      context is NULL.
 
@@ -454,7 +454,7 @@
    protobuf, `resource_pb_size` being the size of the buffer. Returns a -ve
    value on error, or a positive (>= 0) resource id (for use in
    census_delete_resource() and census_record_values()). In order to be valid, a
-   resource must have a name, and at least one numerator in it's unit type. The
+   resource must have a name, and at least one numerator in its unit type. The
    resource name must be unique, and an error will be returned if it is not. */
 CENSUSAPI int32_t census_define_resource(const uint8_t *resource_pb,
                                          size_t resource_pb_size);
@@ -462,7 +462,7 @@
 /* Delete a resource created by census_define_resource(). */
 CENSUSAPI void census_delete_resource(int32_t resource_id);
 
-/* Determine the id of a resource, given it's name. returns -1 if the resource
+/* Determine the id of a resource, given its name. returns -1 if the resource
    does not exist. */
 CENSUSAPI int32_t census_resource_id(const char *name);
 
diff --git a/src/core/ext/census/gen/trace_context.pb.c b/src/core/ext/census/gen/trace_context.pb.c
index c8aea32..f4126d4 100644
--- a/src/core/ext/census/gen/trace_context.pb.c
+++ b/src/core/ext/census/gen/trace_context.pb.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016, Google Inc.
+ * Copyright 2017, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,51 +31,24 @@
  *
  */
 /* Automatically generated nanopb constant definitions */
-/* Generated by nanopb-0.3.5-dev */
+/* Generated by nanopb-0.3.7-dev at Fri Jan 20 16:14:22 2017. */
 
 #include "src/core/ext/census/gen/trace_context.pb.h"
 
+/* @@protoc_insertion_point(includes) */
 #if PB_PROTO_HEADER_VERSION != 30
 #error Regenerate this file with the current version of nanopb generator.
 #endif
 
 
 
-const pb_field_t google_trace_TraceId_fields[3] = {
-    PB_FIELD(  1, FIXED64 , OPTIONAL, STATIC  , FIRST, google_trace_TraceId, hi, hi, 0),
-    PB_FIELD(  2, FIXED64 , OPTIONAL, STATIC  , OTHER, google_trace_TraceId, lo, hi, 0),
-    PB_LAST_FIELD
-};
-
-const pb_field_t google_trace_TraceContext_fields[4] = {
-    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, google_trace_TraceContext, trace_id, trace_id, &google_trace_TraceId_fields),
-    PB_FIELD(  2, FIXED64 , OPTIONAL, STATIC  , OTHER, google_trace_TraceContext, span_id, trace_id, 0),
-    PB_FIELD(  3, BOOL    , OPTIONAL, STATIC  , OTHER, google_trace_TraceContext, is_sampled, span_id, 0),
+const pb_field_t google_trace_TraceContext_fields[5] = {
+    PB_FIELD(  1, FIXED64 , OPTIONAL, STATIC  , FIRST, google_trace_TraceContext, trace_id_hi, trace_id_hi, 0),
+    PB_FIELD(  2, FIXED64 , OPTIONAL, STATIC  , OTHER, google_trace_TraceContext, trace_id_lo, trace_id_hi, 0),
+    PB_FIELD(  3, FIXED64 , OPTIONAL, STATIC  , OTHER, google_trace_TraceContext, span_id, trace_id_lo, 0),
+    PB_FIELD(  4, FIXED32 , OPTIONAL, STATIC  , OTHER, google_trace_TraceContext, span_options, span_id, 0),
     PB_LAST_FIELD
 };
 
 
-/* Check that field information fits in pb_field_t */
-#if !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_32BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in 8 or 16 bit
- * field descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext)
-#endif
-
-#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
-/* If you get an error here, it means that you need to define PB_FIELD_16BIT
- * compile-time option. You can do that in pb.h or on compiler command line.
- * 
- * The reason you need to do this is that some of your messages contain tag
- * numbers or field sizes that are larger than what can fit in the default
- * 8 bit descriptors.
- */
-PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext)
-#endif
-
-
+/* @@protoc_insertion_point(eof) */
diff --git a/src/core/ext/census/gen/trace_context.pb.h b/src/core/ext/census/gen/trace_context.pb.h
index cfb2f04..ea127bf 100644
--- a/src/core/ext/census/gen/trace_context.pb.h
+++ b/src/core/ext/census/gen/trace_context.pb.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2016, Google Inc.
+ * Copyright 2017, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,11 +31,13 @@
  *
  */
 /* Automatically generated nanopb header */
-/* Generated by nanopb-0.3.5-dev */
+/* Generated by nanopb-0.3.7-dev at Fri Jan 20 16:14:22 2017. */
 
 #ifndef GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H
 #define GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H
 #include "third_party/nanopb/pb.h"
+
+/* @@protoc_insertion_point(includes) */
 #if PB_PROTO_HEADER_VERSION != 30
 #error Regenerate this file with the current version of nanopb generator.
 #endif
@@ -45,44 +47,35 @@
 #endif
 
 /* Struct definitions */
-typedef struct _google_trace_TraceId {
-    bool has_hi;
-    uint64_t hi;
-    bool has_lo;
-    uint64_t lo;
-} google_trace_TraceId;
-
 typedef struct _google_trace_TraceContext {
-    bool has_trace_id;
-    google_trace_TraceId trace_id;
+    bool has_trace_id_hi;
+    uint64_t trace_id_hi;
+    bool has_trace_id_lo;
+    uint64_t trace_id_lo;
     bool has_span_id;
     uint64_t span_id;
-    bool has_is_sampled;
-    bool is_sampled;
+    bool has_span_options;
+    uint32_t span_options;
+/* @@protoc_insertion_point(struct:google_trace_TraceContext) */
 } google_trace_TraceContext;
 
 /* Default values for struct fields */
 
 /* Initializer values for message structs */
-#define google_trace_TraceId_init_default        {false, 0, false, 0}
-#define google_trace_TraceContext_init_default   {false, google_trace_TraceId_init_default, false, 0, false, 0}
-#define google_trace_TraceId_init_zero           {false, 0, false, 0}
-#define google_trace_TraceContext_init_zero      {false, google_trace_TraceId_init_zero, false, 0, false, 0}
+#define google_trace_TraceContext_init_default   {false, 0, false, 0, false, 0, false, 0}
+#define google_trace_TraceContext_init_zero      {false, 0, false, 0, false, 0, false, 0}
 
 /* Field tags (for use in manual encoding/decoding) */
-#define google_trace_TraceId_hi_tag              1
-#define google_trace_TraceId_lo_tag              2
-#define google_trace_TraceContext_trace_id_tag   1
-#define google_trace_TraceContext_span_id_tag    2
-#define google_trace_TraceContext_is_sampled_tag 3
+#define google_trace_TraceContext_trace_id_hi_tag 1
+#define google_trace_TraceContext_trace_id_lo_tag 2
+#define google_trace_TraceContext_span_id_tag    3
+#define google_trace_TraceContext_span_options_tag 4
 
 /* Struct field encoding specification for nanopb */
-extern const pb_field_t google_trace_TraceId_fields[3];
-extern const pb_field_t google_trace_TraceContext_fields[4];
+extern const pb_field_t google_trace_TraceContext_fields[5];
 
 /* Maximum encoded size of messages (where known) */
-#define google_trace_TraceId_size                18
-#define google_trace_TraceContext_size           31
+#define google_trace_TraceContext_size           32
 
 /* Message IDs (where set with "msgid" option) */
 #ifdef PB_MSGID
@@ -95,5 +88,6 @@
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
+/* @@protoc_insertion_point(eof) */
 
-#endif /* GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H */
+#endif
diff --git a/src/core/ext/census/trace_context.c b/src/core/ext/census/trace_context.c
index fbb20d3..47d0de1 100644
--- a/src/core/ext/census/trace_context.c
+++ b/src/core/ext/census/trace_context.c
@@ -73,7 +73,7 @@
   }
 
   // check fields
-  if (!ctxt->has_trace_id) {
+  if (!ctxt->has_trace_id_hi || !ctxt->has_trace_id_lo) {
     gpr_log(GPR_DEBUG, "Invalid TraceContext: missing trace_id");
     return false;
   }
diff --git a/src/core/ext/census/trace_context.h b/src/core/ext/census/trace_context.h
index 1cb5e26..f391a1b 100644
--- a/src/core/ext/census/trace_context.h
+++ b/src/core/ext/census/trace_context.h
@@ -38,6 +38,9 @@
 
 #include "src/core/ext/census/gen/trace_context.pb.h"
 
+/* Span option flags. */
+#define SPAN_OPTIONS_IS_SAMPLED 0x01
+
 /* Maximum number of bytes required to encode a TraceContext (31)
 1 byte for trace_id field
 1 byte for trace_id length
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index d64c241..70bab4c 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -86,8 +86,11 @@
   /* Status came from 'the wire' - or somewhere below the surface
      layer */
   STATUS_FROM_WIRE,
-  /* Status was created by some internal channel stack operation */
+  /* Status was created by some internal channel stack operation: must come via
+     add_batch_error */
   STATUS_FROM_CORE,
+  /* Status was created by some surface error */
+  STATUS_FROM_SURFACE,
   /* Status came from the server sending status */
   STATUS_FROM_SERVER_STATUS,
   STATUS_SOURCE_COUNT
@@ -212,6 +215,8 @@
   void *saved_receiving_stream_ready_bctlp;
 };
 
+int grpc_call_error_trace = 0;
+
 #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
 #define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
 #define CALL_ELEM_FROM_CALL(call, idx) \
@@ -221,11 +226,11 @@
 
 static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
                        grpc_transport_stream_op *op);
-static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
-                                          grpc_status_code status,
-                                          const char *description);
+static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+                               status_source source, grpc_status_code status,
+                               const char *description);
 static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
-                              grpc_error *error);
+                              status_source source, grpc_error *error);
 static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
                          grpc_error *error);
 static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
@@ -352,7 +357,8 @@
                                               call->start_time, send_deadline,
                                               CALL_STACK_FROM_CALL(call)));
   if (error != GRPC_ERROR_NONE) {
-    cancel_with_error(exec_ctx, call, GRPC_ERROR_REF(error));
+    cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE,
+                      GRPC_ERROR_REF(error));
   }
   if (args->cq != NULL) {
     GPR_ASSERT(
@@ -527,7 +533,6 @@
                                              grpc_status_code status,
                                              const char *description,
                                              void *reserved) {
-  grpc_call_error r;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   GRPC_API_TRACE(
       "grpc_call_cancel_with_status("
@@ -535,16 +540,16 @@
       4, (c, (int)status, description, reserved));
   GPR_ASSERT(reserved == NULL);
   gpr_mu_lock(&c->mu);
-  r = cancel_with_status(&exec_ctx, c, status, description);
+  cancel_with_status(&exec_ctx, c, STATUS_FROM_API_OVERRIDE, status,
+                     description);
   gpr_mu_unlock(&c->mu);
   grpc_exec_ctx_finish(&exec_ctx);
-  return r;
+  return GRPC_CALL_OK;
 }
 
 typedef struct termination_closure {
   grpc_closure closure;
   grpc_call *call;
-  grpc_error *error;
   grpc_transport_stream_op op;
 } termination_closure;
 
@@ -559,36 +564,27 @@
                              grpc_error *error) {
   termination_closure *tc = tcp;
   memset(&tc->op, 0, sizeof(tc->op));
-  tc->op.cancel_error = tc->error;
+  tc->op.cancel_error = GRPC_ERROR_REF(error);
   /* reuse closure to catch completion */
-  grpc_closure_init(&tc->closure, done_termination, tc,
-                    grpc_schedule_on_exec_ctx);
-  tc->op.on_complete = &tc->closure;
+  tc->op.on_complete = grpc_closure_init(&tc->closure, done_termination, tc,
+                                         grpc_schedule_on_exec_ctx);
   execute_op(exec_ctx, tc->call, &tc->op);
 }
 
-static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
-                                             termination_closure *tc) {
-  set_status_from_error(exec_ctx, tc->call, STATUS_FROM_API_OVERRIDE,
-                        GRPC_ERROR_REF(tc->error));
-  grpc_closure_init(&tc->closure, send_termination, tc,
-                    grpc_schedule_on_exec_ctx);
-  GRPC_CALL_INTERNAL_REF(tc->call, "termination");
-  grpc_closure_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE);
-  return GRPC_CALL_OK;
-}
-
-static grpc_call_error terminate_with_error(grpc_exec_ctx *exec_ctx,
-                                            grpc_call *c, grpc_error *error) {
+static void terminate_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
+                                 grpc_error *error) {
   termination_closure *tc = gpr_malloc(sizeof(*tc));
   memset(tc, 0, sizeof(*tc));
   tc->call = c;
-  tc->error = error;
-  return terminate_with_status(exec_ctx, tc);
+  GRPC_CALL_INTERNAL_REF(tc->call, "termination");
+  grpc_closure_sched(exec_ctx, grpc_closure_init(&tc->closure, send_termination,
+                                                 tc, grpc_schedule_on_exec_ctx),
+                     error);
 }
 
 static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
-                              grpc_error *error) {
+                              status_source source, grpc_error *error) {
+  set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error));
   terminate_with_error(exec_ctx, c, error);
 }
 
@@ -600,32 +596,35 @@
       GRPC_ERROR_INT_GRPC_STATUS, status);
 }
 
-static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
-                                          grpc_status_code status,
-                                          const char *description) {
-  return terminate_with_error(exec_ctx, c,
-                              error_from_status(status, description));
+static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+                               status_source source, grpc_status_code status,
+                               const char *description) {
+  cancel_with_error(exec_ctx, c, source,
+                    error_from_status(status, description));
 }
 
 /*******************************************************************************
  * FINAL STATUS CODE MANIPULATION
  */
 
-static void get_final_status_from(grpc_call *call, status_source from_source,
-                                  void (*set_value)(grpc_status_code code,
-                                                    void *user_data),
-                                  void *set_value_user_data,
-                                  grpc_slice *details) {
+static bool get_final_status_from(
+    grpc_call *call, status_source from_source, bool allow_ok_status,
+    void (*set_value)(grpc_status_code code, void *user_data),
+    void *set_value_user_data, grpc_slice *details) {
   grpc_status_code code;
   const char *msg = NULL;
   grpc_error_get_status(call->status[from_source].error, call->send_deadline,
                         &code, &msg, NULL);
+  if (code == GRPC_STATUS_OK && !allow_ok_status) {
+    return false;
+  }
 
   set_value(code, set_value_user_data);
   if (details != NULL) {
     *details =
         msg == NULL ? grpc_empty_slice() : grpc_slice_from_copied_string(msg);
   }
+  return true;
 }
 
 static void get_final_status(grpc_call *call,
@@ -633,22 +632,37 @@
                                                void *user_data),
                              void *set_value_user_data, grpc_slice *details) {
   int i;
-  /* search for the best status we can present: ideally the error we use has a
-     clearly defined grpc-status, and we'll prefer that. */
-  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
-    if (call->status[i].is_set &&
-        grpc_error_has_clear_grpc_status(call->status[i].error)) {
-      get_final_status_from(call, (status_source)i, set_value,
-                            set_value_user_data, details);
-      return;
+  if (grpc_call_error_trace) {
+    gpr_log(GPR_DEBUG, "get_final_status %s", call->is_client ? "CLI" : "SVR");
+    for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+      if (call->status[i].is_set) {
+        gpr_log(GPR_DEBUG, "  %d: %s", i,
+                grpc_error_string(call->status[i].error));
+      }
     }
   }
-  /* If no clearly defined status exists, search for 'anything' */
-  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
-    if (call->status[i].is_set) {
-      get_final_status_from(call, (status_source)i, set_value,
-                            set_value_user_data, details);
-      return;
+  /* first search through ignoring "OK" statuses: if something went wrong,
+   * ensure we report it */
+  for (int allow_ok_status = 0; allow_ok_status < 2; allow_ok_status++) {
+    /* search for the best status we can present: ideally the error we use has a
+       clearly defined grpc-status, and we'll prefer that. */
+    for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+      if (call->status[i].is_set &&
+          grpc_error_has_clear_grpc_status(call->status[i].error)) {
+        if (get_final_status_from(call, (status_source)i, allow_ok_status != 0,
+                                  set_value, set_value_user_data, details)) {
+          return;
+        }
+      }
+    }
+    /* If no clearly defined status exists, search for 'anything' */
+    for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+      if (call->status[i].is_set) {
+        if (get_final_status_from(call, (status_source)i, allow_ok_status != 0,
+                                  set_value, set_value_user_data, details)) {
+          return;
+        }
+      }
     }
   }
   /* If nothing exists, set some default */
@@ -1029,11 +1043,6 @@
 
   gpr_mu_lock(&call->mu);
 
-  if (error != GRPC_ERROR_NONE) {
-    set_status_from_error(exec_ctx, call, STATUS_FROM_CORE,
-                          GRPC_ERROR_REF(error));
-  }
-
   if (bctl->send_initial_metadata) {
     grpc_metadata_batch_destroy(
         exec_ctx,
@@ -1176,7 +1185,8 @@
   grpc_call *call = bctl->call;
   gpr_mu_lock(&bctl->call->mu);
   if (error != GRPC_ERROR_NONE) {
-    cancel_with_error(exec_ctx, call, GRPC_ERROR_REF(error));
+    cancel_with_error(exec_ctx, call, STATUS_FROM_SURFACE,
+                      GRPC_ERROR_REF(error));
   }
   if (call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
       call->receiving_stream == NULL) {
@@ -1203,7 +1213,8 @@
       gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
                    algo);
       gpr_log(GPR_ERROR, "%s", error_msg);
-      cancel_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+      cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
+                         GRPC_STATUS_UNIMPLEMENTED, error_msg);
     } else if (grpc_compression_options_is_algorithm_enabled(
                    &compression_options, algo) == 0) {
       /* check if algorithm is supported by current channel config */
@@ -1212,7 +1223,8 @@
       gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
                    algo_name);
       gpr_log(GPR_ERROR, "%s", error_msg);
-      cancel_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+      cancel_with_status(exec_ctx, call, STATUS_FROM_SURFACE,
+                         GRPC_STATUS_UNIMPLEMENTED, error_msg);
     } else {
       call->incoming_compression_algorithm = algo;
     }
@@ -1242,7 +1254,10 @@
                             grpc_error *error) {
   if (error == GRPC_ERROR_NONE) return;
   int idx = (int)gpr_atm_no_barrier_fetch_add(&bctl->num_errors, 1);
-  if (idx == 0) cancel_with_error(exec_ctx, bctl->call, GRPC_ERROR_REF(error));
+  if (idx == 0) {
+    cancel_with_error(exec_ctx, bctl->call, STATUS_FROM_CORE,
+                      GRPC_ERROR_REF(error));
+  }
   bctl->errors[idx] = error;
 }
 
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index 8c46a83..b70343d 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -125,6 +125,8 @@
 grpc_compression_algorithm grpc_call_compression_for_level(
     grpc_call *call, grpc_compression_level level);
 
+extern int grpc_call_error_trace;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index cfa1882..787e4d0 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -199,6 +199,7 @@
     grpc_cq_event_timeout_trace = 1;
     grpc_register_tracer("op_failure", &grpc_trace_operation_failures);
     grpc_register_tracer("resource_quota", &grpc_resource_quota_trace);
+    grpc_register_tracer("call_error", &grpc_call_error_trace);
 #ifndef NDEBUG
     grpc_register_tracer("pending_tags", &grpc_trace_pending_tags);
 #endif
diff --git a/src/csharp/Grpc.Core.Testing/.gitignore b/src/csharp/Grpc.Core.Testing/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj
new file mode 100644
index 0000000..9b0b3ab
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Grpc.Core.Testing</RootNamespace>
+    <AssemblyName>Grpc.Core.Testing</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <DocumentationFile>bin\$(Configuration)\Grpc.Core.Testing.Xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Interactive.Async">
+      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TestCalls.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Grpc.Core.Testing.project.json" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.project.json b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.project.json
new file mode 100644
index 0000000..c2f5bcb
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.project.json
@@ -0,0 +1,8 @@
+{
+  "frameworks": {
+    "net45": { }
+  },
+  "runtimes": {
+    "win": { }
+  }
+}
diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.xproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.xproj
new file mode 100644
index 0000000..c972387
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>2b372155-80ba-4cf9-82d6-4b938e8ec3a0</ProjectGuid>
+    <RootNamespace>Grpc.Core.Testing</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file
diff --git a/examples/php/helloworld.proto b/src/csharp/Grpc.Core.Testing/Properties/AssemblyInfo.cs
similarity index 77%
rename from examples/php/helloworld.proto
rename to src/csharp/Grpc.Core.Testing/Properties/AssemblyInfo.cs
index ad8f7a1..d3ca0c4 100644
--- a/examples/php/helloworld.proto
+++ b/src/csharp/Grpc.Core.Testing/Properties/AssemblyInfo.cs
@@ -1,3 +1,5 @@
+#region Copyright notice and license
+
 // Copyright 2015, Google Inc.
 // All rights reserved.
 //
@@ -27,24 +29,16 @@
 // (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";
+#endregion
 
-option java_package = "ex.grpc";
+using System.Reflection;
+using System.Runtime.CompilerServices;
 
-package helloworld;
-
-// The greeting service definition.
-service Greeter {
-  // Sends a greeting
-  rpc SayHello (HelloRequest) returns (HelloReply) {}
-}
-
-// The request message containing the user's name.
-message HelloRequest {
-  optional string name = 1;
-}
-
-// The response message containing the greetings
-message HelloReply {
-  optional string message = 1;
-}
+[assembly: AssemblyTitle("Grpc.Core.Testing")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
diff --git a/src/csharp/Grpc.Core.Testing/Settings.StyleCop b/src/csharp/Grpc.Core.Testing/Settings.StyleCop
new file mode 100644
index 0000000..2942add
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/Settings.StyleCop
@@ -0,0 +1,10 @@
+<StyleCopSettings Version="105">
+  <SourceFileList>
+    <SourceFile>Health.cs</SourceFile>
+    <Settings>
+    <GlobalSettings>
+      <BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
+    </GlobalSettings>
+    </Settings>
+  </SourceFileList>
+</StyleCopSettings>
diff --git a/src/csharp/Grpc.Core.Testing/TestCalls.cs b/src/csharp/Grpc.Core.Testing/TestCalls.cs
new file mode 100644
index 0000000..d8c36f2
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/TestCalls.cs
@@ -0,0 +1,91 @@
+#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.Tasks;
+using Grpc.Core;
+
+namespace Grpc.Core.Testing
+{
+    /// <summary>
+    /// Test doubles for client-side call objects.
+    /// </summary>
+    public static class TestCalls
+    {
+        /// <summary>
+        /// Creates a test double for <c>AsyncUnaryCall</c>. Only for testing.
+        /// Note: experimental API that can change or be removed without any prior notice.
+        /// </summary>
+        public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TResponse> (
+            Task<TResponse> responseAsync, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc,
+            Func<Metadata> getTrailersFunc, Action disposeAction)
+        {
+            return new AsyncUnaryCall<TResponse>(responseAsync, responseHeadersAsync, getStatusFunc, getTrailersFunc, disposeAction);
+        }
+
+        /// <summary>
+        /// Creates a test double for <c>AsyncClientStreamingCall</c>. Only for testing.
+        /// Note: experimental API that can change or be removed without any prior notice.
+        /// </summary>
+        public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(
+            IClientStreamWriter<TRequest> requestStream, Task<TResponse> responseAsync,
+            Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc,
+            Func<Metadata> getTrailersFunc, Action disposeAction)
+        {
+            return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, responseAsync, responseHeadersAsync, getStatusFunc, getTrailersFunc, disposeAction);
+        }
+
+        /// <summary>
+        /// Creates a test double for <c>AsyncServerStreamingCall</c>. Only for testing.
+        /// Note: experimental API that can change or be removed without any prior notice.
+        /// </summary>
+        public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TResponse>(
+            IAsyncStreamReader<TResponse> responseStream, Task<Metadata> responseHeadersAsync, 
+            Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction)
+        {
+            return new AsyncServerStreamingCall<TResponse>(responseStream, responseHeadersAsync, getStatusFunc, getTrailersFunc, disposeAction);
+        }
+
+        /// <summary>
+        /// Creates a test double for <c>AsyncDuplexStreamingCall</c>. Only for testing.
+        /// Note: experimental API that can change or be removed without any prior notice.
+        /// </summary>
+        public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TResponse, TRequest>(
+            IClientStreamWriter<TRequest> requestStream, IAsyncStreamReader<TResponse> responseStream,
+            Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc,
+            Func<Metadata> getTrailersFunc, Action disposeAction)
+        {
+            return new AsyncDuplexStreamingCall<TRequest, TResponse>(requestStream, responseStream, responseHeadersAsync, getStatusFunc, getTrailersFunc, disposeAction);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core.Testing/packages.config b/src/csharp/Grpc.Core.Testing/packages.config
new file mode 100644
index 0000000..53cfad5
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Testing/project.json b/src/csharp/Grpc.Core.Testing/project.json
new file mode 100644
index 0000000..02be957
--- /dev/null
+++ b/src/csharp/Grpc.Core.Testing/project.json
@@ -0,0 +1,39 @@
+{
+  "version": "1.2.0-dev",
+  "title": "gRPC C# Core Testing",
+  "authors": [ "Google Inc." ],
+  "copyright": "Copyright 2017, Google Inc.",
+  "packOptions": {
+    "summary": "Testing support for gRPC C#",
+    "description": "Useful when testing code that uses gRPC.",
+    "owners": [ "grpc-packages" ],
+    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+    "projectUrl": "https://github.com/grpc/grpc",
+    "requireLicenseAcceptance": false,
+    "tags": [ "gRPC test testing" ]
+  },
+  "buildOptions": {
+    "define": [ "SIGNED" ],
+    "keyFile": "../keys/Grpc.snk",
+    "xmlDoc": true,
+    "compile": {
+      "includeFiles": [ "../Grpc.Core/Version.cs" ]
+    }
+  },
+  "dependencies": {
+    "Grpc.Core": "1.2.0-dev"
+  },
+  "frameworks": {
+    "net45": {
+      "frameworkAssemblies": {
+        "System.Runtime": "",
+        "System.IO": ""
+      }
+    },
+    "netstandard1.5": {
+      "dependencies": {
+        "NETStandard.Library": "1.6.0"
+      }
+    }
+  }
+}
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 99158fb..77ac347 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -49,6 +49,11 @@
     "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
     "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
     "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
+[assembly: InternalsVisibleTo("Grpc.Core.Testing,PublicKey=" +
+    "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
+    "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
+    "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
+    "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
 [assembly: InternalsVisibleTo("Grpc.IntegrationTesting,PublicKey=" +
     "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
     "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
@@ -56,5 +61,6 @@
     "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
 #else
 [assembly: InternalsVisibleTo("Grpc.Core.Tests")]
+[assembly: InternalsVisibleTo("Grpc.Core.Testing")]
 [assembly: InternalsVisibleTo("Grpc.IntegrationTesting")]
 #endif
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 179e731..84ba460 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -40,6 +40,8 @@
 EndProject

 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.csproj", "{B88F91D6-436D-4C78-8B99-47800FA8DE03}"

 EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Core.Testing", "Grpc.Core.Testing\Grpc.Core.Testing.csproj", "{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}"

+EndProject

 Global

 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

 		Debug|Any CPU = Debug|Any CPU

@@ -110,6 +112,10 @@
 		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU

 		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU

 		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.Build.0 = Release|Any CPU

+		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

+		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Debug|Any CPU.Build.0 = Debug|Any CPU

+		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Release|Any CPU.ActiveCfg = Release|Any CPU

+		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Release|Any CPU.Build.0 = Release|Any CPU

 	EndGlobalSection

 	GlobalSection(NestedProjects) = preSolution

 	EndGlobalSection

diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 3b9306b..b99fdcb 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -59,6 +59,7 @@
 %DOTNET% restore . || goto :error
 
 %DOTNET% pack --configuration Release Grpc.Core\project.json --output ..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Core.Testing\project.json --output ..\..\artifacts || goto :error
 %DOTNET% pack --configuration Release Grpc.Auth\project.json --output ..\..\artifacts || goto :error
 %DOTNET% pack --configuration Release Grpc.HealthCheck\project.json --output ..\..\artifacts || goto :error
 %DOTNET% pack --configuration Release Grpc.Reflection\project.json --output ..\..\artifacts || goto :error
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index dcb4fe3..442e3ac 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -61,6 +61,7 @@
 dotnet restore .
 
 dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts
+dotnet pack --configuration Release Grpc.Core.Testing/project.json --output ../../artifacts
 dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifacts
 dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
 dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
diff --git a/src/php/composer.json b/src/php/composer.json
index f352916..746474d 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -13,10 +13,8 @@
   "autoload": {
     "psr-4": {
       "Grpc\\": "lib/Grpc/",
-      "Grpc\\Testing\\": "tests/interop/Grpc/Testing/",
-      "GPBMetadata\\Src\\Proto\\Grpc\\Testing\\": "tests/interop/GPBMetadata/Src/Proto/Grpc/Testing/",
-      "Math\\": "tests/generated_code/Math/",
-      "GPBMetadata\\": "tests/generated_code/GPBMetadata/"
+      "": ["tests/interop/",
+           "tests/generated_code/"]
     }
   }
 }
diff --git a/src/proto/census/trace_context.proto b/src/proto/census/trace_context.proto
index a5d5a95..fc0a54d 100644
--- a/src/proto/census/trace_context.proto
+++ b/src/proto/census/trace_context.proto
@@ -31,18 +31,14 @@
 
 package google.trace;
 
-// A TraceId uniquely represents a single Trace. It is a 128-bit nonce.
-message TraceId {
-  fixed64 hi = 1;
-  fixed64 lo = 2;
-}
-
 // Tracing information that is propagated with RPC's.
 message TraceContext {
-  // Trace identifer. Must be present.
-  TraceId trace_id = 1;
-  // ID of parent (client) span. Must be present.
-  fixed64 span_id = 2;
-  // true if this trace is sampled.
-  bool is_sampled = 3;
+  // A TraceId uniquely represents a single Trace. It is a 128-bit nonce.
+  // The 128-bit ID is split into 2 64-bit chunks. (REQUIRED)
+  fixed64 trace_id_hi = 1;
+  fixed64 trace_id_lo = 2;
+  // ID of parent (client) span. (REQUIRED)
+  fixed64 span_id = 3;
+  // Span option flags. First bit is true if this trace is sampled. (OPTIONAL)
+  fixed32 span_options = 4;
 }
diff --git a/templates/src/csharp/Grpc.Core.Testing/project.json.template b/templates/src/csharp/Grpc.Core.Testing/project.json.template
new file mode 100644
index 0000000..7aff991
--- /dev/null
+++ b/templates/src/csharp/Grpc.Core.Testing/project.json.template
@@ -0,0 +1,41 @@
+%YAML 1.2
+--- |
+  {
+    "version": "${settings.csharp_version}",
+    "title": "gRPC C# Core Testing",
+    "authors": [ "Google Inc." ],
+    "copyright": "Copyright 2017, Google Inc.",
+    "packOptions": {
+      "summary": "Testing support for gRPC C#",
+      "description": "Useful when testing code that uses gRPC.",
+      "owners": [ "grpc-packages" ],
+      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+      "projectUrl": "https://github.com/grpc/grpc",
+      "requireLicenseAcceptance": false,
+      "tags": [ "gRPC test testing" ]
+    },
+    "buildOptions": {
+      "define": [ "SIGNED" ],
+      "keyFile": "../keys/Grpc.snk",
+      "xmlDoc": true,
+      "compile": {
+        "includeFiles": [ "../Grpc.Core/Version.cs" ]
+      }
+    },
+    "dependencies": {
+      "Grpc.Core": "${settings.csharp_version}"
+    },
+    "frameworks": {
+      "net45": {
+        "frameworkAssemblies": {
+          "System.Runtime": "",
+          "System.IO": ""
+        }
+      },
+      "netstandard1.5": {
+        "dependencies": {
+          "NETStandard.Library": "1.6.0"
+        }
+      }
+    }
+  }
diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template
index 562b770..2f91d48 100755
--- a/templates/src/csharp/build_packages_dotnetcli.bat.template
+++ b/templates/src/csharp/build_packages_dotnetcli.bat.template
@@ -61,6 +61,7 @@
   %%DOTNET% restore . || goto :error
   
   %%DOTNET% pack --configuration Release Grpc.Core\project.json --output ..\..\artifacts || goto :error
+  %%DOTNET% pack --configuration Release Grpc.Core.Testing\project.json --output ..\..\artifacts || goto :error
   %%DOTNET% pack --configuration Release Grpc.Auth\project.json --output ..\..\artifacts || goto :error
   %%DOTNET% pack --configuration Release Grpc.HealthCheck\project.json --output ..\..\artifacts || goto :error
   %%DOTNET% pack --configuration Release Grpc.Reflection\project.json --output ..\..\artifacts || goto :error
diff --git a/templates/src/csharp/build_packages_dotnetcli.sh.template b/templates/src/csharp/build_packages_dotnetcli.sh.template
index 91c6fb6..c536437 100755
--- a/templates/src/csharp/build_packages_dotnetcli.sh.template
+++ b/templates/src/csharp/build_packages_dotnetcli.sh.template
@@ -63,6 +63,7 @@
   dotnet restore .
   
   dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts
+  dotnet pack --configuration Release Grpc.Core.Testing/project.json --output ../../artifacts
   dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifacts
   dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
   dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
diff --git a/templates/src/php/composer.json.template b/templates/src/php/composer.json.template
index 5223efd..08710d3 100644
--- a/templates/src/php/composer.json.template
+++ b/templates/src/php/composer.json.template
@@ -15,10 +15,8 @@
     "autoload": {
       "psr-4": {
         "Grpc\\": "lib/Grpc/",
-        "Grpc\\Testing\\": "tests/interop/Grpc/Testing/",
-        "GPBMetadata\\Src\\Proto\\Grpc\\Testing\\": "tests/interop/GPBMetadata/Src/Proto/Grpc/Testing/",
-        "Math\\": "tests/generated_code/Math/",
-        "GPBMetadata\\": "tests/generated_code/GPBMetadata/"
+        "": ["tests/interop/",
+             "tests/generated_code/"]
       }
     }
   }
diff --git a/test/core/census/data/context_full.pb b/test/core/census/data/context_full.pb
index 80ebcf2..7b5895c 100644
--- a/test/core/census/data/context_full.pb
+++ b/test/core/census/data/context_full.pb
Binary files differ
diff --git a/test/core/census/data/context_full.txt b/test/core/census/data/context_full.txt
index 7901a10..7d8df37 100644
--- a/test/core/census/data/context_full.txt
+++ b/test/core/census/data/context_full.txt
@@ -1,3 +1,4 @@
-trace_id { hi : 5; lo : 1 }
+trace_id_hi : 5
+trace_id_lo : 1
 span_id : 7
-is_sampled : true
+span_options : 1
diff --git a/test/core/census/data/context_no_sample.pb b/test/core/census/data/context_no_sample.pb
deleted file mode 100644
index ab7ad7d..0000000
--- a/test/core/census/data/context_no_sample.pb
+++ /dev/null
Binary files differ
diff --git a/test/core/census/data/context_no_sample.txt b/test/core/census/data/context_no_sample.txt
deleted file mode 100644
index 1502980..0000000
--- a/test/core/census/data/context_no_sample.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-trace_id { hi : 5; lo : 1 }
-span_id : 7
diff --git a/test/core/census/data/context_no_span_options.pb b/test/core/census/data/context_no_span_options.pb
new file mode 100644
index 0000000..4b3425a
--- /dev/null
+++ b/test/core/census/data/context_no_span_options.pb
Binary files differ
diff --git a/test/core/census/data/context_no_span_options.txt b/test/core/census/data/context_no_span_options.txt
new file mode 100644
index 0000000..4c8398f
--- /dev/null
+++ b/test/core/census/data/context_no_span_options.txt
@@ -0,0 +1,3 @@
+trace_id_hi : 5
+trace_id_lo : 1
+span_id : 7
diff --git a/test/core/census/data/context_span_only.pb b/test/core/census/data/context_span_only.pb
index 2a9527a..a9315be 100644
--- a/test/core/census/data/context_span_only.pb
+++ b/test/core/census/data/context_span_only.pb
Binary files differ
diff --git a/test/core/census/data/context_span_only.txt b/test/core/census/data/context_span_only.txt
index d90de2e..4e473fc 100644
--- a/test/core/census/data/context_span_only.txt
+++ b/test/core/census/data/context_span_only.txt
@@ -1,2 +1,2 @@
 span_id : 7
-is_sampled : true
+span_options : 1
diff --git a/test/core/census/data/context_trace_only.pb b/test/core/census/data/context_trace_only.pb
index 7fdf6f6..aabb325 100644
--- a/test/core/census/data/context_trace_only.pb
+++ b/test/core/census/data/context_trace_only.pb
Binary files differ
diff --git a/test/core/census/data/context_trace_only.txt b/test/core/census/data/context_trace_only.txt
index 9b68a6a..e48a6d7 100644
--- a/test/core/census/data/context_trace_only.txt
+++ b/test/core/census/data/context_trace_only.txt
@@ -1,2 +1,3 @@
-trace_id { hi : 5; lo : 1 }
-is_sampled : true
+trace_id_hi : 5
+trace_id_lo : 1
+span_options : 1
diff --git a/test/core/census/trace_context_test.c b/test/core/census/trace_context_test.c
index ee409e8..5963b1a 100644
--- a/test/core/census/trace_context_test.c
+++ b/test/core/census/trace_context_test.c
@@ -59,7 +59,6 @@
                                     uint8_t *buffer, size_t buf_size) {
   google_trace_TraceContext ctxt2 = google_trace_TraceContext_init_zero;
   size_t msg_length;
-  GPR_ASSERT(ctxt1->has_trace_id && ctxt1->has_span_id);
 
   msg_length = encode_trace_context(ctxt1, buffer, buf_size);
   if (msg_length == 0) {
@@ -70,16 +69,17 @@
     return false;
   }
 
-  if (!ctxt2.has_trace_id || !ctxt2.has_span_id) {
+  if (!ctxt2.has_trace_id_hi || !ctxt2.has_trace_id_lo || !ctxt2.has_span_id) {
     return false;
   }
 
-  GPR_ASSERT(
-      ctxt1->trace_id.hi == ctxt2.trace_id.hi &&
-      ctxt1->trace_id.lo == ctxt2.trace_id.lo &&
-      ctxt1->span_id == ctxt2.span_id &&
-      ctxt1->has_is_sampled == ctxt2.has_is_sampled &&
-      (ctxt1->has_is_sampled ? ctxt1->is_sampled == ctxt2.is_sampled : true));
+  GPR_ASSERT(ctxt1->trace_id_hi == ctxt2.trace_id_hi &&
+             ctxt1->trace_id_lo == ctxt2.trace_id_lo &&
+             ctxt1->span_id == ctxt2.span_id &&
+             ctxt1->has_span_options == ctxt2.has_span_options &&
+             (ctxt1->has_span_options
+                  ? ctxt1->span_options == ctxt2.span_options
+                  : true));
 
   return true;
 }
@@ -94,7 +94,7 @@
     return false;
   }
 
-  if (!ctxt->has_trace_id || !ctxt->has_span_id) {
+  if (!ctxt->has_trace_id_hi || !ctxt->has_trace_id_lo || !ctxt->has_span_id) {
     return false;
   }
 
@@ -144,49 +144,48 @@
       &ctxt, "test/core/census/data/context_span_only.pb", false);
 }
 
-// Test proto-buffer without is_sampled value.
-static void test_no_sample() {
+// Test proto-buffer without span_options value.
+static void test_no_span_options() {
   google_trace_TraceContext ctxt = google_trace_TraceContext_init_zero;
   read_and_validate_context_from_file(
-      &ctxt, "test/core/census/data/context_no_sample.pb", true);
-  GPR_ASSERT(ctxt.has_is_sampled == false && ctxt.is_sampled == false);
+      &ctxt, "test/core/census/data/context_no_span_options.pb", true);
+  GPR_ASSERT(ctxt.has_span_options == false && ctxt.span_options == 0);
 }
 
 static void test_encode_decode() {
   uint8_t buffer[BUF_SIZE] = {0};
 
   google_trace_TraceContext ctxt1 = google_trace_TraceContext_init_zero;
-  ctxt1.has_trace_id = true;
-  ctxt1.trace_id.has_hi = true;
-  ctxt1.trace_id.has_lo = true;
-  ctxt1.trace_id.lo = 1;
-  ctxt1.trace_id.hi = 2;
+  ctxt1.has_trace_id_hi = true;
+  ctxt1.has_trace_id_lo = true;
+  ctxt1.trace_id_lo = 1;
+  ctxt1.trace_id_hi = 2;
   ctxt1.has_span_id = true;
   ctxt1.span_id = 3;
   validate_encode_decode_context(&ctxt1, buffer, sizeof(buffer));
 
+  // Missing trace_id. This should fail.
   google_trace_TraceContext ctxt2 = google_trace_TraceContext_init_zero;
-  ctxt2.has_trace_id = true;
-  ctxt2.trace_id.has_hi = false;
-  ctxt2.trace_id.has_lo = false;
+  ctxt2.has_trace_id_hi = false;
+  ctxt2.has_trace_id_lo = false;
   ctxt2.has_span_id = true;
   validate_encode_decode_context(&ctxt2, buffer, sizeof(buffer));
 }
 
-// Test a corrupted proto-buffer.
+// Test a corrupted proto-buffer. This should fail.
 static void test_corrupt() {
   uint8_t buffer[BUF_SIZE] = {0};
   google_trace_TraceContext ctxt1 = google_trace_TraceContext_init_zero;
   size_t msg_length;
 
-  ctxt1.has_trace_id = true;
-  ctxt1.trace_id.has_hi = true;
-  ctxt1.trace_id.has_lo = true;
-  ctxt1.trace_id.lo = 1;
-  ctxt1.trace_id.hi = 2;
+  ctxt1.has_trace_id_hi = true;
+  ctxt1.has_trace_id_lo = true;
+  ctxt1.trace_id_lo = 1;
+  ctxt1.trace_id_hi = 2;
   ctxt1.has_span_id = true;
   ctxt1.span_id = 3;
-  ctxt1.is_sampled = true;
+  ctxt1.has_span_options = true;
+  ctxt1.span_options = SPAN_OPTIONS_IS_SAMPLED;
   msg_length = encode_trace_context(&ctxt1, buffer, sizeof(buffer));
 
   /* Corrupt some bytes.  255 (0xFF) should be illegal for the first byte of the
@@ -198,19 +197,19 @@
 }
 
 static void test_buffer_size() {
-  // This buffer is too small, so the encode should fail.
+  // This buffer is too small. This should fail.
   uint8_t buffer[16] = {0};
   google_trace_TraceContext ctxt1 = google_trace_TraceContext_init_zero;
   size_t msg_length;
 
-  ctxt1.has_trace_id = true;
-  ctxt1.trace_id.has_hi = true;
-  ctxt1.trace_id.has_lo = true;
-  ctxt1.trace_id.lo = 1;
-  ctxt1.trace_id.hi = 2;
+  ctxt1.has_trace_id_hi = true;
+  ctxt1.has_trace_id_lo = true;
+  ctxt1.trace_id_lo = 1;
+  ctxt1.trace_id_hi = 2;
   ctxt1.has_span_id = true;
   ctxt1.span_id = 3;
-  ctxt1.is_sampled = true;
+  ctxt1.has_span_options = true;
+  ctxt1.span_options = SPAN_OPTIONS_IS_SAMPLED;
   msg_length = encode_trace_context(&ctxt1, buffer, sizeof(buffer));
 
   GPR_ASSERT(msg_length == 0);
@@ -224,7 +223,7 @@
   test_span_only();
   test_encode_decode();
   test_corrupt();
-  test_no_sample();
+  test_no_span_options();
   test_buffer_size();
 
   return 0;
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index bd2d695..e81a628 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -447,7 +447,395 @@
   config.tear_down_data(&f);
 }
 
+static void test_max_concurrent_streams_with_timeout_on_first(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+  grpc_arg server_arg;
+  grpc_channel_args server_args;
+  grpc_call *c1;
+  grpc_call *c2;
+  grpc_call *s1;
+  grpc_call *s2;
+  cq_verifier *cqv;
+  grpc_call_details call_details;
+  grpc_metadata_array request_metadata_recv;
+  grpc_metadata_array initial_metadata_recv1;
+  grpc_metadata_array trailing_metadata_recv1;
+  grpc_metadata_array initial_metadata_recv2;
+  grpc_metadata_array trailing_metadata_recv2;
+  grpc_status_code status1;
+  grpc_call_error error;
+  grpc_slice details1 = grpc_empty_slice();
+  grpc_status_code status2;
+  grpc_slice details2 = grpc_empty_slice();
+  grpc_op ops[6];
+  grpc_op *op;
+  int was_cancelled;
+
+  server_arg.key = GRPC_ARG_MAX_CONCURRENT_STREAMS;
+  server_arg.type = GRPC_ARG_INTEGER;
+  server_arg.value.integer = 1;
+
+  server_args.num_args = 1;
+  server_args.args = &server_arg;
+
+  f = begin_test(config, "test_max_concurrent_streams_with_timeout_on_first",
+                 NULL, &server_args);
+  cqv = cq_verifier_create(f.cq);
+
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_metadata_array_init(&initial_metadata_recv1);
+  grpc_metadata_array_init(&trailing_metadata_recv1);
+  grpc_metadata_array_init(&initial_metadata_recv2);
+  grpc_metadata_array_init(&trailing_metadata_recv2);
+  grpc_call_details_init(&call_details);
+
+  /* perform a ping-pong to ensure that settings have had a chance to round
+     trip */
+  simple_request_body(config, f);
+  /* perform another one to make sure that the one stream case still works */
+  simple_request_body(config, f);
+
+  /* start two requests - ensuring that the second is not accepted until
+     the first completes */
+  c1 = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/alpha"),
+      get_host_override_slice("foo.test.google.fr:1234", config),
+      n_seconds_time(3), NULL);
+  GPR_ASSERT(c1);
+  c2 = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/beta"),
+      get_host_override_slice("foo.test.google.fr:1234", config),
+      n_seconds_time(1000), NULL);
+  GPR_ASSERT(c2);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s1, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  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++;
+  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(301), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv1;
+  op->data.recv_status_on_client.status = &status1;
+  op->data.recv_status_on_client.status_details = &details1;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata =
+      &initial_metadata_recv1;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(302), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(301), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  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++;
+  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(401), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv2;
+  op->data.recv_status_on_client.status = &status2;
+  op->data.recv_status_on_client.status_details = &details2;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata =
+      &initial_metadata_recv2;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(402), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  grpc_call_details_destroy(&call_details);
+  grpc_call_details_init(&call_details);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s2, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(201)));
+
+  CQ_EXPECT_COMPLETION(cqv, tag(302), 1);
+  /* first request is finished, we should be able to start the second */
+  CQ_EXPECT_COMPLETION(cqv, tag(401), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  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_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  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;
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s2, ops, (size_t)(op - ops), tag(202), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(402), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(202), 1);
+  cq_verify(cqv);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_call_destroy(c1);
+  grpc_call_destroy(s1);
+  grpc_call_destroy(c2);
+  grpc_call_destroy(s2);
+
+  grpc_slice_unref(details1);
+  grpc_slice_unref(details2);
+  grpc_metadata_array_destroy(&initial_metadata_recv1);
+  grpc_metadata_array_destroy(&trailing_metadata_recv1);
+  grpc_metadata_array_destroy(&initial_metadata_recv2);
+  grpc_metadata_array_destroy(&trailing_metadata_recv2);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_max_concurrent_streams_with_timeout_on_second(
+    grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+  grpc_arg server_arg;
+  grpc_channel_args server_args;
+  grpc_call *c1;
+  grpc_call *c2;
+  grpc_call *s1;
+  cq_verifier *cqv;
+  grpc_call_details call_details;
+  grpc_metadata_array request_metadata_recv;
+  grpc_metadata_array initial_metadata_recv1;
+  grpc_metadata_array trailing_metadata_recv1;
+  grpc_metadata_array initial_metadata_recv2;
+  grpc_metadata_array trailing_metadata_recv2;
+  grpc_status_code status1;
+  grpc_call_error error;
+  grpc_slice details1 = grpc_empty_slice();
+  grpc_status_code status2;
+  grpc_slice details2 = grpc_empty_slice();
+  grpc_op ops[6];
+  grpc_op *op;
+  int was_cancelled;
+
+  server_arg.key = GRPC_ARG_MAX_CONCURRENT_STREAMS;
+  server_arg.type = GRPC_ARG_INTEGER;
+  server_arg.value.integer = 1;
+
+  server_args.num_args = 1;
+  server_args.args = &server_arg;
+
+  f = begin_test(config, "test_max_concurrent_streams_with_timeout_on_second",
+                 NULL, &server_args);
+  cqv = cq_verifier_create(f.cq);
+
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_metadata_array_init(&initial_metadata_recv1);
+  grpc_metadata_array_init(&trailing_metadata_recv1);
+  grpc_metadata_array_init(&initial_metadata_recv2);
+  grpc_metadata_array_init(&trailing_metadata_recv2);
+  grpc_call_details_init(&call_details);
+
+  /* perform a ping-pong to ensure that settings have had a chance to round
+     trip */
+  simple_request_body(config, f);
+  /* perform another one to make sure that the one stream case still works */
+  simple_request_body(config, f);
+
+  /* start two requests - ensuring that the second is not accepted until
+     the first completes , and the second request will timeout in the
+     concurrent_list */
+  c1 = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/alpha"),
+      get_host_override_slice("foo.test.google.fr:1234", config),
+      n_seconds_time(1000), NULL);
+  GPR_ASSERT(c1);
+  c2 = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/beta"),
+      get_host_override_slice("foo.test.google.fr:1234", config),
+      n_seconds_time(3), NULL);
+  GPR_ASSERT(c2);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
+                                 f.server, &s1, &call_details,
+                                 &request_metadata_recv, f.cq, f.cq, tag(101)));
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  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++;
+  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(301), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv1;
+  op->data.recv_status_on_client.status = &status1;
+  op->data.recv_status_on_client.status_details = &details1;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata =
+      &initial_metadata_recv1;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c1, ops, (size_t)(op - ops), tag(302), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(301), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  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++;
+  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(401), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv2;
+  op->data.recv_status_on_client.status = &status2;
+  op->data.recv_status_on_client.status_details = &details2;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata =
+      &initial_metadata_recv2;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c2, ops, (size_t)(op - ops), tag(402), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  /* the second request is time out*/
+  CQ_EXPECT_COMPLETION(cqv, tag(401), 0);
+  CQ_EXPECT_COMPLETION(cqv, tag(402), 1);
+  cq_verify(cqv);
+
+  /* second request is finished because of time out, so destroy the second call
+   */
+  grpc_call_destroy(c2);
+
+  /* now reply the first call */
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  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_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  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;
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s1, ops, (size_t)(op - ops), tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(302), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  cq_verify(cqv);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_call_destroy(c1);
+  grpc_call_destroy(s1);
+
+  grpc_slice_unref(details1);
+  grpc_slice_unref(details2);
+  grpc_metadata_array_destroy(&initial_metadata_recv1);
+  grpc_metadata_array_destroy(&trailing_metadata_recv1);
+  grpc_metadata_array_destroy(&initial_metadata_recv2);
+  grpc_metadata_array_destroy(&trailing_metadata_recv2);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
 void max_concurrent_streams(grpc_end2end_test_config config) {
+  test_max_concurrent_streams_with_timeout_on_first(config);
+  test_max_concurrent_streams_with_timeout_on_second(config);
   test_max_concurrent_streams(config);
 }
 
diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc
index 4d045da..041cc0e 100644
--- a/test/cpp/util/cli_call.cc
+++ b/test/cpp/util/cli_call.cc
@@ -111,7 +111,7 @@
     return false;
   }
   std::vector<grpc::Slice> slices;
-  recv_buffer.Dump(&slices);
+  GPR_ASSERT(recv_buffer.Dump(&slices).ok());
 
   response->clear();
   for (size_t i = 0; i < slices.size(); i++) {
@@ -196,7 +196,7 @@
   }
 
   std::vector<grpc::Slice> slices;
-  recv_buffer.Dump(&slices);
+  GPR_ASSERT(recv_buffer.Dump(&slices).ok());
   response->clear();
   for (size_t i = 0; i < slices.size(); i++) {
     response->append(reinterpret_cast<const char*>(slices[i].begin()),
diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc
index d501c36..5dd1b00 100644
--- a/test/cpp/util/proto_file_parser.cc
+++ b/test/cpp/util/proto_file_parser.cc
@@ -83,7 +83,7 @@
                                  const grpc::string& protofiles)
     : has_error_(false),
       dynamic_factory_(new protobuf::DynamicMessageFactory()) {
-  std::vector<std::string> service_list;
+  std::vector<grpc::string> service_list;
   if (channel) {
     reflection_db_.reset(new grpc::ProtoReflectionDescriptorDatabase(channel));
     reflection_db_->GetServices(&service_list);