diff --git a/build.json b/build.json
index 943c5f27982085c76dced44b912726172f13d556..850b404408b68a701a608ce3f0b617b5455342d9 100644
--- a/build.json
+++ b/build.json
@@ -1895,6 +1895,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -1912,6 +1915,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -1970,6 +1976,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2208,6 +2217,9 @@
         "gpr_test_util",
         "gpr",
         "grpc++_test_config"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2226,6 +2238,9 @@
         "gpr_test_util",
         "gpr",
         "grpc++_test_config"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2240,6 +2255,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2344,6 +2362,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2362,6 +2383,9 @@
         "gpr_test_util",
         "gpr",
         "grpc++_test_config"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2380,6 +2404,9 @@
         "gpr_test_util",
         "gpr",
         "grpc++_test_config"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2431,6 +2458,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2480,6 +2510,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -2497,6 +2530,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
diff --git a/include/grpc++/dynamic_thread_pool.h b/include/grpc++/dynamic_thread_pool.h
index bc4e2d4d749da309e9e3c3888419bb1e6d23d492..f0cd35940f5dea7b171a0bc651482d746969355e 100644
--- a/include/grpc++/dynamic_thread_pool.h
+++ b/include/grpc++/dynamic_thread_pool.h
@@ -41,6 +41,7 @@
 #include <grpc++/thread_pool_interface.h>
 
 #include <list>
+#include <memory>
 #include <queue>
 
 namespace grpc {
diff --git a/include/grpc++/impl/sync_no_cxx11.h b/include/grpc++/impl/sync_no_cxx11.h
index fda668957ebc76e40483321d653d3f5d360f8f98..5869b04c765eb3554bdb68e7568837b3dee4ff0b 100644
--- a/include/grpc++/impl/sync_no_cxx11.h
+++ b/include/grpc++/impl/sync_no_cxx11.h
@@ -87,7 +87,7 @@ class condition_variable {
   ~condition_variable() { gpr_cv_destroy(&cv_); }
   void wait(lock_guard<mutex> &mu) {
     mu.locked = false;
-    gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME);
+    gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
     mu.locked = true;
   }
   void notify_one() { gpr_cv_signal(&cv_); }
diff --git a/include/grpc++/server_credentials.h b/include/grpc++/server_credentials.h
index 83ae9fd1eb0fd0c773580d8f56f638f97c3f4bf1..11acd67e8adad9443e23c10f1956473310a97db7 100644
--- a/include/grpc++/server_credentials.h
+++ b/include/grpc++/server_credentials.h
@@ -58,12 +58,15 @@ class ServerCredentials {
 
 // Options to create ServerCredentials with SSL
 struct SslServerCredentialsOptions {
+  SslServerCredentialsOptions() : force_client_auth(false) {}
+
   struct PemKeyCertPair {
     grpc::string private_key;
     grpc::string cert_chain;
   };
   grpc::string pem_root_certs;
   std::vector<PemKeyCertPair> pem_key_cert_pairs;
+  bool force_client_auth;
 };
 
 // Builds SSL ServerCredentials given SSL specific options
diff --git a/include/grpc/census.h b/include/grpc/census.h
index 379783905aa704bc64a7b2162928199a516a49e1..7603dfdce1c59141cf1637624bce3965bf1cb37b 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -44,26 +44,30 @@
 extern "C" {
 #endif
 
-/* Identify census functionality that can be enabled via census_initialize(). */
-enum census_functions {
-  CENSUS_NONE = 0,    /* Do not enable census. */
-  CENSUS_TRACING = 1, /* Enable census tracing. */
-  CENSUS_STATS = 2,   /* Enable Census stats collection. */
-  CENSUS_CPU = 4,     /* Enable Census CPU usage collection. */
-  CENSUS_ALL = CENSUS_TRACING | CENSUS_STATS | CENSUS_CPU
+/* Identify census features that can be enabled via census_initialize(). */
+enum census_features {
+  CENSUS_FEATURE_NONE = 0,    /* Do not enable census. */
+  CENSUS_FEATURE_TRACING = 1, /* Enable census tracing. */
+  CENSUS_FEATURE_STATS = 2,   /* Enable Census stats collection. */
+  CENSUS_FEATURE_CPU = 4,     /* Enable Census CPU usage collection. */
+  CENSUS_FEATURE_ALL =
+      CENSUS_FEATURE_TRACING | CENSUS_FEATURE_STATS | CENSUS_FEATURE_CPU
 };
 
-/* Shutdown and startup census subsystem. The 'functions' argument should be
- * the OR (|) of census_functions values. If census fails to initialize, then
+/** Shutdown and startup census subsystem. The 'features' argument should be
+ * the OR (|) of census_features values. If census fails to initialize, then
  * census_initialize() will return a non-zero value. It is an error to call
  * census_initialize() more than once (without an intervening
  * census_shutdown()). */
-int census_initialize(int functions);
-void census_shutdown();
+int census_initialize(int features);
+void census_shutdown(void);
 
-/* If any census feature has been initialized, this funtion will return a
- * non-zero value. */
-int census_available();
+/** Return the features supported by the current census implementation (not all
+ * features will be available on all platforms). */
+int census_supported(void);
+
+/** Return the census features currently enabled. */
+int census_enabled(void);
 
 /* Internally, Census relies on a context, which should be propagated across
  * RPC's. From the RPC subsystems viewpoint, this is an opaque data structure.
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 8e3bbbf4cbd631cb1a423c33601d8f4b578cc255..c548549159b4162a004222e3e4d0ea4d78009c49 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -471,8 +471,8 @@ char *grpc_channel_get_target(grpc_channel *channel);
     clients will want to simply pass NULL. See grpc_channel_args definition for
     more on this. The data in 'args' need only live through the invocation of
     this function. */
-grpc_channel *grpc_channel_create(const char *target,
-                                  const grpc_channel_args *args);
+grpc_channel *grpc_insecure_channel_create(const char *target,
+                                           const grpc_channel_args *args);
 
 /** Create a lame client: this client fails every operation attempted on it. */
 grpc_channel *grpc_lame_client_channel_create(const char *target);
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 29eddc57a867114914e52d714e3e6b0179c25b08..ff84050c6d73a7325340c4a1f067fa7e2ae6445e 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -87,7 +87,7 @@ typedef struct {
      directory).
    - pem_key_cert_pair is a pointer on the object containing client's private
      key and certificate chain. This parameter can be NULL if the client does
-     not have such a key/cert pair.  */
+     not have such a key/cert pair. */
 grpc_credentials *grpc_ssl_credentials_create(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair);
 
@@ -174,10 +174,13 @@ void grpc_server_credentials_release(grpc_server_credentials *creds);
    - pem_key_cert_pairs is an array private key / certificate chains of the
      server. This parameter cannot be NULL.
    - num_key_cert_pairs indicates the number of items in the private_key_files
-     and cert_chain_files parameters. It should be at least 1. */
+     and cert_chain_files parameters. It should be at least 1.
+   - force_client_auth, if set to non-zero will force the client to authenticate
+     with an SSL cert. Note that this option is ignored if pem_root_certs is
+     NULL. */
 grpc_server_credentials *grpc_ssl_server_credentials_create(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
-    size_t num_key_cert_pairs);
+    size_t num_key_cert_pairs, int force_client_auth);
 
 /* --- Server-side secure ports. --- */
 
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 724b69c703fb39b884b798da1ab5a4bda286faef..2982a89fad11b045717505b854f2e144d99b93b8 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -249,7 +249,7 @@ bool GetModuleAndMessagePath(const Descriptor* type,
   do {
     message_path.push_back(path_elem_type);
     path_elem_type = path_elem_type->containing_type();
-  } while (path_elem_type != nullptr);
+  } while (path_elem_type); // implicit nullptr comparison; don't be explicit
   grpc::string file_name = type->file()->name();
   static const int proto_suffix_length = strlen(".proto");
   if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
diff --git a/src/core/census/grpc_context.c b/src/core/census/grpc_context.c
index 0ed63469b649f78cd41722530af8cc2bdca3381f..d4243cb246f0577181d047bbdeb80dfe17565e74 100644
--- a/src/core/census/grpc_context.c
+++ b/src/core/census/grpc_context.c
@@ -39,7 +39,7 @@ static void grpc_census_context_destroy(void *context) {
 }
 
 void grpc_census_call_set_context(grpc_call *call, census_context *context) {
-  if (!census_available()) {
+  if (census_enabled() == CENSUS_FEATURE_NONE) {
     return;
   }
   if (context == NULL) {
diff --git a/src/core/census/initialize.c b/src/core/census/initialize.c
index 80165206417f2c7d6d86bba8381b1d8f546c55d3..8d60f790eb78813f75858e8e6ca772eaa7d5bea3 100644
--- a/src/core/census/initialize.c
+++ b/src/core/census/initialize.c
@@ -33,20 +33,25 @@
 
 #include <grpc/census.h>
 
-static int census_fns_enabled = CENSUS_NONE;
+static int features_enabled = CENSUS_FEATURE_NONE;
 
-int census_initialize(int functions) {
-  if (census_fns_enabled != CENSUS_NONE) {
+int census_initialize(int features) {
+  if (features_enabled != CENSUS_FEATURE_NONE) {
     return 1;
   }
-  if (functions != CENSUS_NONE) {
+  if (features != CENSUS_FEATURE_NONE) {
     return 1;
   } else {
-    census_fns_enabled = functions;
+    features_enabled = features;
     return 0;
   }
 }
 
-void census_shutdown() { census_fns_enabled = CENSUS_NONE; }
+void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; }
 
-int census_available() { return (census_fns_enabled != CENSUS_NONE); }
+int census_supported(void) {
+  /* TODO(aveitch): improve this as we implement features... */
+  return CENSUS_FEATURE_NONE;
+}
+
+int census_enabled(void) { return features_enabled; }
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index 4bf24e7db31b0d4b96bfe5cdf4e907d1be3c05f8..9fc8589fbb407773757173c0ab1458588cf0ccbb 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -284,19 +284,19 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
       grpc_channel_args_get_compression_algorithm(args);
 
   channeld->mdstr_request_compression_algorithm_key =
-      grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY);
+      grpc_mdstr_from_string(mdctx, GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, 0);
 
   channeld->mdstr_outgoing_compression_algorithm_key =
-      grpc_mdstr_from_string(mdctx, "grpc-encoding");
+      grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
 
   for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
-    char *algorith_name;
-    GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorith_name) != 0);
+    char *algorithm_name;
+    GPR_ASSERT(grpc_compression_algorithm_name(algo_idx, &algorithm_name) != 0);
     channeld->mdelem_compression_algorithms[algo_idx] =
         grpc_mdelem_from_metadata_strings(
             mdctx,
             grpc_mdstr_ref(channeld->mdstr_outgoing_compression_algorithm_key),
-            grpc_mdstr_from_string(mdctx, algorith_name));
+            grpc_mdstr_from_string(mdctx, algorithm_name, 0));
   }
 
   GPR_ASSERT(!is_last);
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 59a35d1e35009183f6f4c8e0a787b7502c0081ce..82232de51c1b5ca6721b2c9ee40060defcd2bb2f 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -244,7 +244,7 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx,
 
   tmp = gpr_strvec_flatten(&v, NULL);
   gpr_strvec_destroy(&v);
-  result = grpc_mdstr_from_string(mdctx, tmp);
+  result = grpc_mdstr_from_string(mdctx, tmp, 0);
   gpr_free(tmp);
 
   return result;
@@ -288,7 +288,7 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
       grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
   channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200");
   channeld->user_agent = grpc_mdelem_from_metadata_strings(
-      mdctx, grpc_mdstr_from_string(mdctx, "user-agent"),
+      mdctx, grpc_mdstr_from_string(mdctx, "user-agent", 0),
       user_agent_from_args(mdctx, channel_args));
 }
 
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 30b011a3a47b2503b9bdeea4487135a395eb3fca..0955ae319aad18046e96b4b6906b0ac7683eaa65 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -258,9 +258,9 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
   channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http");
   channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https");
   channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
-  channeld->path_key = grpc_mdstr_from_string(mdctx, ":path");
-  channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority");
-  channeld->host_key = grpc_mdstr_from_string(mdctx, "host");
+  channeld->path_key = grpc_mdstr_from_string(mdctx, ":path", 0);
+  channeld->authority_key = grpc_mdstr_from_string(mdctx, ":authority", 0);
+  channeld->host_key = grpc_mdstr_from_string(mdctx, "host", 0);
   channeld->content_type =
       grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
 
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index cc680507ffcde704d85d565fb4974d6bd3aeaa32..bcd2aa8536fa3481d4655de68a8bf660b9d45f1c 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -79,6 +79,8 @@ struct grpc_tcp_server {
 
   /* active port count: how many ports are actually still listening */
   int active_ports;
+  /* number of iomgr callbacks that have been explicitly scheduled during shutdown */
+  int iomgr_callbacks_pending;
 
   /* all listening ports */
   server_port *ports;
@@ -93,6 +95,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
   gpr_mu_init(&s->mu);
   gpr_cv_init(&s->cv);
   s->active_ports = 0;
+  s->iomgr_callbacks_pending = 0;
   s->cb = NULL;
   s->cb_arg = NULL;
   s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
@@ -112,10 +115,10 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s,
   for (i = 0; i < s->nports; i++) {
     server_port *sp = &s->ports[i];
     sp->shutting_down = 1;
-    grpc_winsocket_shutdown(sp->socket);
+    s->iomgr_callbacks_pending += grpc_winsocket_shutdown(sp->socket);
   }
   /* This happens asynchronously. Wait while that happens. */
-  while (s->active_ports) {
+  while (s->active_ports || s->iomgr_callbacks_pending) {
     gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
   }
   gpr_mu_unlock(&s->mu);
@@ -254,8 +257,16 @@ static void on_accept(void *arg, int from_iocp) {
 
   /* The general mechanism for shutting down is to queue abortion calls. While
      this is necessary in the read/write case, it's useless for the accept
-     case. Let's do nothing. */
-  if (!from_iocp) return;
+     case. We only need to adjust the pending callback count */
+  if (!from_iocp) {
+    gpr_mu_lock(&sp->server->mu);
+    GPR_ASSERT(sp->server->iomgr_callbacks_pending > 0);
+    if (0 == --sp->server->iomgr_callbacks_pending) {
+      gpr_cv_broadcast(&sp->server->cv);
+    }
+    gpr_mu_unlock(&sp->server->mu);
+    return;
+  }
 
   /* The IOCP notified us of a completed operation. Let's grab the results,
       and act accordingly. */
@@ -264,11 +275,12 @@ static void on_accept(void *arg, int from_iocp) {
                                             &transfered_bytes, FALSE, &flags);
   if (!wsa_success) {
     if (sp->shutting_down) {
-      /* During the shutdown case, we ARE expecting an error. So that's swell,
+      /* During the shutdown case, we ARE expecting an error. So that's well,
          and we can wake up the shutdown thread. */
       sp->shutting_down = 0;
       sp->socket->read_info.outstanding = 0;
       gpr_mu_lock(&sp->server->mu);
+      GPR_ASSERT(sp->server->active_ports > 0);
       if (0 == --sp->server->active_ports) {
         gpr_cv_broadcast(&sp->server->cv);
       }
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index 38ae74abecdb6604cbaa81e405be0c26736eda3b..5e0457a37b10800f5bee97d9a9facb788c00330c 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -368,7 +368,14 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
   return GRPC_ENDPOINT_WRITE_PENDING;
 }
 
-static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
+static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) {
+  (void) ps;
+  grpc_tcp *tcp = (grpc_tcp *) ep;
+  grpc_iocp_add_socket(tcp->socket);
+}
+
+static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) {
+  (void) pss;
   grpc_tcp *tcp = (grpc_tcp *) ep;
   grpc_iocp_add_socket(tcp->socket);
 }
@@ -402,8 +409,9 @@ static char *win_get_peer(grpc_endpoint *ep) {
 }
 
 static grpc_endpoint_vtable vtable = {win_notify_on_read, win_write,
-                                      win_add_to_pollset, win_shutdown,
-                                      win_destroy,        win_get_peer};
+                                      win_add_to_pollset, win_add_to_pollset_set,
+                                      win_shutdown,       win_destroy,
+                                      win_get_peer};
 
 grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
   grpc_tcp *tcp = (grpc_tcp *) gpr_malloc(sizeof(grpc_tcp));
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 9a69f53a5a3bc554e045865b7923c3772db4b3be..e86b5430b2ca90f5d9a8389bd1ec6abad279a26c 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -80,7 +80,7 @@ static void bubble_up_error(grpc_call_element *elem, const char *error_msg) {
   channel_data *chand = elem->channel_data;
   grpc_transport_stream_op_add_cancellation(
       &calld->op, GRPC_STATUS_UNAUTHENTICATED,
-      grpc_mdstr_from_string(chand->md_ctx, error_msg));
+      grpc_mdstr_from_string(chand->md_ctx, error_msg, 0));
   grpc_call_next_op(elem, &calld->op);
 }
 
@@ -316,10 +316,10 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
       (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
           sc, "client_auth_filter");
   chand->md_ctx = metadata_context;
-  chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority");
-  chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path");
-  chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message");
-  chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status");
+  chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority", 0);
+  chand->path_string = grpc_mdstr_from_string(chand->md_ctx, ":path", 0);
+  chand->error_msg_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-message", 0);
+  chand->status_key = grpc_mdstr_from_string(chand->md_ctx, "grpc-status", 0);
 }
 
 /* Destructor for channel data */
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 38612cf308e1b5ba0779de86f0dfaf989ed05be1..15268cefbe263c238aafc1229bbc8730e39d29ee 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -259,8 +259,10 @@ static void ssl_build_config(const char *pem_root_certs,
 
 static void ssl_build_server_config(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
-    size_t num_key_cert_pairs, grpc_ssl_server_config *config) {
+    size_t num_key_cert_pairs, int force_client_auth,
+    grpc_ssl_server_config *config) {
   size_t i;
+  config->force_client_auth = force_client_auth;
   if (pem_root_certs != NULL) {
     ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
                           &config->pem_root_certs_size);
@@ -302,14 +304,14 @@ grpc_credentials *grpc_ssl_credentials_create(
 
 grpc_server_credentials *grpc_ssl_server_credentials_create(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
-    size_t num_key_cert_pairs) {
+    size_t num_key_cert_pairs, int force_client_auth) {
   grpc_ssl_server_credentials *c =
       gpr_malloc(sizeof(grpc_ssl_server_credentials));
   memset(c, 0, sizeof(grpc_ssl_server_credentials));
   c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
   c->base.vtable = &ssl_server_vtable;
   ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
-                          num_key_cert_pairs, &c->config);
+                          num_key_cert_pairs, force_client_auth, &c->config);
   return &c->base;
 }
 
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index f6e423eb279e731ae354a3856b1909451abcd014..726b4c1e123128db7ddc0f8d2162940022605f36 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -653,9 +653,10 @@ grpc_security_status grpc_ssl_server_security_connector_create(
       config->pem_private_keys_sizes,
       (const unsigned char **)config->pem_cert_chains,
       config->pem_cert_chains_sizes, config->num_key_cert_pairs,
-      config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(),
-      alpn_protocol_strings, alpn_protocol_string_lengths,
-      (uint16_t)num_alpn_protocols, &c->handshaker_factory);
+      config->pem_root_certs, config->pem_root_certs_size,
+      config->force_client_auth, ssl_cipher_suites(), alpn_protocol_strings,
+      alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols,
+      &c->handshaker_factory);
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index a4c723f02608db349dce898e6b414ef3762089d6..2c9aa1c5a4e52dcd2afe06ca1994220f77bcafa1 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -201,6 +201,7 @@ typedef struct {
   size_t num_key_cert_pairs;
   unsigned char *pem_root_certs;
   size_t pem_root_certs_size;
+  int force_client_auth;
 } grpc_ssl_server_config;
 
 /* Creates an SSL server_security_connector.
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
index 284433037976690360a0c9cd15ac8d24629487af..f24e272207fa0ba1ed831dbbf279bd1f6a16c6b5 100644
--- a/src/core/support/stack_lockfree.c
+++ b/src/core/support/stack_lockfree.c
@@ -72,6 +72,11 @@ typedef union lockfree_node {
 struct gpr_stack_lockfree {
   lockfree_node *entries;
   lockfree_node head; /* An atomic entry describing curr head */
+
+#ifndef NDEBUG
+  /* Bitmap of pushed entries to check for double-push or pop */
+  gpr_atm pushed[(INVALID_ENTRY_INDEX+1)/(8*sizeof(gpr_atm))];
+#endif
 };
 
 gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
@@ -86,6 +91,9 @@ gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
   /* Clear out all entries */
   memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
   memset(&stack->head, 0, sizeof(stack->head));
+#ifndef NDEBUG
+  memset(&stack->pushed, 0, sizeof(stack->pushed));
+#endif
 
   /* Point the head at reserved dummy entry */
   stack->head.contents.index = INVALID_ENTRY_INDEX;
@@ -106,6 +114,19 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
   /* Also post-increment the aba_ctr */
   newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++;
 
+#ifndef NDEBUG
+  /* Check for double push */
+  {
+    int pushed_index = entry / (8*sizeof(gpr_atm));
+    int pushed_bit = entry % (8*sizeof(gpr_atm));
+    gpr_atm old_val;
+
+    old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
+					   (gpr_atm)(1UL << pushed_bit));
+    GPR_ASSERT((old_val & (1UL<<pushed_bit)) == 0);
+  }
+#endif
+
   do {
     /* Atomically get the existing head value for use */
     head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
@@ -119,6 +140,7 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
 int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
   lockfree_node head;
   lockfree_node newhead;
+
   do {
     head.atm = gpr_atm_acq_load(&(stack->head.atm));
     if (head.contents.index == INVALID_ENTRY_INDEX) {
@@ -128,5 +150,18 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
         gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
 
   } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
+#ifndef NDEBUG
+  /* Check for valid pop */
+  {
+    int pushed_index = head.contents.index / (8*sizeof(gpr_atm));
+    int pushed_bit = head.contents.index % (8*sizeof(gpr_atm));
+    gpr_atm old_val;
+
+    old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
+					   -(gpr_atm)(1UL << pushed_bit));
+    GPR_ASSERT((old_val & (1UL<<pushed_bit)) != 0);
+  }
+#endif
+
   return head.contents.index;
 }
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index a1da8221132fa1ffb68a6e0a1b9f12a5cdac7734..12378f0066322da8320dc999be8d873e79fe8e21 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -932,7 +932,7 @@ static int prepare_application_metadata(grpc_call *call, size_t count,
     GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
     l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key,
                                                (const gpr_uint8 *)md->value,
-                                               md->value_length);
+                                               md->value_length, 1);
     if (!grpc_mdstr_is_legal_header(l->md->key)) {
       gpr_log(GPR_ERROR, "attempt to send invalid metadata key");
       return 0;
@@ -1203,7 +1203,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
 static grpc_call_error cancel_with_status(grpc_call *c, grpc_status_code status,
                                           const char *description) {
   grpc_mdstr *details =
-      description ? grpc_mdstr_from_string(c->metadata_context, description)
+      description ? grpc_mdstr_from_string(c->metadata_context, description, 0)
                   : NULL;
 
   GPR_ASSERT(status != GRPC_STATUS_OK);
@@ -1497,7 +1497,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
             op->data.send_status_from_server.status_details != NULL
                 ? grpc_mdstr_from_string(
                       call->metadata_context,
-                      op->data.send_status_from_server.status_details)
+                      op->data.send_status_from_server.status_details, 0)
                 : NULL;
         req = &reqs[out++];
         req->op = GRPC_IOREQ_SEND_CLOSE;
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index a84d33072361f903bdb282b3f6bbc5a3b92cc34b..81f673f856efde5c1f2ec63c106a0f68131b49e5 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -101,19 +101,19 @@ grpc_channel *grpc_channel_create_from_filters(
   /* decremented by grpc_channel_destroy */
   gpr_ref_init(&channel->refs, 1);
   channel->metadata_context = mdctx;
-  channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
+  channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status", 0);
   channel->grpc_compression_algorithm_string =
-      grpc_mdstr_from_string(mdctx, "grpc-encoding");
-  channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message");
+      grpc_mdstr_from_string(mdctx, "grpc-encoding", 0);
+  channel->grpc_message_string = grpc_mdstr_from_string(mdctx, "grpc-message", 0);
   for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
     char buf[GPR_LTOA_MIN_BUFSIZE];
     gpr_ltoa(i, buf);
     channel->grpc_status_elem[i] = grpc_mdelem_from_metadata_strings(
         mdctx, GRPC_MDSTR_REF(channel->grpc_status_string),
-        grpc_mdstr_from_string(mdctx, buf));
+        grpc_mdstr_from_string(mdctx, buf, 0));
   }
-  channel->path_string = grpc_mdstr_from_string(mdctx, ":path");
-  channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
+  channel->path_string = grpc_mdstr_from_string(mdctx, ":path", 0);
+  channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority", 0);
   gpr_mu_init(&channel->registered_call_mu);
   channel->registered_calls = NULL;
 
@@ -170,11 +170,11 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
       channel, cq,
       grpc_mdelem_from_metadata_strings(
           channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
-          grpc_mdstr_from_string(channel->metadata_context, method)),
+          grpc_mdstr_from_string(channel->metadata_context, method, 0)),
       host ?
       grpc_mdelem_from_metadata_strings(
           channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
-          grpc_mdstr_from_string(channel->metadata_context, host)) : NULL,
+          grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL,
       deadline);
 }
 
@@ -183,10 +183,10 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
   registered_call *rc = gpr_malloc(sizeof(registered_call));
   rc->path = grpc_mdelem_from_metadata_strings(
       channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
-      grpc_mdstr_from_string(channel->metadata_context, method));
+      grpc_mdstr_from_string(channel->metadata_context, method, 0));
   rc->authority = host ? grpc_mdelem_from_metadata_strings(
       channel->metadata_context, GRPC_MDSTR_REF(channel->authority_string),
-      grpc_mdstr_from_string(channel->metadata_context, host)) : NULL;
+      grpc_mdstr_from_string(channel->metadata_context, host, 0)) : NULL;
   gpr_mu_lock(&channel->registered_call_mu);
   rc->next = channel->registered_calls;
   channel->registered_calls = rc;
@@ -288,7 +288,7 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
     gpr_ltoa(i, tmp);
     return grpc_mdelem_from_metadata_strings(
         channel->metadata_context, GRPC_MDSTR_REF(channel->grpc_status_string),
-        grpc_mdstr_from_string(channel->metadata_context, tmp));
+        grpc_mdstr_from_string(channel->metadata_context, tmp, 0));
   }
 }
 
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index fdc2185e1482715065dd9cc9ab69f05943d5c017..707d6156884e02d861b879b0c54bcab56d5a65eb 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -154,8 +154,8 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
    Asynchronously: - resolve target
                    - connect to it (trying alternatives as presented)
                    - perform handshakes */
-grpc_channel *grpc_channel_create(const char *target,
-                                  const grpc_channel_args *args) {
+grpc_channel *grpc_insecure_channel_create(const char *target,
+                                           const grpc_channel_args *args) {
   grpc_channel *channel = NULL;
 #define MAX_FILTERS 3
   const grpc_channel_filter *filters[MAX_FILTERS];
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index a015262612aba10d7d24e664514a0b6a49fab5ac..442bc72f2139255d1835c627c6df888587c86fbf 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -80,8 +80,11 @@ void grpc_init(void) {
     grpc_security_pre_init();
     grpc_iomgr_init();
     grpc_tracer_init("GRPC_TRACE");
-    if (census_initialize(CENSUS_NONE)) {
-      gpr_log(GPR_ERROR, "Could not initialize census.");
+    /* Only initialize census if noone else has. */
+    if (census_enabled() == CENSUS_FEATURE_NONE) {
+      if (census_initialize(census_supported())) { /* enable all features. */
+        gpr_log(GPR_ERROR, "Could not initialize census.");
+      }
     }
     grpc_timers_global_init();
   }
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index 335e66a8c299a3d8d1dcbe370ae372c512253061..57db7393d54c919cf627b905a17b16793d2aa543 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -690,8 +690,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
   GPR_ASSERT(!is_last);
   chand->server = NULL;
   chand->channel = NULL;
-  chand->path_key = grpc_mdstr_from_string(metadata_context, ":path");
-  chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority");
+  chand->path_key = grpc_mdstr_from_string(metadata_context, ":path", 0);
+  chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority", 0);
   chand->next = chand->prev = chand;
   chand->registered_methods = NULL;
   chand->connectivity_state = GRPC_CHANNEL_IDLE;
@@ -913,8 +913,8 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
     chand->registered_methods = gpr_malloc(alloc);
     memset(chand->registered_methods, 0, alloc);
     for (rm = s->registered_methods; rm; rm = rm->next) {
-      host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host) : NULL;
-      method = grpc_mdstr_from_string(mdctx, rm->method);
+      host = rm->host ? grpc_mdstr_from_string(mdctx, rm->host, 0) : NULL;
+      method = grpc_mdstr_from_string(mdctx, rm->method, 0);
       hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
       for (probes = 0; chand->registered_methods[(hash + probes) % slots]
                            .server_registered_method != NULL;
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 65b31a5afdfc69b971fcbffd598520a5eb95235f..0f04169741af7a467390176ea9e1aa816a3739f3 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -441,7 +441,7 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
       gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
   mdelem = grpc_mdelem_from_metadata_strings(
       c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str),
-      grpc_mdstr_from_string(c->mdctx, timeout_str));
+      grpc_mdstr_from_string(c->mdctx, timeout_str, 0));
   mdelem = hpack_enc(c, mdelem, st);
   if (mdelem) GRPC_MDELEM_UNREF(mdelem);
 }
@@ -456,7 +456,7 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
                                        grpc_mdctx *ctx) {
   memset(c, 0, sizeof(*c));
   c->mdctx = ctx;
-  c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout");
+  c->timeout_key_str = grpc_mdstr_from_string(ctx, "grpc-timeout", 0);
 }
 
 void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index ca100703d4576659846b00883eb38270a14d6aeb..1ea4a82c16f12797464bdb5a73b748bbe3492699 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -232,7 +232,7 @@ static void init_transport(grpc_chttp2_transport *t,
   t->global.pings.next = t->global.pings.prev = &t->global.pings;
   t->parsing.is_client = is_client;
   t->parsing.str_grpc_timeout =
-      grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
+      grpc_mdstr_from_string(t->metadata_context, "grpc-timeout", 0);
   t->parsing.deframe_state =
       is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
   t->writing.is_client = is_client;
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index e95b7a21f9aeb5d3f71ac06d13f9f5a62055b5f3..967fd4898c5be08ae21fa9a752a79b0ba9c5b0c8 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -309,7 +309,37 @@ static void slice_unref(void *p) {
   unlock(ctx);
 }
 
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) {
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int canonicalize_key) {
+  if (canonicalize_key) {
+    size_t len;
+    size_t i;
+    int canonical = 1;
+
+    for (i = 0; str[i]; i++) {
+      if (str[i] >= 'A' && str[i] <= 'Z') {
+        canonical = 0;
+        /* Keep going in loop just to get string length */
+      }
+    }
+    len = i;
+
+    if (canonical) {
+      return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, len);
+    } else {
+      char *copy = gpr_malloc(len);
+      grpc_mdstr *ret;
+      for (i = 0; i < len; i++) {
+        if (str[i] >= 'A' && str[i] <= 'Z') {
+          copy[i] = str[i] - 'A' + 'a';
+        } else {
+          copy[i] = str[i];
+        }
+      }
+      ret = grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)copy, len);
+      gpr_free(copy);
+      return ret;
+    }
+  }
   return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str));
 }
 
@@ -491,8 +521,8 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
 grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
                                       const char *value) {
   return grpc_mdelem_from_metadata_strings(ctx,
-                                           grpc_mdstr_from_string(ctx, key),
-                                           grpc_mdstr_from_string(ctx, value));
+                                           grpc_mdstr_from_string(ctx, key, 0),
+                                           grpc_mdstr_from_string(ctx, value, 0));
 }
 
 grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
@@ -504,9 +534,10 @@ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
 grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
                                                 const char *key,
                                                 const gpr_uint8 *value,
-                                                size_t value_length) {
+                                                size_t value_length,
+                                                int canonicalize_key) {
   return grpc_mdelem_from_metadata_strings(
-      ctx, grpc_mdstr_from_string(ctx, key),
+      ctx, grpc_mdstr_from_string(ctx, key, canonicalize_key),
       grpc_mdstr_from_buffer(ctx, value, value_length));
 }
 
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index 99b15322c39528226ddc9bab3e50eae2b595fe1f..15ef9bb555ee5aa80d598138a2b62b511519f8c2 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -95,7 +95,7 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx);
 
 /* Constructors for grpc_mdstr instances; take a variety of data types that
    clients may have handy */
-grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str);
+grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str, int perform_key_canonicalization);
 /* Unrefs the slice. */
 grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice);
 grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str,
@@ -117,7 +117,8 @@ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
 grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
                                                 const char *key,
                                                 const gpr_uint8 *value,
-                                                size_t value_length);
+                                                size_t value_length,
+                                                int canonicalize_key);
 
 /* Mutator and accessor for grpc_mdelem user data. The destructor function
    is used as a type tag and is checked during user_data fetch. */
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 6156a39d093684d88f4fb90086b78f61b0ec9f16..609fc06ed5d357737204a58dd3cb17f882abe0b0 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -1293,8 +1293,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
     const size_t* pem_private_keys_sizes, const unsigned char** pem_cert_chains,
     const size_t* pem_cert_chains_sizes, size_t key_cert_pair_count,
     const unsigned char* pem_client_root_certs,
-    size_t pem_client_root_certs_size, const char* cipher_list,
-    const unsigned char** alpn_protocols,
+    size_t pem_client_root_certs_size, int force_client_auth,
+    const char* cipher_list, const unsigned char** alpn_protocols,
     const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols,
     tsi_ssl_handshaker_factory** factory) {
   tsi_ssl_server_handshaker_factory* impl = NULL;
@@ -1349,6 +1349,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
       if (result != TSI_OK) break;
 
       if (pem_client_root_certs != NULL) {
+        int flags = SSL_VERIFY_PEER;
         STACK_OF(X509_NAME)* root_names = NULL;
         result = ssl_ctx_load_verification_certs(
             impl->ssl_contexts[i], pem_client_root_certs,
@@ -1358,7 +1359,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
           break;
         }
         SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
-        SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, NULL);
+        if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+        SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL);
         /* TODO(jboeuf): Add revocation verification. */
       }
 
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
index b2aa2f393e5a0c533003c5f36e985d244f0b2f7a..4bf6c81b75df253978c288169b8caedd2a54d917 100644
--- a/src/core/tsi/ssl_transport_security.h
+++ b/src/core/tsi/ssl_transport_security.h
@@ -107,10 +107,14 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
    - key_cert_pair_count indicates the number of items in the private_key_files
      and cert_chain_files parameters.
    - pem_client_roots is the buffer containing the PEM encoding of the client
-     root certificates. This parameter may be NULL in which case the server
-     will not ask the client to authenticate itself with a certificate (server-
-     only authentication mode).
-   - pem_client_roots_size is the size of the associated buffer.
+     root certificates. This parameter may be NULL in which case the server will
+     not authenticate the client. If not NULL, the force_client_auth parameter
+     specifies if the server will accept only authenticated clients or both
+     authenticated and non-authenticated clients.
+   - pem_client_root_certs_size is the size of the associated buffer.
+   - force_client_auth, if set to non-zero will force the client to authenticate
+     with an SSL cert. Note that this option is ignored if pem_client_root_certs
+     is NULL or pem_client_roots_certs_size is 0
    - cipher_suites contains an optional list of the ciphers that the server
      supports. The format of this string is described in:
      https://www.openssl.org/docs/apps/ciphers.html.
@@ -131,8 +135,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
     const size_t* pem_private_keys_sizes, const unsigned char** pem_cert_chains,
     const size_t* pem_cert_chains_sizes, size_t key_cert_pair_count,
     const unsigned char* pem_client_root_certs,
-    size_t pem_client_root_certs_size, const char* cipher_suites,
-    const unsigned char** alpn_protocols,
+    size_t pem_client_root_certs_size, int force_client_auth,
+    const char* cipher_suites, const unsigned char** alpn_protocols,
     const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols,
     tsi_ssl_handshaker_factory** factory);
 
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 5ad87845675f03ba65503d5b57b2a06f59155b4f..e802fa8034e3ff5fa9f4a7a7939dfe70e30f1695 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -49,7 +49,7 @@ class InsecureCredentialsImpl GRPC_FINAL : public Credentials {
     grpc_channel_args channel_args;
     args.SetChannelArgs(&channel_args);
     return std::shared_ptr<ChannelInterface>(new Channel(
-        target, grpc_channel_create(target.c_str(), &channel_args)));
+        target, grpc_insecure_channel_create(target.c_str(), &channel_args)));
   }
 
   // InsecureCredentials should not be applied to a call.
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index 3e262dd74f79b1e07ebf0568033785bf702975a4..32c45e228067b0f21d5724da2c4d3a804bf7123e 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -51,7 +51,8 @@ std::shared_ptr<ServerCredentials> SslServerCredentials(
   }
   grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create(
       options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
-      &pem_key_cert_pairs[0], pem_key_cert_pairs.size());
+      &pem_key_cert_pairs[0], pem_key_cert_pairs.size(),
+      options.force_client_auth);
   return std::shared_ptr<ServerCredentials>(
       new SecureServerCredentials(c_creds));
 }
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index afb8204c07e2c97ef2da170788edb502228c625b..8e5036832d5e0c66e4bd198e2a21972b2a10d3c5 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -24,13 +24,22 @@
     <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="BouncyCastle.Crypto">
       <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
@@ -79,7 +88,7 @@
     </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="GoogleCredential.cs" />
-    <Compile Include="OAuth2InterceptorFactory.cs" />
+    <Compile Include="OAuth2Interceptors.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index eeaa49aa92a5ae3d9715f88df494827bab37a5e2..2dc10d24c27460e5f81f2861b9c45f802c8aa06d 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -20,9 +20,9 @@
     </dependencies>
   </metadata>
   <files>
-    <file src="bin/Release/Grpc.Auth.dll" target="lib/net45" />
-	<file src="bin/Release/Grpc.Auth.pdb" target="lib/net45" />
-	<file src="bin/Release/Grpc.Auth.xml" target="lib/net45" />
+    <file src="bin/ReleaseSigned/Grpc.Auth.dll" target="lib/net45" />
+	<file src="bin/ReleaseSigned/Grpc.Auth.pdb" target="lib/net45" />
+	<file src="bin/ReleaseSigned/Grpc.Auth.xml" target="lib/net45" />
 	<file src="**\*.cs" target="src" />
   </files>
 </package>
diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
similarity index 79%
rename from src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
rename to src/csharp/Grpc.Auth/OAuth2Interceptors.cs
index 420c4cb5371f67740223025d4428574ec0cdb0d8..c785ca5a16bcf09b4f91127dddc5e948129ff7dc 100644
--- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
+++ b/src/csharp/Grpc.Auth/OAuth2Interceptors.cs
@@ -47,17 +47,31 @@ using Grpc.Core.Utils;
 
 namespace Grpc.Auth
 {
-    public static class OAuth2InterceptorFactory
+    public static class OAuth2Interceptors
     {
         /// <summary>
-        /// Creates OAuth2 interceptor.
+        /// Creates OAuth2 interceptor that will obtain access token from GoogleCredentials.
         /// </summary>
-        public static MetadataInterceptorDelegate Create(GoogleCredential googleCredential)
+        public static MetadataInterceptorDelegate FromCredential(GoogleCredential googleCredential)
         {
             var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default);
             return new MetadataInterceptorDelegate(interceptor.InterceptHeaders);
         }
 
+        /// <summary>
+        /// Creates OAuth2 interceptor that will use given OAuth2 token.
+        /// </summary>
+        /// <param name="oauth2Token"></param>
+        /// <returns></returns>
+        public static MetadataInterceptorDelegate FromAccessToken(string oauth2Token)
+        {
+            Preconditions.CheckNotNull(oauth2Token);
+            return new MetadataInterceptorDelegate((metadata) =>
+            {
+                metadata.Add(OAuth2Interceptor.CreateBearerTokenHeader(oauth2Token));
+            });
+        }
+
         /// <summary>
         /// Injects OAuth2 authorization header into initial metadata (= request headers).
         /// </summary>
@@ -97,8 +111,15 @@ namespace Grpc.Auth
             public void InterceptHeaders(Metadata metadata)
             {
                 var accessToken = GetAccessToken(CancellationToken.None);
-                metadata.Add(new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken));
+                metadata.Add(CreateBearerTokenHeader(accessToken));
+            }
+
+            public static Metadata.Entry CreateBearerTokenHeader(string accessToken)
+            {
+                return new Metadata.Entry(AuthorizationHeader, Schema + " " + accessToken);
             }
         }
+
+
     }
 }
diff --git a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
index 70cb32d5b2bd29f4ac51a91e50700e6ea45fd252..83396c546b62aac31e83d57146a962c8d37792df 100644
--- a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
@@ -9,5 +9,3 @@ using System.Runtime.CompilerServices;
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-
-[assembly: InternalsVisibleTo("Grpc.Auth.Tests")]
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index e286ea519f9522d7c39a45e1aa9b52d9fb482ee6..540fe756c070e0149c2bc6fc1325ec9ebf55e125 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -209,8 +209,8 @@ namespace Grpc.Core.Tests
         {
             var headers = new Metadata
             {
-                new Metadata.Entry("asciiHeader", "abcdefg"),
-                new Metadata.Entry("binaryHeader-bin", new byte[] { 1, 2, 3, 0, 0xff }),
+                new Metadata.Entry("ascii-header", "abcdefg"),
+                new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }),
             };
             var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, headers);
             var call = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None);
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 1c4cca8b698e2ca2c47d1c4ec1f30998e3cbf61f..242a60d098df79977d170b308cf69776f3a7a70a 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -17,15 +17,22 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="nunit.core">
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 0d879e9b1e0f3e5362efeab4cd8edf8eccd942b5..940a6b8ac09ed6b01bec10359f55e880f5dcaf42 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -21,15 +21,23 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <DefineConstants>SIGNED</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 5ace6dcf8942d37a9704a6d10722a196b5a7cc36..086776f69db393dd83f4b057efd8e2bac6345196 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -21,9 +21,9 @@
     </dependencies>
   </metadata>
   <files>
-    <file src="bin/Release/Grpc.Core.dll" target="lib/net45" />
-	<file src="bin/Release/Grpc.Core.pdb" target="lib/net45" />
-	<file src="bin/Release/Grpc.Core.xml" target="lib/net45" />
+    <file src="bin/ReleaseSigned/Grpc.Core.dll" target="lib/net45" />
+	<file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
+	<file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
 	<file src="**\*.cs" target="src" />
   </files>
 </package>
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 2b3d7530f2cf0037457d38991123c5dbf7ce6fe9..29db85d7aae3e4eb88f72075bc4d64a11e4dcb7a 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -10,4 +10,12 @@ using System.Runtime.CompilerServices;
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
+#if SIGNED
+[assembly: InternalsVisibleTo("Grpc.Core.Tests,PublicKey=" +
+    "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
+    "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
+    "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
+    "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
+#else
 [assembly: InternalsVisibleTo("Grpc.Core.Tests")]
+#endif
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index 85996a570cdb595ac11b382b327ea53808b4c82e..b603e3af3c370d12feef457eb4a94434c0f9ebc5 100644
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -19,17 +19,22 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
-    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
-    <PlatformTarget>AnyCPU</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index 6c8856cc92136ea4c2e4e62581eaef74d8d90891..5f74b58773672c7a26569ddc35face653d3878d4 100644
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -19,17 +19,22 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
-    <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
-    <PlatformTarget>AnyCPU</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index d59d7515d1ffb886bf3402dbcb2b7bc3802066d9..9a8f780b245f82b928e21282e5ec3e72bf46eab2 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -19,15 +19,22 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="nunit.framework">
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 26f332c1cf7e30a9833465e3098103cc3ba1b914..242d29a9a5fb49796a482b924e1033437c25b69a 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -65,7 +65,7 @@ namespace math.Tests
             // for header support.
             client.HeaderInterceptor = (metadata) =>
             {
-                metadata.Add(new Metadata.Entry("customHeader", "abcdef"));
+                metadata.Add(new Metadata.Entry("custom-header", "abcdef"));
             };
         }
 
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index eaf24a253c09643dd6e85b6c118b12fff00644fc..c1aa40500e4465a33e310ca39c2c60d92e921d5b 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -19,15 +19,22 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index 72e110302b69e751c0d8c734456ef3f31503c742..c922ddfb9e73e81603e46c43d0258e1f93dc2585 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -17,7 +17,6 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
@@ -25,10 +24,18 @@
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="Google.ProtocolBuffers">
       <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 4ebb6446dd2d9a937bc92217a41f093d0daefa6a..0b7a7b91c6bed3ab6d529e988b59bfd21b6f0336 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -18,7 +18,6 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
@@ -26,10 +25,18 @@
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="Google.ProtocolBuffers">
       <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
index ca35b368053dab1e729e8b875236d6f15effc87c..acdfba42c81aac5b4dde7ad84193c0e75b2a09e8 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
@@ -20,9 +20,9 @@
     </dependencies>
   </metadata>
   <files>
-    <file src="bin/Release/Grpc.HealthCheck.dll" target="lib/net45" />
-	<file src="bin/Release/Grpc.HealthCheck.pdb" target="lib/net45" />
-	<file src="bin/Release/Grpc.HealthCheck.xml" target="lib/net45" />
+    <file src="bin/ReleaseSigned/Grpc.HealthCheck.dll" target="lib/net45" />
+	<file src="bin/ReleaseSigned/Grpc.HealthCheck.pdb" target="lib/net45" />
+	<file src="bin/ReleaseSigned/Grpc.HealthCheck.xml" target="lib/net45" />
 	<file src="**\*.cs" target="src" />
   </files>
 </package>
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index 37d53d61e0d950f4b780daf457340eafde545479..2c38c9645c5f7804e73a69fb4576f3eab46a6703 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -18,18 +18,25 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
     <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
     <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 0f3b9eb5101d0eca124248ac37355b93f4d4bb07..949ad61375c4c0c15562cc8ab5a358e8c8c99e98 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -18,18 +18,25 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
     <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
     <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index db2e304d373bcab7ff20946f41c6239c2b731598..abc27f811ed412ad6b4e81f947e5210ac6fd6cf2 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -18,18 +18,25 @@
     <DefineConstants>DEBUG;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
     <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>full</DebugType>
+    <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <Externalconsole>true</Externalconsole>
     <PlatformTarget>AnyCPU</PlatformTarget>
   </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\ReleaseSigned</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <SignAssembly>True</SignAssembly>
+    <AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="BouncyCastle.Crypto">
       <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 4f8a5a5da73e573b1e80d215d268a2608834f530..7411d91d5a7ae0e6f51ae15d23db79ac4df9c5da 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -127,7 +127,7 @@ namespace Grpc.IntegrationTesting
                     {
                         credential = credential.CreateScoped(new[] { AuthScope });
                     }
-                    client.HeaderInterceptor = OAuth2InterceptorFactory.Create(credential);
+                    client.HeaderInterceptor = OAuth2Interceptors.FromCredential(credential);
                 }
 
                 RunTestCaseAsync(options.testCase, client).Wait();
@@ -356,11 +356,7 @@ namespace Grpc.IntegrationTesting
             Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
             string oauth2Token = credential.Token.AccessToken;
 
-            // Intercept calls with an OAuth2 token obtained out-of-band.
-            client.HeaderInterceptor = new MetadataInterceptorDelegate((metadata) =>
-            {
-                metadata.Add(new Metadata.Entry("Authorization", "Bearer " + oauth2Token));
-            });
+            client.HeaderInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetFillUsername(true)
@@ -381,13 +377,16 @@ namespace Grpc.IntegrationTesting
             var credential = GoogleCredential.GetApplicationDefault().CreateScoped(new[] { AuthScope });
             Assert.IsTrue(credential.RequestAccessTokenAsync(CancellationToken.None).Result);
             string oauth2Token = credential.Token.AccessToken;
+            var headerInterceptor = OAuth2Interceptors.FromAccessToken(oauth2Token);
 
             var request = SimpleRequest.CreateBuilder()
                 .SetFillUsername(true)
                 .SetFillOauthScope(true)
                 .Build();
 
-            var response = client.UnaryCall(request, headers: new Metadata { new Metadata.Entry("Authorization", "Bearer " + oauth2Token) });
+            var headers = new Metadata();
+            headerInterceptor(headers);
+            var response = client.UnaryCall(request, headers: headers);
 
             Assert.AreEqual(AuthScopeResponse, response.OauthScope);
             Assert.AreEqual(ServiceAccountUser, response.Username);
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 0cd8aaef6d2b542e1b23ba8fa49bc39dcab45265..f19f29c6a27ccebfbdf884dde6c8d6c2040a1c63 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -36,58 +36,81 @@ Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
+		ReleaseSigned|Any CPU = ReleaseSigned|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
 		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
 		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{C61154BA-DD4A-4838-8420-0162A28925E0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
 		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
 		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{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
-	EndGlobalSection
-	GlobalSection(NestedProjects) = preSolution
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index c3e5fe8817dfe9f73d1352684a617c2f1982bf0b..9e1253bf0bda053b234db604dc795005ad33529c 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -12,7 +12,7 @@ cd ..\..\vsprojects\nuget_package
 @call buildall.bat || goto :error
 endlocal
 
-@call buildall.bat || goto :error
+@call buildall.bat BUILD_SIGNED || goto :error
 
 %NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
 %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
diff --git a/src/csharp/buildall.bat b/src/csharp/buildall.bat
index 16860aec3c3d78cd5f9d6a2261eda419c7a140cc..e73feb87b9da6053cfe9cb995f05819e381b1292 100644
--- a/src/csharp/buildall.bat
+++ b/src/csharp/buildall.bat
@@ -13,6 +13,11 @@ msbuild ..\..\vsprojects\grpc.sln /t:grpc_csharp_ext /p:PlatformToolset=v120 ||
 
 msbuild Grpc.sln /p:Configuration=Debug || goto :error
 msbuild Grpc.sln /p:Configuration=Release || goto :error
+
+if "%1" == "BUILD_SIGNED" (
+msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
+)
+
 endlocal
 
 goto :EOF
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 6d15124d2cc82d01f64c2f547ad86baff5edb03f..49a0471042cfef878341065bda80bfb808398ac7 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -366,8 +366,9 @@ grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) {
 /* Channel */
 
 GPR_EXPORT grpc_channel *GPR_CALLTYPE
+
 grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) {
-  return grpc_channel_create(target, args);
+  return grpc_insecure_channel_create(target, args);
 }
 
 GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_destroy(grpc_channel *channel) {
@@ -790,8 +791,9 @@ grpcsharp_ssl_server_credentials_create(
       key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i];
     }
   }
+  /* TODO: Add a force_client_auth parameter and pass it here. */
   creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs,
-                                             num_key_cert_pairs);
+                                             num_key_cert_pairs, 0);
   gpr_free(key_cert_pairs);
   return creds;
 }
diff --git a/src/csharp/keys/Grpc.public.snk b/src/csharp/keys/Grpc.public.snk
new file mode 100644
index 0000000000000000000000000000000000000000..bac3046b367212f394cd5ef7e9b802aeccc0d238
Binary files /dev/null and b/src/csharp/keys/Grpc.public.snk differ
diff --git a/src/csharp/keys/README.md b/src/csharp/keys/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3e9a3cb5614bd1de9354bb3fd6d22a835f426a5
--- /dev/null
+++ b/src/csharp/keys/README.md
@@ -0,0 +1,5 @@
+Contents
+--------
+
+- Grpc.public.snk:
+  Public key to verify strong name of gRPC assemblies.
\ No newline at end of file
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 0b7333e45025a3852c4cca9044a780baf3a1f275..c43b55f11527ce72bbbe98d5554de2267f7246f8 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -105,7 +105,7 @@ NAN_METHOD(Channel::New) {
     NanUtf8String *host = new NanUtf8String(args[0]);
     NanUtf8String *host_override = NULL;
     if (args[1]->IsUndefined()) {
-      wrapped_channel = grpc_channel_create(**host, NULL);
+      wrapped_channel = grpc_insecure_channel_create(**host, NULL);
     } else if (args[1]->IsObject()) {
       grpc_credentials *creds = NULL;
       Handle<Object> args_hash(args[1]->ToObject()->Clone());
@@ -150,7 +150,7 @@ NAN_METHOD(Channel::New) {
         }
       }
       if (creds == NULL) {
-        wrapped_channel = grpc_channel_create(**host, &channel_args);
+        wrapped_channel = grpc_insecure_channel_create(**host, &channel_args);
       } else {
         wrapped_channel =
             grpc_secure_channel_create(creds, **host, &channel_args);
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index 66aaa3300fc647ded7450d338555af4542dd84e6..c4a93a6465dd6782a8be10e84addee25915cfb95 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -138,8 +138,10 @@ NAN_METHOD(ServerCredentials::CreateSsl) {
     return NanThrowTypeError("createSsl's third argument must be a Buffer");
   }
   key_cert_pair.cert_chain = ::node::Buffer::Data(args[2]);
+  // TODO Add a force_client_auth parameter and pass it as the last parameter
+  // here.
   NanReturnValue(WrapStruct(
-      grpc_ssl_server_credentials_create(root_certs, &key_cert_pair, 1)));
+      grpc_ssl_server_credentials_create(root_certs, &key_cert_pair, 1, 0)));
 }
 
 }  // namespace node
diff --git a/src/node/index.js b/src/node/index.js
index d81e780443fc44c5609ba8dc8c6d6427bd83f5c5..b26ab35f2c578cab438bedd2f3c7a8a4ec850431 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -48,7 +48,7 @@ var grpc = require('bindings')('grpc');
  * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
  * @return {Object<string, *>} The resulting gRPC object
  */
-function loadObject(value) {
+exports.loadObject = function loadObject(value) {
   var result = {};
   if (value.className === 'Namespace') {
     _.each(value.children, function(child) {
@@ -62,7 +62,9 @@ function loadObject(value) {
   } else {
     return value;
   }
-}
+};
+
+var loadObject = exports.loadObject;
 
 /**
  * Load a gRPC object from a .proto file.
@@ -71,7 +73,7 @@ function loadObject(value) {
  *     'json'. Defaults to 'proto'
  * @return {Object<string, *>} The resulting gRPC object
  */
-function load(filename, format) {
+exports.load = function load(filename, format) {
   if (!format) {
     format = 'proto';
   }
@@ -88,7 +90,7 @@ function load(filename, format) {
   }
 
   return loadObject(builder.ns);
-}
+};
 
 /**
  * Get a function that a client can use to update metadata with authentication
@@ -97,7 +99,7 @@ function load(filename, format) {
  * @param {Object} credential The credential object to use
  * @return {function(Object, callback)} Metadata updater function
  */
-function getGoogleAuthDelegate(credential) {
+exports.getGoogleAuthDelegate = function getGoogleAuthDelegate(credential) {
   /**
    * Update a metadata object with authentication information.
    * @param {string} authURI The uri to authenticate to
@@ -120,20 +122,10 @@ function getGoogleAuthDelegate(credential) {
       callback(null, metadata);
     });
   };
-}
-
-/**
- * See docs for loadObject
- */
-exports.loadObject = loadObject;
+};
 
 /**
- * See docs for load
- */
-exports.load = load;
-
-/**
- * See docs for Server
+ * @see module:src/server.Server
  */
 exports.Server = server.Server;
 
@@ -141,6 +133,7 @@ exports.Server = server.Server;
  * Status name to code number mapping
  */
 exports.status = grpc.status;
+
 /**
  * Call error name to code number mapping
  */
@@ -156,6 +149,7 @@ exports.Credentials = grpc.Credentials;
  */
 exports.ServerCredentials = grpc.ServerCredentials;
 
-exports.getGoogleAuthDelegate = getGoogleAuthDelegate;
-
+/**
+ * @see module:src/client.makeClientConstructor
+ */
 exports.makeGenericClientConstructor = client.makeClientConstructor;
diff --git a/src/node/jsdoc_conf.json b/src/node/jsdoc_conf.json
new file mode 100644
index 0000000000000000000000000000000000000000..876a8e19c6e0efc4615c0659651e264ec0b8910a
--- /dev/null
+++ b/src/node/jsdoc_conf.json
@@ -0,0 +1,22 @@
+{
+  "tags": {
+    "allowUnknownTags": true
+  },
+  "source": {
+    "include": [ "index.js", "src" ],
+    "includePattern": ".+\\.js(doc)?$",
+    "excludePattern": "(^|\\/|\\\\)_"
+  },
+  "opts": {
+    "package": "package.json",
+    "readme": "README.md"
+  },
+  "plugins": [],
+  "templates": {
+    "cleverLinks": false,
+    "monospaceLinks": false,
+    "default": {
+      "outputSourceFiles": true
+    }
+  }
+}
diff --git a/src/node/package.json b/src/node/package.json
index 1caf15879231c1a8007ef488f8d5d380646fd8ca..756d41b0af2a483e468faa648cf7358eb52f715b 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -21,7 +21,8 @@
   },
   "scripts": {
     "lint": "node ./node_modules/jshint/bin/jshint src test examples interop index.js",
-    "test": "node ./node_modules/mocha/bin/mocha && npm run-script lint"
+    "test": "node ./node_modules/mocha/bin/mocha && npm run-script lint",
+    "gen_docs": "./node_modules/.bin/jsdoc -c jsdoc_conf.json"
   },
   "dependencies": {
     "bindings": "^1.2.0",
@@ -32,6 +33,7 @@
   "devDependencies": {
     "async": "^0.9.0",
     "google-auth-library": "^0.9.2",
+    "jsdoc": "^3.3.2",
     "jshint": "^2.5.0",
     "minimist": "^1.1.0",
     "mocha": "~1.21.0",
diff --git a/src/node/src/client.js b/src/node/src/client.js
index d89c656c07e6c7be24beb4efd814004236a1947d..f843669bd0fca37a79cccb7c9c00cd9b8f7e6737 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -31,6 +31,11 @@
  *
  */
 
+/**
+ * Server module
+ * @module
+ */
+
 'use strict';
 
 var _ = require('lodash');
@@ -72,6 +77,7 @@ function ClientWritableStream(call, serialize) {
 /**
  * Attempt to write the given chunk. Calls the callback when done. This is an
  * implementation of a method needed for implementing stream.Writable.
+ * @access private
  * @param {Buffer} chunk The chunk to write
  * @param {string} encoding Ignored
  * @param {function(Error=)} callback Called when the write is complete
@@ -110,6 +116,7 @@ function ClientReadableStream(call, deserialize) {
 
 /**
  * Read the next object from the stream.
+ * @access private
  * @param {*} size Ignored because we use objectMode=true
  */
 function _read(size) {
@@ -519,7 +526,7 @@ var requester_makers = {
  * @param {string} serviceName The name of the service
  * @return {function(string, Object)} New client constructor
  */
-function makeClientConstructor(methods, serviceName) {
+exports.makeClientConstructor = function(methods, serviceName) {
   /**
    * Create a client with the given methods
    * @constructor
@@ -568,7 +575,7 @@ function makeClientConstructor(methods, serviceName) {
   });
 
   return Client;
-}
+};
 
 /**
  * Creates a constructor for clients for the given service
@@ -576,22 +583,18 @@ function makeClientConstructor(methods, serviceName) {
  *     for
  * @return {function(string, Object)} New client constructor
  */
-function makeProtobufClientConstructor(service) {
+exports.makeProtobufClientConstructor =  function(service) {
   var method_attrs = common.getProtobufServiceAttrs(service, service.name);
-  var Client = makeClientConstructor(method_attrs);
+  var Client = exports.makeClientConstructor(method_attrs);
   Client.service = service;
-
   return Client;
-}
-
-exports.makeClientConstructor = makeClientConstructor;
-
-exports.makeProtobufClientConstructor = makeProtobufClientConstructor;
+};
 
 /**
- * See docs for client.status
+ * Map of status code names to status codes
  */
 exports.status = grpc.status;
+
 /**
  * See docs for client.callError
  */
diff --git a/src/node/src/common.js b/src/node/src/common.js
index feaa859a4f4e264a8dc7752ed3ca6dcd94030c39..5551ebeec84998cfd63f55a58a165be8d9c286c0 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -31,6 +31,10 @@
  *
  */
 
+/**
+ * @module
+ */
+
 'use strict';
 
 var _ = require('lodash');
@@ -40,7 +44,7 @@ var _ = require('lodash');
  * @param {function()} cls The constructor of the message type to deserialize
  * @return {function(Buffer):cls} The deserialization function
  */
-function deserializeCls(cls) {
+exports.deserializeCls = function deserializeCls(cls) {
   /**
    * Deserialize a buffer to a message object
    * @param {Buffer} arg_buf The buffer to deserialize
@@ -51,14 +55,16 @@ function deserializeCls(cls) {
     // and longs as strings (second argument)
     return cls.decode(arg_buf).toRaw(false, true);
   };
-}
+};
+
+var deserializeCls = exports.deserializeCls;
 
 /**
  * Get a function that serializes objects to a buffer by protobuf class.
  * @param {function()} Cls The constructor of the message type to serialize
  * @return {function(Cls):Buffer} The serialization function
  */
-function serializeCls(Cls) {
+exports.serializeCls = function serializeCls(Cls) {
   /**
    * Serialize an object to a Buffer
    * @param {Object} arg The object to serialize
@@ -67,14 +73,16 @@ function serializeCls(Cls) {
   return function serialize(arg) {
     return new Buffer(new Cls(arg).encode().toBuffer());
   };
-}
+};
+
+var serializeCls = exports.serializeCls;
 
 /**
  * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
  * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
  * @return {string} The fully qualified name of the value
  */
-function fullyQualifiedName(value) {
+exports.fullyQualifiedName = function fullyQualifiedName(value) {
   if (value === null || value === undefined) {
     return '';
   }
@@ -89,7 +97,9 @@ function fullyQualifiedName(value) {
     }
   }
   return name;
-}
+};
+
+var fullyQualifiedName = exports.fullyQualifiedName;
 
 /**
  * Wrap a function to pass null-like values through without calling it. If no
@@ -97,7 +107,7 @@ function fullyQualifiedName(value) {
  * @param {?function} func The function to wrap
  * @return {function} The wrapped function
  */
-function wrapIgnoreNull(func) {
+exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
   if (!func) {
     return _.identity;
   }
@@ -107,14 +117,14 @@ function wrapIgnoreNull(func) {
     }
     return func(arg);
   };
-}
+};
 
 /**
  * Return a map from method names to method attributes for the service.
  * @param {ProtoBuf.Reflect.Service} service The service to get attributes for
  * @return {Object} The attributes map
  */
-function getProtobufServiceAttrs(service) {
+exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service) {
   var prefix = '/' + fullyQualifiedName(service) + '/';
   return _.object(_.map(service.children, function(method) {
     return [_.camelCase(method.name), {
@@ -127,26 +137,4 @@ function getProtobufServiceAttrs(service) {
       responseDeserialize: deserializeCls(method.resolvedResponseType.build())
     }];
   }));
-}
-
-/**
- * See docs for deserializeCls
- */
-exports.deserializeCls = deserializeCls;
-
-/**
- * See docs for serializeCls
- */
-exports.serializeCls = serializeCls;
-
-/**
- * See docs for fullyQualifiedName
- */
-exports.fullyQualifiedName = fullyQualifiedName;
-
-/**
- * See docs for wrapIgnoreNull
- */
-exports.wrapIgnoreNull = wrapIgnoreNull;
-
-exports.getProtobufServiceAttrs = getProtobufServiceAttrs;
+};
diff --git a/src/node/src/server.js b/src/node/src/server.js
index e876313d96cc00d9c21b4ba6137e93523ab18c61..9fbd1ee3bd5ed0159e8679dcf5669647c458248e 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -31,6 +31,11 @@
  *
  */
 
+/**
+ * Server module
+ * @module
+ */
+
 'use strict';
 
 var _ = require('lodash');
@@ -50,6 +55,7 @@ var EventEmitter = require('events').EventEmitter;
 
 /**
  * Handle an error on a call by sending it as a status
+ * @access private
  * @param {grpc.Call} call The call to send the error on
  * @param {Object} error The error object
  */
@@ -82,6 +88,7 @@ function handleError(call, error) {
 /**
  * Wait for the client to close, then emit a cancelled event if the client
  * cancelled.
+ * @access private
  * @param {grpc.Call} call The call object to wait on
  * @param {EventEmitter} emitter The event emitter to emit the cancelled event
  *     on
@@ -102,6 +109,7 @@ function waitForCancel(call, emitter) {
 
 /**
  * Send a response to a unary or client streaming call.
+ * @access private
  * @param {grpc.Call} call The call to respond on
  * @param {*} value The value to respond with
  * @param {function(*):Buffer=} serialize Serialization function for the
@@ -130,6 +138,7 @@ function sendUnaryResponse(call, value, serialize, metadata) {
 /**
  * Initialize a writable stream. This is used for both the writable and duplex
  * stream constructors.
+ * @access private
  * @param {Writable} stream The stream to set up
  * @param {function(*):Buffer=} Serialization function for responses
  */
@@ -203,6 +212,7 @@ function setUpWritable(stream, serialize) {
 /**
  * Initialize a readable stream. This is used for both the readable and duplex
  * stream constructors.
+ * @access private
  * @param {Readable} stream The stream to initialize
  * @param {function(Buffer):*=} deserialize Deserialization function for
  *     incoming data.
@@ -242,6 +252,7 @@ function ServerWritableStream(call, serialize) {
 /**
  * Start writing a chunk of data. This is an implementation of a method required
  * for implementing stream.Writable.
+ * @access private
  * @param {Buffer} chunk The chunk of data to write
  * @param {string} encoding Ignored
  * @param {function(Error=)} callback Callback to indicate that the write is
@@ -266,6 +277,11 @@ function _write(chunk, encoding, callback) {
 
 ServerWritableStream.prototype._write = _write;
 
+/**
+ * Send the initial metadata for a writable stream.
+ * @param {Object<String, Array<(String|Buffer)>>} responseMetadata Metadata
+ *   to send
+ */
 function sendMetadata(responseMetadata) {
   /* jshint validthis: true */
   if (!this.call.metadataSent) {
@@ -281,6 +297,10 @@ function sendMetadata(responseMetadata) {
   }
 }
 
+/**
+ * @inheritdoc
+ * @alias module:src/server~ServerWritableStream#sendMetadata
+ */
 ServerWritableStream.prototype.sendMetadata = sendMetadata;
 
 util.inherits(ServerReadableStream, Readable);
@@ -301,6 +321,7 @@ function ServerReadableStream(call, deserialize) {
 /**
  * Start reading from the gRPC data source. This is an implementation of a
  * method required for implementing stream.Readable
+ * @access private
  * @param {number} size Ignored
  */
 function _read(size) {
@@ -388,6 +409,7 @@ ServerDuplexStream.prototype.getPeer = getPeer;
 
 /**
  * Fully handle a unary call
+ * @access private
  * @param {grpc.Call} call The call to handle
  * @param {Object} handler Request handler object for the method that was called
  * @param {Object} metadata Metadata from the client
@@ -442,6 +464,7 @@ function handleUnary(call, handler, metadata) {
 
 /**
  * Fully handle a server streaming call
+ * @access private
  * @param {grpc.Call} call The call to handle
  * @param {Object} handler Request handler object for the method that was called
  * @param {Object} metadata Metadata from the client
@@ -470,6 +493,7 @@ function handleServerStreaming(call, handler, metadata) {
 
 /**
  * Fully handle a client streaming call
+ * @access private
  * @param {grpc.Call} call The call to handle
  * @param {Object} handler Request handler object for the method that was called
  * @param {Object} metadata Metadata from the client
@@ -504,6 +528,7 @@ function handleClientStreaming(call, handler, metadata) {
 
 /**
  * Fully handle a bidirectional streaming call
+ * @access private
  * @param {grpc.Call} call The call to handle
  * @param {Object} handler Request handler object for the method that was called
  * @param {Object} metadata Metadata from the client
@@ -587,7 +612,8 @@ function Server(options) {
     }
     server.requestCall(handleNewCall);
   };
-  /** Shuts down the server.
+  /**
+   * Shuts down the server.
    */
   this.shutdown = function() {
     server.shutdown();
@@ -621,6 +647,15 @@ Server.prototype.register = function(name, handler, serialize, deserialize,
   return true;
 };
 
+/**
+ * Add a service to the server, with a corresponding implementation. If you are
+ * generating this from a proto file, you should instead use
+ * addProtoService.
+ * @param {Object<String, *>} service The service descriptor, as
+ *     {@link module:src/common.getProtobufServiceAttrs} returns
+ * @param {Object<String, function>} implementation Map of method names to
+ *     method implementation for the provided service.
+ */
 Server.prototype.addService = function(service, implementation) {
   if (this.started) {
     throw new Error('Can\'t add a service to a started server.');
@@ -658,6 +693,12 @@ Server.prototype.addService = function(service, implementation) {
   });
 };
 
+/**
+ * Add a proto service to the server, with a corresponding implementation
+ * @param {Protobuf.Reflect.Service} service The proto service descriptor
+ * @param {Object<String, function>} implementation Map of method names to
+ *     method implementation for the provided service.
+ */
 Server.prototype.addProtoService = function(service, implementation) {
   this.addService(common.getProtobufServiceAttrs(service), implementation);
 };
@@ -681,6 +722,6 @@ Server.prototype.bind = function(port, creds) {
 };
 
 /**
- * See documentation for Server
+ * @see module:src/server~Server
  */
 exports.Server = Server;
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
index d27f7ca565badcd7c8230f410a4d0daca856cd4c..8518f78c5b23dd1496723632bef890a782456735 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
@@ -38,7 +38,7 @@
 @implementation GRPCUnsecuredChannel
 
 - (instancetype)initWithHost:(NSString *)host {
-  return (self = [super initWithChannel:grpc_channel_create(host.UTF8String, NULL)]);
+  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)]);
 }
 
 @end
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index b67bae75682f6b46aa0fb8abbc45ff59014f1245..1f76c7359d45bf371c415ceb4ccbdfab295431e3 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -472,6 +472,16 @@ cleanup:
   RETURN_DESTROY_ZVAL(result);
 }
 
+/**
+ * Get the endpoint this call/stream is connected to
+ * @return string The URI of the endpoint
+ */
+PHP_METHOD(Call, getPeer) {
+  wrapped_grpc_call *call =
+      (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
+  RETURN_STRING(grpc_call_get_peer(call->wrapped), 1);
+}
+
 /**
  * Cancel the call. This will cause the call to end with STATUS_CANCELLED if it
  * has not already ended with another status.
@@ -485,7 +495,9 @@ PHP_METHOD(Call, cancel) {
 static zend_function_entry call_methods[] = {
     PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
     PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
-    PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+    PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
+    PHP_FE_END};
 
 void grpc_init_call(TSRMLS_D) {
   zend_class_entry ce;
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index b8262db162bf48350cd0d05919904d099aff6b1f..7d8a6f87ab67359e2ab465812b908be8a02d0b21 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -152,7 +152,7 @@ PHP_METHOD(Channel, __construct) {
   override = target;
   override_len = target_length;
   if (args_array == NULL) {
-    channel->wrapped = grpc_channel_create(target, NULL);
+    channel->wrapped = grpc_insecure_channel_create(target, NULL);
   } else {
     array_hash = Z_ARRVAL_P(args_array);
     if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
@@ -182,7 +182,7 @@ PHP_METHOD(Channel, __construct) {
     }
     php_grpc_read_args_array(args_array, &args);
     if (creds == NULL) {
-      channel->wrapped = grpc_channel_create(target, &args);
+      channel->wrapped = grpc_insecure_channel_create(target, &args);
     } else {
       gpr_log(GPR_DEBUG, "Initialized secure channel");
       channel->wrapped =
@@ -194,6 +194,16 @@ PHP_METHOD(Channel, __construct) {
   memcpy(channel->target, override, override_len);
 }
 
+/**
+ * Get the endpoint this call/stream is connected to
+ * @return string The URI of the endpoint
+ */
+PHP_METHOD(Channel, getTarget) {
+  wrapped_grpc_channel *channel =
+      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+  RETURN_STRING(grpc_channel_get_target(channel->wrapped), 1);
+}
+
 /**
  * Close the channel
  */
@@ -208,7 +218,9 @@ PHP_METHOD(Channel, close) {
 
 static zend_function_entry channel_methods[] = {
     PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
-    PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+    PHP_ME(Channel, getTarget, NULL, ZEND_ACC_PUBLIC)
+    PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
+    PHP_FE_END};
 
 void grpc_init_channel(TSRMLS_D) {
   zend_class_entry ce;
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 4c4a598cb0c904477609416ac447bb1ec3ca28bf..e9183c45986cbc3d93d7bb46891b26a922bd490b 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -115,8 +115,10 @@ PHP_METHOD(ServerCredentials, createSsl) {
                          "createSsl expects 3 strings", 1 TSRMLS_CC);
     return;
   }
-  grpc_server_credentials *creds =
-      grpc_ssl_server_credentials_create(pem_root_certs, &pem_key_cert_pair, 1);
+  /* TODO: add a force_client_auth field in ServerCredentials and pass it as
+   * the last parameter. */
+  grpc_server_credentials *creds = grpc_ssl_server_credentials_create(
+      pem_root_certs, &pem_key_cert_pair, 1, 0);
   zval *creds_object = grpc_php_wrap_server_credentials(creds);
   RETURN_DESTROY_ZVAL(creds_object);
 }
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index 5b28417a0df479d442fd4e91f81bbdc2b5b35547..35057224f8ca021b16eaba9b702a477aaea8eca3 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -67,6 +67,13 @@ abstract class AbstractCall {
     return $this->metadata;
   }
 
+  /**
+   * @return string The URI of the endpoint.
+   */
+  public function getPeer() {
+    return $this->call->getPeer();
+  }
+
   /**
    * Cancels the call
    */
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 8c438e4bf92e6ac9a858a62f8de6d5c1e7b37d4d..a0c677908c7c4bc9714c8f5ffdc01401c1cf1d3b 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -67,6 +67,13 @@ class BaseStub {
     $this->channel = new Channel($hostname, $opts);
   }
 
+  /**
+   * @return string The URI of the endpoint.
+   */
+  public function getTarget() {
+    return $this->channel->getTarget();
+  }
+
   /**
    * Close the communication channel associated with this stub
    */
diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
index 6102aaf0a8b939041decab850cf7bf11b7ed59a6..8b7e67f57c25ffdbea4b1cec39e21ec6d1d33ed6 100644
--- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
+++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
@@ -43,7 +43,9 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
     $div_arg = new math\DivArgs();
     $div_arg->setDividend(7);
     $div_arg->setDivisor(4);
-    list($response, $status) = self::$client->Div($div_arg)->wait();
+    $call = self::$client->Div($div_arg);
+    $this->assertTrue(is_string($call->getPeer()));
+    list($response, $status) = $call->wait();
     $this->assertSame(1, $response->getQuotient());
     $this->assertSame(3, $response->getRemainder());
     $this->assertSame(\Grpc\STATUS_OK, $status->code);
@@ -53,6 +55,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
     $fib_arg = new math\FibArgs();
     $fib_arg->setLimit(7);
     $call = self::$client->Fib($fib_arg);
+    $this->assertTrue(is_string($call->getPeer()));
     $result_array = iterator_to_array($call->responses());
     $extract_num = function($num){
       return $num->getNum();
@@ -72,6 +75,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
       }
     };
     $call = self::$client->Sum($num_iter());
+    $this->assertTrue(is_string($call->getPeer()));
     list($response, $status) = $call->wait();
     $this->assertSame(21, $response->getNum());
     $this->assertSame(\Grpc\STATUS_OK, $status->code);
@@ -79,6 +83,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
 
   public function testBidiStreaming() {
     $call = self::$client->DivMany();
+    $this->assertTrue(is_string($call->getPeer()));
     for ($i = 0; $i < 7; $i++) {
       $div_arg = new math\DivArgs();
       $div_arg->setDividend(2 * $i + 1);
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 20415775574c3f1c77b68dccc3388ec30a7de71e..44e6242c299e54d079ae17ae4d3bff32fffc4332 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -332,10 +332,11 @@ if (in_array($args['test_case'], array(
   $opts['update_metadata'] = $auth->getUpdateMetadataFunc();
 }
 
-$stub = new grpc\testing\TestServiceClient(
-    new Grpc\BaseStub(
-        $server_address,
-        $opts));
+$internal_stub = new Grpc\BaseStub($server_address, $opts);
+hardAssert(is_string($internal_stub->getTarget()),
+           'Unexpected target URI value');
+
+$stub = new grpc\testing\TestServiceClient($internal_stub);
 
 echo "Connecting to $server_address\n";
 echo "Running test case $args[test_case]\n";
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index 77a2d86ce4cb5896a0812126d3f8df98f175d604..caff15ee110f6ac2a0fb076d1e48af5e8de4d109 100755
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -79,4 +79,8 @@ class CallTest extends PHPUnit_Framework_TestCase{
     $result = $this->call->startBatch($batch);
     $this->assertTrue($result->send_metadata);
   }
+
+  public function testGetPeer() {
+    $this->assertTrue(is_string($this->call->getPeer()));
+  }
 }
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 2980dca4a750cc4c3b9b5d7f2cfb054d20b10400..27e27cdfdf313f8bb757f697fb0d2900b1531956 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -34,8 +34,8 @@
 class EndToEndTest extends PHPUnit_Framework_TestCase{
   public function setUp() {
     $this->server = new Grpc\Server([]);
-    $port = $this->server->addHttp2Port('0.0.0.0:0');
-    $this->channel = new Grpc\Channel('localhost:' . $port, []);
+    $this->port = $this->server->addHttp2Port('0.0.0.0:0');
+    $this->channel = new Grpc\Channel('localhost:' . $this->port, []);
     $this->server->start();
   }
 
@@ -149,4 +149,8 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
     unset($call);
     unset($server_call);
   }
+
+  public function testGetTarget() {
+    $this->assertTrue(is_string($this->channel->getTarget()));
+  }
 }
diff --git a/src/python/src/grpc/_adapter/_c/types/channel.c b/src/python/src/grpc/_adapter/_c/types/channel.c
index c235597466c9a24a525603f8fab56fc25635a7df..feb256cf00095e147f5a529de87008f64d2d9604 100644
--- a/src/python/src/grpc/_adapter/_c/types/channel.c
+++ b/src/python/src/grpc/_adapter/_c/types/channel.c
@@ -104,7 +104,7 @@ Channel *pygrpc_Channel_new(
   if (creds) {
     self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args);
   } else {
-    self->c_chan = grpc_channel_create(target, &c_args);
+    self->c_chan = grpc_insecure_channel_create(target, &c_args);
   }
   pygrpc_discard_channel_args(c_args);
   return self;
diff --git a/src/python/src/grpc/_adapter/_c/types/server_credentials.c b/src/python/src/grpc/_adapter/_c/types/server_credentials.c
index f22edbf18727b8ab579d0604c8e239a7942b95f6..f6859b79d7da994e66daabf9669f00e638b5fa54 100644
--- a/src/python/src/grpc/_adapter/_c/types/server_credentials.c
+++ b/src/python/src/grpc/_adapter/_c/types/server_credentials.c
@@ -128,8 +128,10 @@ ServerCredentials *pygrpc_ServerCredentials_ssl(
   }
 
   self = (ServerCredentials *)type->tp_alloc(type, 0);
+  /* TODO: Add a force_client_auth parameter in the python object and pass it
+     here as the last arg. */
   self->c_creds = grpc_ssl_server_credentials_create(
-      root_certs, key_cert_pairs, num_key_cert_pairs);
+      root_certs, key_cert_pairs, num_key_cert_pairs, 0);
   gpr_free(key_cert_pairs);
   return self;
 }
diff --git a/src/python/src/grpc/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py
index a49cd007bfa195589cf214e36ebbc645042759b1..9a8edfad0cbb4fd2650aed9a5b50bff0abf31804 100644
--- a/src/python/src/grpc/_adapter/_low_test.py
+++ b/src/python/src/grpc/_adapter/_low_test.py
@@ -97,7 +97,7 @@ class InsecureServerInsecureClient(unittest.TestCase):
     CLIENT_METADATA_BIN_VALUE = b'\0'*1000
     SERVER_INITIAL_METADATA_KEY = 'init_me_me_me'
     SERVER_INITIAL_METADATA_VALUE = 'whodawha?'
-    SERVER_TRAILING_METADATA_KEY = 'California_is_in_a_drought'
+    SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought'
     SERVER_TRAILING_METADATA_VALUE = 'zomg it is'
     SERVER_STATUS_CODE = _types.StatusCode.OK
     SERVER_STATUS_DETAILS = 'our work is never over'
diff --git a/src/python/src/grpc/_links/_proto_scenarios.py b/src/python/src/grpc/_links/_proto_scenarios.py
index ccf3c297824187587ce4c64b2638085a33ff43a8..320c0e0f5067c82212b7986005a88404f26e247a 100644
--- a/src/python/src/grpc/_links/_proto_scenarios.py
+++ b/src/python/src/grpc/_links/_proto_scenarios.py
@@ -33,6 +33,7 @@ import abc
 import threading
 
 from grpc._junkdrawer import math_pb2
+from grpc.framework.common import test_constants
 
 
 class ProtoScenario(object):
@@ -219,10 +220,9 @@ class BidirectionallyUnaryScenario(ProtoScenario):
 class BidirectionallyStreamingScenario(ProtoScenario):
   """A scenario that transmits no protocol buffers in either direction."""
 
-  _STREAM_LENGTH = 200
   _REQUESTS = tuple(
       math_pb2.DivArgs(dividend=59 + index, divisor=7 + index)
-      for index in range(_STREAM_LENGTH))
+      for index in range(test_constants.STREAM_LENGTH))
 
   def __init__(self):
     self._lock = threading.Lock()
diff --git a/src/python/src/grpc/framework/common/test_constants.py b/src/python/src/grpc/framework/common/test_constants.py
index 237b8754ed2068645044be45a0dcbee64d713583..3126d0d82ce898efd78fdb7df55b42b60527020d 100644
--- a/src/python/src/grpc/framework/common/test_constants.py
+++ b/src/python/src/grpc/framework/common/test_constants.py
@@ -35,3 +35,9 @@ SHORT_TIMEOUT = 4
 # Absurdly large value for maximum duration in seconds for should-not-time-out
 # RPCs made during tests.
 LONG_TIMEOUT = 3000
+
+# The number of payloads to transmit in streaming tests.
+STREAM_LENGTH = 200
+
+# The size of thread pools to use in tests.
+POOL_SIZE = 10
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index bfb9f6ff01bf05a818522da821d7d51501219407..a7607a83a36fc43c5c0107ce8e739acdfecb86de 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -235,8 +235,8 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
 */
 static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
   grpc_metadata_array *md_ary = NULL;
-  int array_length;
-  int i;
+  long array_length;
+  long i;
 
   /* Construct a metadata object from key and value and add it */
   TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 9bf1a9f945c11d8c45d9ac9de2ea462c155cc145..0cb6fa2f800b741e5302c5cbffaea68e4d94c024 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -146,7 +146,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
   target_chars = StringValueCStr(target);
   grpc_rb_hash_convert_to_channel_args(channel_args, &args);
   if (credentials == Qnil) {
-    ch = grpc_channel_create(target_chars, &args);
+    ch = grpc_insecure_channel_create(target_chars, &args);
   } else {
     creds = grpc_rb_get_wrapped_credentials(credentials);
     ch = grpc_secure_channel_create(creds, target_chars, &args);
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 65d9c9a237b7b3127423aaedfdb23a9c0e0ad5c2..327fd1a4fc1b82afc8f5903d9b7b337a3f251b5c 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -139,7 +139,7 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
           rb_raise(rb_eRangeError, "%f out of Time range",
                    RFLOAT_VALUE(time));
         }
-        t.tv_nsec = (time_t)(d * 1e9 + 0.5);
+        t.tv_nsec = (int)(d * 1e9 + 0.5);
       }
       break;
 
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index 5f4093589077e2982cf7aa6284ccb490d9b83e11..62c211d7691022f21d6e6e09d05153945b3a1291 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -176,11 +176,12 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
   }
   key_cert_pair.private_key = RSTRING_PTR(pem_private_key);
   key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain);
+  /* TODO Add a force_client_auth parameter and pass it here. */
   if (pem_root_certs == Qnil) {
-    creds = grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1);
+    creds = grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1, 0);
   } else {
     creds = grpc_ssl_server_credentials_create(RSTRING_PTR(pem_root_certs),
-                                               &key_cert_pair, 1);
+                                               &key_cert_pair, 1, 0);
   }
   if (creds == NULL) {
     rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
diff --git a/templates/vsprojects/Grpc.mak.template b/templates/vsprojects/Grpc.mak.template
index 9d85376648b5c808fef67a672d53b8bed172968d..9d2f676d3804c9bfa7c265661f01d52dbd046d3a 100644
--- a/templates/vsprojects/Grpc.mak.template
+++ b/templates/vsprojects/Grpc.mak.template
@@ -33,16 +33,18 @@
 <%def name="to_windows_path(path)">${path.replace('/','\\')}</%def>\
 <%
   build_from_project_file = set(['gpr',
-                                 'grpc',
-                                 'grpc_unsecure',
                                  'gpr_test_util',
+                                 'grpc',
                                  'grpc_test_util',
                                  'grpc_test_util_unsecure',
+                                 'grpc_unsecure',
+                                 'grpc++',
+                                 'grpc++_unsecure'
                                 ])
   buildable_targets = [ target for target in targets + libs
                         if target.build in ['all', 'test', 'private', 'tool', 'benchmark'] and
                         target.language in ['c', 'c++'] and
-                        all([src.endswith('.c') for src in target.src]) and
+                        all([(src.endswith('.c') or src.endswith('.cc') or src.endswith('.proto')) for src in target.src]) and
                         'windows' in target.get('platforms', ['windows']) ]
   c_test_targets = [ target for target in buildable_targets if target.build == 'test' and not target.language == 'c++' ]
   cxx_test_targets = [ target for target in buildable_targets if target.build == 'test' and target.language == 'c++' ]
@@ -60,8 +62,19 @@ REPO_ROOT=..
 OPENSSL_INCLUDES = .\packages\${get_openssl()}\build\native\include
 ZLIB_INCLUDES = .\packages\${get_zlib()}\build\native\include
 INCLUDES=/I$(REPO_ROOT) /I$(REPO_ROOT)\include /I$(OPENSSL_INCLUDES) /I$(ZLIB_INCLUDES)
-DEFINES=/D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /D _CRT_SECURE_NO_WARNINGS
+
+GFLAGS_INCLUDES = .\..\third_party\gflags\include
+GTEST_INCLUDES = .\..\third_party\gtest\include
+PROTOBUF_INCLUDES = .\..\third_party\protobuf\src
+CXX_INCLUDES=/I$(GFLAGS_INCLUDES) /I$(GTEST_INCLUDES) /I$(PROTOBUF_INCLUDES)
+
+#_SCL_SECURE_NO_WARNINGS supresses a ton of "potentially unsafe use of std lib" warnings
+DEFINES=/D WIN32 /D _LIB /D _USE_32BIT_TIME_T /D _UNICODE /D UNICODE /D _CRT_SECURE_NO_WARNINGS /D _SCL_SECURE_NO_WARNINGS
+
+#important options: /TC vs. /TP: compile as C vs. compile as C++
 CFLAGS=/c $(INCLUDES) /Z7 /W3 /WX- /sdl $(DEFINES) /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TC /analyze-
+CXXFLAGS=/c $(INCLUDES) $(CXX_INCLUDES) /Z7 /W3 /WX- /sdl $(DEFINES) /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Gd /TP /analyze-
+
 LFLAGS=/DEBUG /INCREMENTAL /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86
 
 OPENSSL_LIBS=.\packages\${get_openssl()}\build\native\lib\v120\Win32\Debug\static\ssleay32.lib .\packages\${get_openssl()}\build\native\lib\v120\Win32\Debug\static\libeay32.lib
@@ -70,6 +83,12 @@ GENERAL_LIBS=advapi32.lib comdlg32.lib gdi32.lib kernel32.lib odbc32.lib odbccp3
 ZLIB_LIBS=.\packages\${get_zlib()}\build\native\lib\v120\Win32\Debug\static\cdecl\zlib.lib
 LIBS=$(OPENSSL_LIBS) $(ZLIB_LIBS) $(GENERAL_LIBS) $(WINSOCK_LIBS)
 
+#shlwapi.lib provides PathMatchSpec() for gflags in windows
+GFLAGS_LIBS=.\..\third_party\gflags\lib\Debug\gflags.lib shlwapi.lib
+GTEST_LIBS=.\..\third_party\gtest\msvc\gtest\Debug\gtestd.lib
+PROTOBUF_LIBS=.\..\third_party\protobuf\vsprojects\Debug\libprotobuf.lib
+CXX_LIBS=$(GFLAGS_LIBS) $(GTEST_LIBS) $(PROTOBUF_LIBS)
+
 all: buildtests
 
 tools:
@@ -99,16 +118,33 @@ buildtests_c: \
 ${target.name}.exe \
 % endfor
 
-	echo All tests built.
+	echo All C tests built.
 
 buildtests_cxx: \
 % for target in cxx_test_targets:
 ${target.name}.exe \
 % endfor
 
-	echo All tests built.
+	echo All C++ tests built.
 
 % for target in buildable_targets:
+
+## replace all .proto includes with .pb.cc / .grpc.pb.cc
+%if target.src:
+%for source in target.src:
+%if source.endswith(".proto"):
+<%
+      src_name_parts = source.split(".")
+      target.src.append(src_name_parts[0] + ".pb.cc")
+      target.src.append(src_name_parts[0] + ".grpc.pb.cc")
+%>\
+%endif
+%endfor
+%endif
+## remove all .proto includes
+<%
+  target.src = [item for item in target.src if not re.search('([^/]+)\.proto$', item)]
+%>\
 %if target.name in build_from_project_file:
 build_${target.name}:
 	msbuild grpc.sln /t:${target.name} /p:Configuration=Debug /p:Linkage-grpc_dependencies_zlib=static
@@ -116,11 +152,22 @@ build_${target.name}:
 %if target.build == 'private':
 Debug\${target.name}.lib: \
 %else:
-${target.name}.exe: build_libs \
+${target.name}.exe: \
+%for dep in target.get('deps', []):
+%if dep in build_from_project_file:
+build_${dep} \
+%else:
+Debug\${dep}.lib \
+%endif
+%endfor
 %endif
 $(OUT_DIR)
 	echo Building ${target.name}
+%if target.language == 'c++':
+    $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ \
+%else:
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ \
+%endif
 %for source in target.src:
 $(REPO_ROOT)\${to_windows_path(source)} \
 %endfor
@@ -135,13 +182,19 @@ $(REPO_ROOT)\${to_windows_path('vsprojects/dummy.c')} \
 %for dep in target.get('deps', []):
 Debug\${dep}.lib \
 %endfor
+%if target.language == 'c++':
+$(CXX_LIBS) \
+%endif
 $(LIBS) \
 %endif
-%for source in target.src:
-$(OUT_DIR)\${re.search('([^/]+)\.c$', source).group(1)}.obj \
-%endfor
 %if not target.src:
 $(OUT_DIR)\dummy.obj \
+%else:
+%for source in target.src:
+%if re.search('([^/]+)\.c{1,2}$', source):
+$(OUT_DIR)\${re.search('([^/]+)\.c{1,2}$', source).group(1)}.obj \
+%endif
+%endfor
 %endif
 
 %if target.build != 'private':
diff --git a/templates/vsprojects/build_test_protos.sh b/templates/vsprojects/build_test_protos.sh
new file mode 100644
index 0000000000000000000000000000000000000000..54edd3699afe23923ff03f922c2cabb6c5f79cad
--- /dev/null
+++ b/templates/vsprojects/build_test_protos.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+GRPC_CPP_PLUGIN_PATH=`which grpc_cpp_plugin`
+
+cd `dirname $0`/../..
+
+find ./test -type f -name "*.proto" |
+while read p ; do
+  echo "processing $p"
+  DIR=$(dirname "$p")
+  protoc $p --grpc_out=./ --plugin=protoc-gen-grpc=$GRPC_CPP_PLUGIN_PATH
+  protoc $p --cpp_out=./
+done
diff --git a/templates/vsprojects/generate_debug_projects.sh b/templates/vsprojects/generate_debug_projects.sh
index 1bbe40b6c8b96b9da41426aeb49efdb81dd7cda1..f103ebe01a926af84bf8cfa61bff257b39d936eb 100755
--- a/templates/vsprojects/generate_debug_projects.sh
+++ b/templates/vsprojects/generate_debug_projects.sh
@@ -37,26 +37,40 @@
 
 cd `dirname $0`/../..
 
-./tools/buildgen/generate_projects.sh
+git add .               #because we're using "git diff" to find changes to grpc.sln and then make files based on those changes, this prevents this file or other files from possibly being found in the diff
 
-git diff |
-grep \\+Project |
-cut -d\" -f 4 |
-sort -u |
-grep _test$ |
-while read p ; do
-  mkdir -p templates/vsprojects/$p
-  echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$p'", targets)}' > templates/vsprojects/$p/$p.vcxproj.template
-done
+./tools/buildgen/generate_projects-old.sh
+
+line_number=0
 
 git diff |
-grep \\+Project |
-cut -d\" -f 4 |
-sort -u |
-grep -v _test$ |
+grep -A2 \\+Project |       #find "Project" immediately after a backslash (escaped), plus 2 additional lines to capture the "libs = ", plus 1 line of "--".  matches will come from the generated grpc.sln
 while read p ; do
-  mkdir -p templates/vsprojects/$p
-  echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$p'", libs)}' > templates/vsprojects/$p/$p.vcxproj.template
+  line_number=$((line_number + 1))
+  if [ "$line_number" -gt "4" ]; then
+    line_number=1;
+  fi
+  echo $line_number
+  echo $p
+  if [ "$line_number" -eq "1" ]; then
+    project_name=$(echo "$p" | cut -d\" -f 4)          #sed: extract line N only; cut with delimiter: ".  select only field 4
+  fi
+  if [ "$line_number" -eq "3" ]; then
+    lib_setting=$(echo "$p" | cut -d\" -f 2)          #
+    echo "project_name"
+    echo $project_name
+    echo "lib_setting"
+    echo $lib_setting
+    mkdir -p templates/vsprojects/$project_name
+    if [ "$lib_setting" = "True" ]; then
+      echo "lib: true"
+      echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$project_name'", libs)}' > templates/vsprojects/$project_name/$project_name.vcxproj.template
+    else
+      echo "lib: not true"
+      echo '<%namespace file="../vcxproj_defs.include" import="gen_project"/>${gen_project("'$project_name'", targets)}' > templates/vsprojects/$project_name/$project_name.vcxproj.template
+    fi
+  fi
+ # sleep .5     #for testing
 done
 
-./tools/buildgen/generate_projects.sh
+./tools/buildgen/generate_projects-old.sh
diff --git a/templates/vsprojects/sln_defs.include b/templates/vsprojects/sln_defs.include
index ee05d0fbde2b3504743996208a8f2e9a20fe96b8..4ba0fbff0755ad4f3641aad0230d841a7c1e8e82 100644
--- a/templates/vsprojects/sln_defs.include
+++ b/templates/vsprojects/sln_defs.include
@@ -15,6 +15,13 @@ cpp_proj_type = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
 %>\
 % for project in solution_projects:
 Project("${cpp_proj_type}") = "${project.name}", "${project.name}\${project.name}.vcxproj", "${project.vs_project_guid}"
+	ProjectSection(myProperties) = preProject
+  % if project.is_library:
+        	lib = "True"
+  % else:
+        	lib = "False"
+  % endif
+	EndProjectSection
   % if project.get('deps', None):
 	ProjectSection(ProjectDependencies) = postProject
     % for dep in project.get('deps', []):
@@ -47,4 +54,4 @@ Global
 		HideSolutionNode = FALSE
 	EndGlobalSection
 EndGlobal
-</%def>\
\ No newline at end of file
+</%def>\
diff --git a/templates/vsprojects/vcxproj_defs.include b/templates/vsprojects/vcxproj_defs.include
index 55ec37393fa0ab0a825feaeabd04c75c2fe582df..39c73860629f5df712d64e2306b00c1669003f2a 100644
--- a/templates/vsprojects/vcxproj_defs.include
+++ b/templates/vsprojects/vcxproj_defs.include
@@ -12,19 +12,21 @@
     if t.name == name:
       target = t
   if not configuration_type and target:
+    print target.name
     if target.build == 'test' or target.build == 'tool':
       configuration_type = 'Application'
   if not configuration_type:
     configuration_type = 'StaticLibrary'
   if not project_guid:
     project_guid = project.vs_project_guid
+  if target.build == 'test' and target.language == 'c++':
+    props.extend(['cpptest'])
   if configuration_type == 'Application':
+    print target.build
     if target.build == 'protoc':
       props.extend(['protoc'])
     else:
       props.extend(['winsock', 'protobuf', 'zlib', 'openssl'])
-    if target.language == 'c++':
-      props.extend(['protobuf'])
   props.extend(['global'])
 %>\
 <?xml version="1.0" encoding="utf-8"?>
@@ -113,6 +115,13 @@ ${gen_package_props(packages)}\
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <TargetName>${name}</TargetName>
+    % if "zlib" in packages:
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    % endif
+    % if "openssl" in packages:
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+    % endif
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <TargetName>${name}</TargetName>
@@ -200,8 +209,20 @@ ${gen_package_props(packages)}\
   % if project.get('src',[]):
   <ItemGroup>
     % for src_name in project.src:
+      % if src_name.endswith(".proto"):
+<% src_name_parts = src_name.split(".") %>\
+    <ClCompile Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".pb.cc")}">
+    </ClCompile>
+    <ClInclude Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".pb.h")}">
+    </ClInclude>
+    <ClCompile Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".grpc.pb.cc")}">
+    </ClCompile>
+    <ClInclude Include="${get_repo_root()}\${to_windows_path(src_name_parts[0] + ".grpc.pb.h")}">
+    </ClInclude>
+      % else:
     <ClCompile Include="${get_repo_root()}\${to_windows_path(src_name)}">
     </ClCompile>
+      % endif
     % endfor
   </ItemGroup>
   % elif configuration_type != 'StaticLibrary':
@@ -230,4 +251,4 @@ ${gen_package_targets(packages)}\
   </ImportGroup>
 ${gen_package_ensure(packages)}\
 </Project>
-</%def>\
\ No newline at end of file
+</%def>\
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 453376caec4d51f559842febd1a39e873d2990f6..77bea2ababda174651b37a3e1282b1e3f2f0c88b 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -113,7 +113,7 @@ void test_connect(const char *server_host, const char *client_host, int port,
   } else {
     gpr_join_host_port(&client_hostport, client_host, port);
   }
-  client = grpc_channel_create(client_hostport, NULL);
+  client = grpc_insecure_channel_create(client_hostport, NULL);
 
   gpr_log(GPR_INFO, "Testing with server=%s client=%s (expecting %s)",
           server_hostport, client_hostport, expect_ok ? "success" : "failure");
diff --git a/test/core/end2end/fixtures/chttp2_fullstack.c b/test/core/end2end/fixtures/chttp2_fullstack.c
index 8a1530e63b05cf3949d161e6c71bfa83655c630e..6647b949ba2bbb30a547280ac720b093297a01ab 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack.c
@@ -72,7 +72,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
   GPR_ASSERT(f->client);
 }
 
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_compression.c b/test/core/end2end/fixtures/chttp2_fullstack_compression.c
index 0a9a31229680a5e9ed0b893d64ce80e1825c8c96..f3d1fa22dcea385423a40ecd096028874f35baac 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_compression.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_compression.c
@@ -82,7 +82,8 @@ void chttp2_init_client_fullstack_compression(grpc_end2end_test_fixture *f,
   }
   ffd->client_args_compression = grpc_channel_args_set_compression_algorithm(
       client_args, GRPC_COMPRESS_GZIP);
-  f->client = grpc_channel_create(ffd->localaddr, ffd->client_args_compression);
+  f->client = grpc_insecure_channel_create(ffd->localaddr,
+                                           ffd->client_args_compression);
 }
 
 void chttp2_init_server_fullstack_compression(grpc_end2end_test_fixture *f,
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
index 351e1c5459b5f2335e977ed5d56fb3f5736fcfaf..89ad7b8c2d83770d1e2dcd519af345252b9c9d16 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix.c
@@ -78,7 +78,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c
index 03d3be5a7c336678b01c637595fd9459c1a61597..a2ab25d886f4380ba7cbd1bde4aa0f1d95ade369 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_uds_posix_with_poll.c
@@ -78,7 +78,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
diff --git a/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c b/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
index 69860d04d5e8e25ade4f852e33ce4659a18df171..93786d0943a3ad17d2296694cd7c83795d00d494 100644
--- a/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_fullstack_with_poll.c
@@ -72,7 +72,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
 void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
                                   grpc_channel_args *client_args) {
   fullstack_fixture_data *ffd = f->fixture_data;
-  f->client = grpc_channel_create(ffd->localaddr, client_args);
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args);
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
index 73a36116fb17b4c1291734c1b47fd975f31d8238..6d5669d05a8a3f6131147c84c0586257150e62c0 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
@@ -115,7 +115,7 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
   grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
                                                   test_server1_cert};
   grpc_server_credentials *ssl_creds =
-      grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1);
+      grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0);
   chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
 }
 
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c
index b1ac3e535f1bea8eb8c6c83a38ff8fb4280a47aa..d0cc3dd74a2ff3cef666c5baa7e118c61f6f3420 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c
@@ -115,7 +115,7 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
   grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
                                                   test_server1_cert};
   grpc_server_credentials *ssl_creds =
-      grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1);
+      grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0);
   chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
 }
 
diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
index de418bf7ee0122e43adb11a20d27c519a0cf5bd2..f74ed9365f7742f1b1fa3a8d6b4ea8f94fcdd964 100644
--- a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
+++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
@@ -120,7 +120,7 @@ static void chttp2_init_server_simple_ssl_secure_fullstack(
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key,
                                                   test_server1_cert};
   grpc_server_credentials *ssl_creds =
-      grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1);
+      grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1, 0);
   chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
 }
 
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
index 79797f93751e3be0cf5b7dccd9998dc432d21cb0..6f1133c009a0aae2e986c07d16de6e552367f56c 100644
--- a/test/core/end2end/no_server_test.c
+++ b/test/core/end2end/no_server_test.c
@@ -61,7 +61,7 @@ int main(int argc, char **argv) {
   cqv = cq_verifier_create(cq);
 
   /* create a call, channel to a non existant server */
-  chan = grpc_channel_create("nonexistant:54321", NULL);
+  chan = grpc_insecure_channel_create("nonexistant:54321", NULL);
   call = grpc_channel_create_call(chan, cq, "/Foo", "nonexistant", deadline);
 
   op = ops;
diff --git a/test/core/end2end/tests/request_response_with_metadata_and_payload.c b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
index ef6dfe9561f766a4e4da701ff067a9b076b9fa8d..9821d7852f3834c987d80a077c237e02b90dae28 100644
--- a/test/core/end2end/tests/request_response_with_metadata_and_payload.c
+++ b/test/core/end2end/tests/request_response_with_metadata_and_payload.c
@@ -111,8 +111,8 @@ static void test_request_response_with_metadata_and_payload(
   gpr_timespec deadline = five_seconds_time();
   grpc_metadata meta_c[2] = {{"key1", "val1", 4, {{NULL, NULL, NULL}}},
                              {"key2", "val2", 4, {{NULL, NULL, NULL}}}};
-  grpc_metadata meta_s[2] = {{"key3", "val3", 4, {{NULL, NULL, NULL}}},
-                             {"key4", "val4", 4, {{NULL, NULL, NULL}}}};
+  grpc_metadata meta_s[2] = {{"KeY3", "val3", 4, {{NULL, NULL, NULL}}},
+                             {"KeY4", "val4", 4, {{NULL, NULL, NULL}}}};
   grpc_end2end_test_fixture f = begin_test(
       config, "test_request_response_with_metadata_and_payload", NULL, NULL);
   cq_verifier *cqv = cq_verifier_create(f.cq);
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index 2b196543792b232c0c828e80ab4efc48d91f2a4a..5647a16101e3f3725d9ac4d7603eaac8ac1f4990 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -183,7 +183,7 @@ int main(int argc, char **argv) {
     return 1;
   }
 
-  channel = grpc_channel_create(target, NULL);
+  channel = grpc_insecure_channel_create(target, NULL);
   cq = grpc_completion_queue_create();
   the_buffer = grpc_raw_byte_buffer_create(&slice, payload_size);
   histogram = gpr_histogram_create(0.01, 60e9);
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
index 082bbd368a7b63d9869101e6fd4d3b6a4403a549..8f349044d97b90363422fe2e59b20f37c7e5d043 100644
--- a/test/core/fling/server.c
+++ b/test/core/fling/server.c
@@ -210,7 +210,7 @@ int main(int argc, char **argv) {
     grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key,
                                                     test_server1_cert};
     grpc_server_credentials *ssl_creds =
-        grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1);
+        grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1, 0);
     server = grpc_server_create(NULL);
     GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, ssl_creds));
     grpc_server_credentials_release(ssl_creds);
diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c
index a932e04f330da4cbe7246cace7568a927a842a75..4a4d4bcb8a1d2c9f63a4f4301acd4c61be2a9f96 100644
--- a/test/core/transport/metadata_test.c
+++ b/test/core/transport/metadata_test.c
@@ -63,9 +63,9 @@ static void test_create_string(void) {
   LOG_TEST("test_create_string");
 
   ctx = grpc_mdctx_create();
-  s1 = grpc_mdstr_from_string(ctx, "hello");
-  s2 = grpc_mdstr_from_string(ctx, "hello");
-  s3 = grpc_mdstr_from_string(ctx, "very much not hello");
+  s1 = grpc_mdstr_from_string(ctx, "hello", 0);
+  s2 = grpc_mdstr_from_string(ctx, "hello", 0);
+  s3 = grpc_mdstr_from_string(ctx, "very much not hello", 0);
   GPR_ASSERT(s1 == s2);
   GPR_ASSERT(s3 != s1);
   GPR_ASSERT(gpr_slice_str_cmp(s1->slice, "hello") == 0);
@@ -190,7 +190,7 @@ static void test_things_stick_around(void) {
 
   for (i = 0; i < nstrs; i++) {
     gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", i);
-    strs[i] = grpc_mdstr_from_string(ctx, buffer);
+    strs[i] = grpc_mdstr_from_string(ctx, buffer, 0);
     shuf[i] = i;
     gpr_free(buffer);
   }
@@ -212,7 +212,7 @@ static void test_things_stick_around(void) {
     GRPC_MDSTR_UNREF(strs[shuf[i]]);
     for (j = i + 1; j < nstrs; j++) {
       gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%dx", shuf[j]);
-      test = grpc_mdstr_from_string(ctx, buffer);
+      test = grpc_mdstr_from_string(ctx, buffer, 0);
       GPR_ASSERT(test == strs[shuf[j]]);
       GRPC_MDSTR_UNREF(test);
       gpr_free(buffer);
@@ -235,13 +235,13 @@ static void test_slices_work(void) {
   ctx = grpc_mdctx_create();
 
   str = grpc_mdstr_from_string(
-      ctx, "123456789012345678901234567890123456789012345678901234567890");
+      ctx, "123456789012345678901234567890123456789012345678901234567890", 0);
   slice = gpr_slice_ref(str->slice);
   GRPC_MDSTR_UNREF(str);
   gpr_slice_unref(slice);
 
   str = grpc_mdstr_from_string(
-      ctx, "123456789012345678901234567890123456789012345678901234567890");
+      ctx, "123456789012345678901234567890123456789012345678901234567890", 0);
   slice = gpr_slice_ref(str->slice);
   gpr_slice_unref(slice);
   GRPC_MDSTR_UNREF(str);
@@ -258,7 +258,7 @@ static void test_base64_and_huffman_works(void) {
   LOG_TEST("test_base64_and_huffman_works");
 
   ctx = grpc_mdctx_create();
-  str = grpc_mdstr_from_string(ctx, "abcdefg");
+  str = grpc_mdstr_from_string(ctx, "abcdefg", 0);
   slice1 = grpc_mdstr_as_base64_encoded_and_huffman_compressed(str);
   slice2 = grpc_chttp2_base64_encode_and_huffman_compress(str->slice);
   GPR_ASSERT(0 == gpr_slice_cmp(slice1, slice2));
diff --git a/tools/buildgen/generate_projects-old.sh b/tools/buildgen/generate_projects-old.sh
new file mode 100644
index 0000000000000000000000000000000000000000..539986774656b26e30c5e9389454cbaef6959c56
--- /dev/null
+++ b/tools/buildgen/generate_projects-old.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+set -e
+
+if [ "x$TEST" = "x" ] ; then
+  TEST=false
+fi
+
+
+cd `dirname $0`/../..
+mako_renderer=tools/buildgen/mako_renderer.py
+
+if [ "x$TEST" != "x" ] ; then
+  tools/buildgen/build-cleaner.py build.json
+fi
+
+. tools/buildgen/generate_build_additions.sh
+
+global_plugins=`find ./tools/buildgen/plugins -name '*.py' |
+  sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
+
+for dir in . ; do
+  local_plugins=`find $dir/templates -name '*.py' |
+    sort | grep -v __init__ | awk ' { printf "-p %s ", $0 } '`
+
+  plugins="$global_plugins $local_plugins"
+
+  find -L $dir/templates -type f -and -name *.template | while read file ; do
+    out=${dir}/${file#$dir/templates/}  # strip templates dir prefix
+    out=${out%.*}  # strip template extension
+    echo "generating file: $out"
+    json_files="build.json $gen_build_files"
+    data=`for i in $json_files ; do echo $i ; done | awk ' { printf "-d %s ", $0 } '`
+    if [ "x$TEST" = "xtrue" ] ; then
+      actual_out=$out
+      out=`mktemp /tmp/gentXXXXXX`
+    fi
+    mkdir -p `dirname $out`  # make sure dest directory exist
+    $mako_renderer $plugins $data -o $out $file
+    if [ "x$TEST" = "xtrue" ] ; then
+      diff -q $out $actual_out
+      rm $out
+    fi
+  done
+done
+
+rm $gen_build_files
diff --git a/tools/buildgen/plugins/generate_vsprojects.py b/tools/buildgen/plugins/generate_vsprojects.py
index 150e72e0b269524ca32a79bc4431aeafc5a685a2..413056fe89fce7881686486e73f694bc2ddcd0cc 100755
--- a/tools/buildgen/plugins/generate_vsprojects.py
+++ b/tools/buildgen/plugins/generate_vsprojects.py
@@ -70,7 +70,7 @@ def mako_plugin(dictionary):
                 if project.get('vs_project_guid', None)]
 
   projects = [project for project in projects
-                if project['language'] != 'c++' or project['build'] == 'all' or project['build'] == 'protoc']
+                if project['language'] != 'c++' or project['build'] == 'all' or project['build'] == 'protoc' or (project['language'] == 'c++' and  (project['build'] == 'test' or project['build'] == 'private'))]
 
   project_dict = dict([(p['name'], p) for p in projects])
 
diff --git a/tools/gce_setup/cloud_prod_runner.sh b/tools/gce_setup/cloud_prod_runner.sh
index 4206a66db78a5123eb3a66d15a7fd1489fce94ec..734370288373d8f8b170f8afadf565f76ea8cba3 100755
--- a/tools/gce_setup/cloud_prod_runner.sh
+++ b/tools/gce_setup/cloud_prod_runner.sh
@@ -34,8 +34,8 @@ log_link=https://pantheon.corp.google.com/m/cloudstorage/b/stoked-keyword-656-ou
 
 main() {
   source grpc_docker.sh
-  test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
-  auth_test_cases=(service_account_creds compute_engine_creds jwt_token_creds)
+  test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response empty_stream timeout_on_sleeping_server)
+  auth_test_cases=(service_account_creds compute_engine_creds jwt_token_creds oauth2_auth_token per_rpc_creds)
   clients=(cxx java go ruby node csharp_mono csharp_dotnet python php)
   for test_case in "${test_cases[@]}"
   do
diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh
index b53aa98aab9e6135479be9069e04be9341c6b22f..c06780a699391a8c349c9c3eb1f5a8afefeda207 100755
--- a/tools/gce_setup/grpc_docker.sh
+++ b/tools/gce_setup/grpc_docker.sh
@@ -508,7 +508,12 @@ grpc_cloud_prod_auth_test_args() {
   grpc_gen_test_cmd="grpc_cloud_prod_auth_"
   [[ -n $1 ]] && {  # test_case
     test_case=$1
-    grpc_gen_test_cmd+="$1"
+    test_command="service_account_creds"
+    if [ "$test_case" == "compute_engine_creds" ]
+    then
+      test_command="compute_engine_creds"
+    fi
+    grpc_gen_test_cmd+=$test_command
     shift
   } || {
     echo "$FUNCNAME: missing arg: test_case" 1>&2
diff --git a/tools/gce_setup/interop_test_runner.sh b/tools/gce_setup/interop_test_runner.sh
index 6ff3731985d4710dd1647d3e4beef591087baa87..506471411be60cad108d5e8debb960d99770f419 100755
--- a/tools/gce_setup/interop_test_runner.sh
+++ b/tools/gce_setup/interop_test_runner.sh
@@ -37,7 +37,7 @@ fail_log_link=https://pantheon.corp.google.com/m/cloudstorage/b/stoked-keyword-6
 
 main() {
   source grpc_docker.sh
-  test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
+  test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response empty_stream timeout_on_sleeping_server)
   clients=(cxx java go ruby node python csharp_mono php)
   servers=(cxx java go ruby node python csharp_mono)
   for test_case in "${test_cases[@]}"
diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh
index 56f9e82ca580436042693dbba7cc7b1ce2a05f07..93cf82d260745c18868a19d707818c604aaf0497 100755
--- a/tools/jenkins/run_jenkins.sh
+++ b/tools/jenkins/run_jenkins.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -31,6 +31,8 @@
 # This script is invoked by Jenkins and triggers a test run based on
 # env variable settings.
 #
+# Bootstrap into bash
+[ -z $1 ] && exec bash $0 bootstrapped
 # Setting up rvm environment BEFORE we set -ex.
 [[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
 # To prevent cygwin bash complaining about empty lines ending with \r
@@ -90,7 +92,9 @@ then
   docker cp $DOCKER_CID:/var/local/git/grpc/report.xml $git_root
   sleep 4
   docker rm $DOCKER_CID || true
-
+elif [ "$platform" == "interop" ]
+then
+  python tools/run_tests/run_interops.py --language=$language
 elif [ "$platform" == "windows" ]
 then
   echo "building $language on Windows"
@@ -103,11 +107,18 @@ then
   /cygdrive/c/nuget/nuget.exe restore src/csharp/Grpc.sln
 
   python tools/run_tests/run_tests.py -t -l $language -x report.xml || true
+
 elif [ "$platform" == "macos" ]
 then
   echo "building $language on MacOS"
 
   ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
+
+elif [ "$platform" == "freebsd" ]
+then
+  echo "building $language on FreeBSD"
+
+  MAKE=gmake ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
 else
   echo "Unknown platform $platform"
   exit 1
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index 46137f01f40a0f722ba4542d5f9bedc34ead8396..ec25b4761024143fc1c9ce4f58278d2d003dde1a 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -206,7 +206,7 @@ class Job(object):
                 do_newline=self._newline_on_success or self._travis)
         if self._bin_hash:
           update_cache.finished(self._spec.identity(), self._bin_hash)
-    elif self._state == _RUNNING and time.time() - self._start > 600:
+    elif self._state == _RUNNING and time.time() - self._start > 900:
       self._tempfile.seek(0)
       stdout = self._tempfile.read()
       filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore'))
diff --git a/tools/run_tests/run_interops.py b/tools/run_tests/run_interops.py
new file mode 100755
index 0000000000000000000000000000000000000000..1cf268526dcc8553a43ce2785ee647b7b024e54d
--- /dev/null
+++ b/tools/run_tests/run_interops.py
@@ -0,0 +1,36 @@
+import argparse
+import xml.etree.cElementTree as ET
+import jobset
+
+argp = argparse.ArgumentParser(description='Run interop tests.')
+argp.add_argument('-l', '--language',
+                  choices=['build_only', 'c++'],
+                  nargs='+',
+                  default=['build_only'])
+args = argp.parse_args()
+
+# build job
+build_steps = 'tools/run_tests/run_interops_build.sh'
+build_job = jobset.JobSpec(cmdline=build_steps, shortname='build')
+
+# test jobs
+_TESTS = ['large_unary', 'empty_unary', 'ping_pong', 'client_streaming', 'server_streaming']
+jobs = []
+jobNumber = 0
+for lang in args.language:
+  for test in _TESTS:
+    test_job = jobset.JobSpec(cmdline=['tools/run_tests/run_interops_test.sh', '%s' % lang, '%s' % test], shortname=test)
+    jobs.append(test_job)
+    jobNumber+=1
+
+root = ET.Element('testsuites')
+testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', name='tests')
+
+# always do the build of docker first, and then all the tests can run in parallel
+jobset.run([build_job], maxjobs=1, xml_report=testsuite)
+jobset.run(jobs, maxjobs=jobNumber, xml_report=testsuite)
+
+tree = ET.ElementTree(root)
+tree.write('report.xml', encoding='UTF-8')
+
+
diff --git a/tools/run_tests/run_interops_build.sh b/tools/run_tests/run_interops_build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..23441a5300de0fb395e17672f49467af7755bfbb
--- /dev/null
+++ b/tools/run_tests/run_interops_build.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -e
+
+#clean up any old docker files and start mirroring repository if not started already
+sudo docker rmi -f grpc/cxx || true
+sudo docker rmi -f grpc/base || true
+sudo docker rmi -f 0.0.0.0:5000/grpc/base || true
+sudo docker run -d -e GCS_BUCKET=docker-interop-images  -e STORAGE_PATH=/admin/docker_images -p 5000:5000 google/docker-registry || true
+
+#prepare building by pulling down base images and necessary files
+sudo docker pull 0.0.0.0:5000/grpc/base
+sudo docker tag -f 0.0.0.0:5000/grpc/base grpc/base
+gsutil cp -R gs://docker-interop-images/admin/service_account tools/dockerfile/grpc_cxx
+gsutil cp -R gs://docker-interop-images/admin/cacerts tools/dockerfile/grpc_cxx
+
+#build docker file, add more languages later
+sudo docker build --no-cache -t grpc/cxx tools/dockerfile/grpc_cxx
diff --git a/tools/run_tests/run_interops_test.sh b/tools/run_tests/run_interops_test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..1d0eedad85ad2782bcfb63a4aa79a1e2680c5a75
--- /dev/null
+++ b/tools/run_tests/run_interops_test.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+language=$1
+test_case=$2
+
+set -e
+if [ "$language" = "c++" ]
+then
+  sudo docker run grpc/cxx /var/local/git/grpc/bins/opt/interop_client --enable_ssl --use_prod_roots --server_host_override=grpc-test.sandbox.google.com --server_host=grpc-test.sandbox.google.com --server_port=443 --test_case=$test_case
+else
+  echo "interop testss not added for $language"
+  exit 1
+fi
+
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 77cc02a087a394c849c1d5e3930b6756d5d9f968..28980c14a82e75d75507bb0e09705eedc54b0776 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -458,7 +458,7 @@ if platform.system() == 'Windows':
                           cwd='vsprojects', shell=True)
 else:
   def make_jobspec(cfg, targets):
-    return jobset.JobSpec(['make',
+    return jobset.JobSpec([os.getenv('MAKE', 'make'),
                            '-j', '%d' % (multiprocessing.cpu_count() + 1),
                            'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' %
                                args.slowdown,
diff --git a/vsprojects/README.md b/vsprojects/README.md
index dade9e500e24d11f6bac469a330faad7210c1c07..e6cbf8335903e871ce9604bd68f4c3fda156b487 100644
--- a/vsprojects/README.md
+++ b/vsprojects/README.md
@@ -19,19 +19,62 @@ After that, you can build the solution using one of these options:
 1. open `grpc.sln` with Visual Studio and hit "Build".
 2. build from commandline using `msbuild grpc.sln /p:Configuration=Debug`
 
-#Testing
+#C/C++ Test Dependencies
+   * gtest isn't available as a git repo like the other dependencies.  download it and add it to `/third_party/gtest/` (the folder will end up with `/build-aux/`, `/cmake/`, `/codegear/`, etc. folders in it).  
+    * if using vs2013: open/import the gtest solution in `/msvc/`, and save over the first solution (you will have to change it from read-only).  change all projects to use `/MDd` (Property Pages - C/C++ - Code Generation - Runtime Library) and build. This is a "multithreaded debug" setting and it needs to match grpc.
+    * build all
+   * open protobuf solution in `/third_party/protobuf/vsprojects`
+    * if using vs2013: on import the gtest stuff will probably fail, I think the paths are interpreted wrong.  it's ok.
+    * tests and test_plugin will fail when built.  also ok
+    * build all
+   *  gflags is automatically imported as a git submodule but it needs to have CMake run on it to be ready for a specific platform
+    * download [CMake](http://www.cmake.org/) windows installer; install
+    * open visual studio developer command prompt (not sure if dev command prompt is necessary)
+    * run `cmake <path to gtest directory>`
+    * this will build a `.sln` and fill up the `/third_party/gflags/include/gflags/` directory with headers
+    * build all
+   * install [NuGet](http://www.nuget.org)
+    * nuget should automatically bring in built versions of zlib and openssl when building grpc.sln (the versions in `/third_party/` are not used).  If it doesn't work use `tools->nuget...->manage...`.  The packages are put in `/vsprojects/packages/`
 
-Use `run_tests.py`, that also supports Windows (with a bit limited experience).
-```
-> REM Run from repository root.
-> python tools\run_tests\run_tests.py -l c
-```
+#C/C++ Test Solution/Project Build Steps
+   * A basic git version of grpc only has templates for non-test items.  This checklist adds test items to grpc.sln and makes individual vs projects for them
+   * set up dependencies (above)
+   * add `"debug": true,` to the top of build.json.  This is the base file for all build tracking, see [templates](https://github.com/grpc/grpc/tree/master/templates) for more information
+    * `"debug": true,` gets picked up by `/tools/buildgen/plugins/generate_vsprojects.py`.  It tells the script to add visual studio GUIDs to all projects.  Otherwise only the projects that already have GUIDs in build.json will be built
+   * run `/templates/vsprojects/generate_debug_projects.sh` to make debug templates/projects.  This runs a regular visual studio buildgen process, which creates the `.sln` file with all of the new debug projects, then uses git diff to find the new project names from the `.sln` that need templates added.  It builds the new templates based on the diff, then re-runs the visual studio buildgen, which builds the vs projects for each of the new debug targets
+    * copy over the `/vsprojects/` folder to your windows build setup (assuming this was built on linux in order to have easy access to python/mako and shell scripts)
+   * run `/templates/vsprojects/build_test_protos.sh`
+    * this builds all `.proto` files in `/test/` in-place.  there might be a better place to put them that mirrors what happens in the linux build process (todo)
+    * each `.proto` file gets built into a `.grpc.pb.cc`, .`grpc.pb.h`, `.pb.cc`, and `.pb.h`.  These are included in each test project in lieu of the `.proto` includes specified in `build.json`.  This substitution is done by `/templates/vsprojects/vcxproj_defs.include`
+    * copy over the `/test/` folder in order to get the new files (assuming this was built on linux in order to have an easy protobuf+grpc plugin installation)
 
-Also, you can `make.bat` directly to build and run gRPC tests.
-```
-> REM Run from this directory.
-> make.bat alarm_test
-```
+#Making and running tests with `/tools/run_tests/run_tests.py` or `/vsprojects/make.bat`
+`run_tests.py` and `make.bat` both rely on `/vsprojects/grpc.mak`, an NMAKE script that includes C/C++ tests in addition to the base grpc projects.  It builds the base projects by calling grpc.sln, but most things are built with a command line similar to a makefile workflow.
+
+ arguments for `/vsprojects/make.bat`:
+
+ * no options or `all` or `buildtests`: builds all tests
+ * `buildtests_c`: just c tests
+ * `buildtests_cxx`: just c++ tests
+ * names of individual tests: just those tests (example: `make.bat gpr_string_test`)
+
+using `run_tests.py` on windows:
+
+ * when `run_tests.py` detects that it's running on windows it calls `make.bat` to build the tests and expects to find tests in `/vsprojects/test_bins/`
+
+`run_tests.py` options:
+
+ * `run_tests.py --help`
+ * `run_tests.py -l c`: run c language tests
+ * `run_tests.py -l c++`: run c++ language tests
+ * note: `run_tests.py` doesn't normally show build steps, so if a build fails it is best to fall back to `make.bat`
+ * if `make.bat` fails, it might be easier to open up the `.sln` file in the visual studio gui (see above for how to build the test projects) and build the offending test from its project file.  The `.mak` and project file templates are slightly different, so it's possible that a project will build one way and not another.  Please report this if it happens.
+
+It can be helpful to disable the firewall when running tests so that 400 connection warnings don't pop up.
+
+Individual tests can be run by directly running the executable in `/vsprojects/run_tests/` (this is `/bins/opt/` on linux).  Many C tests have no output; they either pass or fail internally and communicate this with their exit code (`0=pass`, `nonzero=fail`)
+
+`run_tests.py` will fail if it can't build something, so not-building tests are disabled with a "platforms = posix" note in build.json.  The buildgen tools will not add a test to a windows build unless it is marked "windows" or has no platforms identified.  As tests are ported they will get this mark removed.
 
 # Building protoc plugins
 For generating service stub code, gRPC relies on plugins for `protoc` (the protocol buffer compiler). The solution `grpc_protoc_plugins.sln` allows you to build
diff --git a/vsprojects/cpptest.props b/vsprojects/cpptest.props
new file mode 100644
index 0000000000000000000000000000000000000000..c5ffd54f9902f4af59fad346d8f0ee80ce78ad9d
--- /dev/null
+++ b/vsprojects/cpptest.props
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ImportGroup Label="PropertySheets" />
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup />
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(ProjectDir)\..\..;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\third_party\protobuf\src;$(ProjectDir)\..\..\third_party\gtest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <WarningLevel>EnableAllWarnings</WarningLevel>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>grpc++_test_util.lib;grpc_test_util.lib;gpr_test_util.lib;gtestd.lib;gflags.lib;shlwapi.lib;gpr.lib;grpc.lib;grpc++.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(ProjectDir)\..\..\third_party\gtest\msvc\gtest\Debug;$(ProjectDir)\..\..\third_party\gflags\lib\Debug;$(ProjectDir)\..\Debug;$(ProjectDir)\..\packages\grpc.dependencies.openssl.1.0.2.2\build\native\lib\$(PlatformToolset)\$(Platform)\$(Configuration)\static;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup />
+</Project>
diff --git a/vsprojects/global.props b/vsprojects/global.props
index 14acf4668b31837e252ab3956ad4363736e3cba8..6858bd7b9d45677abe42080f42208dbab77db98f 100644
--- a/vsprojects/global.props
+++ b/vsprojects/global.props
@@ -5,10 +5,10 @@
   <PropertyGroup />
   <ItemDefinitionGroup>
     <ClCompile>
-      <AdditionalIncludeDirectories>$(ProjectDir)\..\..;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\third_party\protobuf\src;$(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>$(ProjectDir)\..\..;$(ProjectDir)\..\..\include;$(ProjectDir)\..\..\third_party\protobuf\src;$(ProjectDir)\..\packages\grpc.dependencies.openssl.1.0.2.2\build\native\include;$(ProjectDir)\..\..\third_party\gflags\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <WarningLevel>EnableAllWarnings</WarningLevel>
     </ClCompile>
   </ItemDefinitionGroup>
   <ItemGroup />
-</Project>
\ No newline at end of file
+</Project>
diff --git a/vsprojects/make.bat b/vsprojects/make.bat
index 04737aeefc47d356dc79a0ff214c54287161dfa3..08c97bcd21fb53df30ba85ed0eea7b7d91d43739 100644
--- a/vsprojects/make.bat
+++ b/vsprojects/make.bat
@@ -5,6 +5,7 @@ setlocal
 @rem Set VS variables (uses Visual Studio 2013)
 @call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
 
-nmake /f Grpc.mak %*
+@rem /K: continue on error
+nmake /K /f Grpc.mak %*
 exit /b %ERRORLEVEL%
-endlocal
\ No newline at end of file
+endlocal