From 714038204a897c4eb7064686181b447f3dfa9da5 Mon Sep 17 00:00:00 2001
From: "Mark D. Roth" <roth@google.com>
Date: Fri, 2 Dec 2016 10:51:39 -0800
Subject: [PATCH] Use the same server code for both secure and insecure
 servers.

---
 BUILD                                         |   8 +
 CMakeLists.txt                                |   3 +
 Makefile                                      |   3 +
 binding.gyp                                   |   1 +
 build.yaml                                    |  10 +
 config.m4                                     |   2 +
 gRPC-Core.podspec                             |   3 +
 grpc.gemspec                                  |   2 +
 package.xml                                   |   2 +
 .../transport/chttp2/server/chttp2_server.c   | 355 ++++++++++++++++++
 .../transport/chttp2/server/chttp2_server.h   |  79 ++++
 .../chttp2/server/insecure/server_chttp2.c    | 283 +-------------
 .../server/secure/server_secure_chttp2.c      | 346 +++--------------
 src/python/grpcio/grpc_core_dependencies.py   |   1 +
 tools/doxygen/Doxyfile.core.internal          |   2 +
 tools/run_tests/sources_and_headers.json      |  23 +-
 vsprojects/vcxproj/grpc/grpc.vcxproj          |   3 +
 vsprojects/vcxproj/grpc/grpc.vcxproj.filters  |   6 +
 .../grpc_unsecure/grpc_unsecure.vcxproj       |   3 +
 .../grpc_unsecure.vcxproj.filters             |   6 +
 20 files changed, 572 insertions(+), 569 deletions(-)
 create mode 100644 src/core/ext/transport/chttp2/server/chttp2_server.c
 create mode 100644 src/core/ext/transport/chttp2/server/chttp2_server.h

diff --git a/BUILD b/BUILD
index 1ee5fd3dacf..ab0fc237b78 100644
--- a/BUILD
+++ b/BUILD
@@ -298,6 +298,7 @@ cc_library(
     "src/core/lib/tsi/ssl_types.h",
     "src/core/lib/tsi/transport_security.h",
     "src/core/lib/tsi/transport_security_interface.h",
+    "src/core/ext/transport/chttp2/server/chttp2_server.h",
     "src/core/ext/client_channel/client_channel.h",
     "src/core/ext/client_channel/client_channel_factory.h",
     "src/core/ext/client_channel/connector.h",
@@ -493,6 +494,7 @@ cc_library(
     "src/core/lib/tsi/fake_transport_security.c",
     "src/core/lib/tsi/ssl_transport_security.c",
     "src/core/lib/tsi/transport_security.c",
+    "src/core/ext/transport/chttp2/server/chttp2_server.c",
     "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
     "src/core/ext/client_channel/channel_connectivity.c",
     "src/core/ext/client_channel/client_channel.c",
@@ -1101,6 +1103,7 @@ cc_library(
     "src/core/ext/transport/chttp2/transport/stream_map.h",
     "src/core/ext/transport/chttp2/transport/varint.h",
     "src/core/ext/transport/chttp2/alpn/alpn.h",
+    "src/core/ext/transport/chttp2/server/chttp2_server.h",
     "src/core/ext/transport/chttp2/client/chttp2_connector.h",
     "src/core/ext/client_channel/client_channel.h",
     "src/core/ext/client_channel/client_channel_factory.h",
@@ -1271,6 +1274,7 @@ cc_library(
     "src/core/ext/transport/chttp2/transport/varint.c",
     "src/core/ext/transport/chttp2/transport/writing.c",
     "src/core/ext/transport/chttp2/alpn/alpn.c",
+    "src/core/ext/transport/chttp2/server/chttp2_server.c",
     "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
     "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
     "src/core/ext/transport/chttp2/client/chttp2_connector.c",
@@ -1655,6 +1659,7 @@ cc_library(
     "src/core/ext/client_channel/subchannel.h",
     "src/core/ext/client_channel/subchannel_index.h",
     "src/core/ext/client_channel/uri_parser.h",
+    "src/core/ext/transport/chttp2/server/chttp2_server.h",
     "src/core/ext/census/aggregation.h",
     "src/core/ext/census/base_resources.h",
     "src/core/ext/census/census_interface.h",
@@ -1856,6 +1861,7 @@ cc_library(
     "src/core/ext/client_channel/uri_parser.c",
     "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
     "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
+    "src/core/ext/transport/chttp2/server/chttp2_server.c",
     "src/core/ext/census/base_resources.c",
     "src/core/ext/census/context.c",
     "src/core/ext/census/gen/census.pb.c",
@@ -2486,6 +2492,7 @@ objc_library(
     "src/core/lib/tsi/fake_transport_security.c",
     "src/core/lib/tsi/ssl_transport_security.c",
     "src/core/lib/tsi/transport_security.c",
+    "src/core/ext/transport/chttp2/server/chttp2_server.c",
     "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
     "src/core/ext/client_channel/channel_connectivity.c",
     "src/core/ext/client_channel/client_channel.c",
@@ -2706,6 +2713,7 @@ objc_library(
     "src/core/lib/tsi/ssl_types.h",
     "src/core/lib/tsi/transport_security.h",
     "src/core/lib/tsi/transport_security_interface.h",
+    "src/core/ext/transport/chttp2/server/chttp2_server.h",
     "src/core/ext/client_channel/client_channel.h",
     "src/core/ext/client_channel/client_channel_factory.h",
     "src/core/ext/client_channel/connector.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 66f740fe288..ff0927504aa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -447,6 +447,7 @@ add_library(grpc
   src/core/lib/tsi/fake_transport_security.c
   src/core/lib/tsi/ssl_transport_security.c
   src/core/lib/tsi/transport_security.c
+  src/core/ext/transport/chttp2/server/chttp2_server.c
   src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
   src/core/ext/client_channel/channel_connectivity.c
   src/core/ext/client_channel/client_channel.c
@@ -953,6 +954,7 @@ add_library(grpc_unsecure
   src/core/ext/transport/chttp2/transport/varint.c
   src/core/ext/transport/chttp2/transport/writing.c
   src/core/ext/transport/chttp2/alpn/alpn.c
+  src/core/ext/transport/chttp2/server/chttp2_server.c
   src/core/ext/transport/chttp2/client/insecure/channel_create.c
   src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
   src/core/ext/transport/chttp2/client/chttp2_connector.c
@@ -1416,6 +1418,7 @@ add_library(grpc++_cronet
   src/core/ext/client_channel/uri_parser.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
+  src/core/ext/transport/chttp2/server/chttp2_server.c
   src/core/ext/census/base_resources.c
   src/core/ext/census/context.c
   src/core/ext/census/gen/census.pb.c
diff --git a/Makefile b/Makefile
index e80a10e4439..db30c215862 100644
--- a/Makefile
+++ b/Makefile
@@ -2786,6 +2786,7 @@ LIBGRPC_SRC = \
     src/core/lib/tsi/fake_transport_security.c \
     src/core/lib/tsi/ssl_transport_security.c \
     src/core/lib/tsi/transport_security.c \
+    src/core/ext/transport/chttp2/server/chttp2_server.c \
     src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
     src/core/ext/client_channel/channel_connectivity.c \
     src/core/ext/client_channel/client_channel.c \
@@ -3564,6 +3565,7 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/ext/transport/chttp2/transport/varint.c \
     src/core/ext/transport/chttp2/transport/writing.c \
     src/core/ext/transport/chttp2/alpn/alpn.c \
+    src/core/ext/transport/chttp2/server/chttp2_server.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
     src/core/ext/transport/chttp2/client/chttp2_connector.c \
@@ -4139,6 +4141,7 @@ LIBGRPC++_CRONET_SRC = \
     src/core/ext/client_channel/uri_parser.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
+    src/core/ext/transport/chttp2/server/chttp2_server.c \
     src/core/ext/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
diff --git a/binding.gyp b/binding.gyp
index 8b1f5131fca..516cbdce5dc 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -727,6 +727,7 @@
         'src/core/lib/tsi/fake_transport_security.c',
         'src/core/lib/tsi/ssl_transport_security.c',
         'src/core/lib/tsi/transport_security.c',
+        'src/core/ext/transport/chttp2/server/chttp2_server.c',
         'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
         'src/core/ext/client_channel/channel_connectivity.c',
         'src/core/ext/client_channel/client_channel.c',
diff --git a/build.yaml b/build.yaml
index 1b95b2098e1..68d19a6b44f 100644
--- a/build.yaml
+++ b/build.yaml
@@ -647,6 +647,14 @@ filegroups:
   - grpc_client_channel
   - grpc_secure
   - grpc_transport_chttp2_client_connector
+- name: grpc_transport_chttp2_server
+  headers:
+  - src/core/ext/transport/chttp2/server/chttp2_server.h
+  src:
+  - src/core/ext/transport/chttp2/server/chttp2_server.c
+  uses:
+  - grpc_transport_chttp2
+  - grpc_base
 - name: grpc_transport_chttp2_server_insecure
   src:
   - src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -654,6 +662,7 @@ filegroups:
   uses:
   - grpc_transport_chttp2
   - grpc_base
+  - grpc_transport_chttp2_server
 - name: grpc_transport_chttp2_server_secure
   src:
   - src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -661,6 +670,7 @@ filegroups:
   - grpc_transport_chttp2
   - grpc_base
   - grpc_secure
+  - grpc_transport_chttp2_server
 - name: grpc_transport_cronet_client_secure
   public_headers:
   - include/grpc/grpc_cronet.h
diff --git a/config.m4 b/config.m4
index 5f48cf04a05..4b86e25581d 100644
--- a/config.m4
+++ b/config.m4
@@ -243,6 +243,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/tsi/fake_transport_security.c \
     src/core/lib/tsi/ssl_transport_security.c \
     src/core/lib/tsi/transport_security.c \
+    src/core/ext/transport/chttp2/server/chttp2_server.c \
     src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
     src/core/ext/client_channel/channel_connectivity.c \
     src/core/ext/client_channel/client_channel.c \
@@ -613,6 +614,7 @@ if test "$PHP_GRPC" != "no"; then
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/insecure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/secure)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/insecure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 8ea6eca6a5b..04f7211d210 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -387,6 +387,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/tsi/ssl_types.h',
                       'src/core/lib/tsi/transport_security.h',
                       'src/core/lib/tsi/transport_security_interface.h',
+                      'src/core/ext/transport/chttp2/server/chttp2_server.h',
                       'src/core/ext/client_channel/client_channel.h',
                       'src/core/ext/client_channel/client_channel_factory.h',
                       'src/core/ext/client_channel/connector.h',
@@ -586,6 +587,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/tsi/fake_transport_security.c',
                       'src/core/lib/tsi/ssl_transport_security.c',
                       'src/core/lib/tsi/transport_security.c',
+                      'src/core/ext/transport/chttp2/server/chttp2_server.c',
                       'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
                       'src/core/ext/client_channel/channel_connectivity.c',
                       'src/core/ext/client_channel/client_channel.c',
@@ -792,6 +794,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/tsi/ssl_types.h',
                               'src/core/lib/tsi/transport_security.h',
                               'src/core/lib/tsi/transport_security_interface.h',
+                              'src/core/ext/transport/chttp2/server/chttp2_server.h',
                               'src/core/ext/client_channel/client_channel.h',
                               'src/core/ext/client_channel/client_channel_factory.h',
                               'src/core/ext/client_channel/connector.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 9fe6512673c..6019b97f672 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -306,6 +306,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/tsi/ssl_types.h )
   s.files += %w( src/core/lib/tsi/transport_security.h )
   s.files += %w( src/core/lib/tsi/transport_security_interface.h )
+  s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h )
   s.files += %w( src/core/ext/client_channel/client_channel.h )
   s.files += %w( src/core/ext/client_channel/client_channel_factory.h )
   s.files += %w( src/core/ext/client_channel/connector.h )
@@ -505,6 +506,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/tsi/fake_transport_security.c )
   s.files += %w( src/core/lib/tsi/ssl_transport_security.c )
   s.files += %w( src/core/lib/tsi/transport_security.c )
+  s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.c )
   s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.c )
   s.files += %w( src/core/ext/client_channel/channel_connectivity.c )
   s.files += %w( src/core/ext/client_channel/client_channel.c )
diff --git a/package.xml b/package.xml
index 7f2c6130ff3..61668815a68 100644
--- a/package.xml
+++ b/package.xml
@@ -314,6 +314,7 @@
     <file baseinstalldir="/" name="src/core/lib/tsi/ssl_types.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/tsi/transport_security.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/tsi/transport_security_interface.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/connector.h" role="src" />
@@ -513,6 +514,7 @@
     <file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/tsi/ssl_transport_security.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/tsi/transport_security.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/secure/secure_channel_create.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/channel_connectivity.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.c" role="src" />
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c
new file mode 100644
index 00000000000..9282d7ef898
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -0,0 +1,355 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/server/chttp2_server.h"
+
+#include <grpc/grpc.h>
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/server.h"
+
+void grpc_chttp2_server_handshaker_factory_create_handshakers(
+    grpc_exec_ctx *exec_ctx,
+    grpc_chttp2_server_handshaker_factory *handshaker_factory,
+    grpc_handshake_manager *handshake_mgr) {
+  if (handshaker_factory != NULL) {
+    handshaker_factory->vtable->create_handshakers(
+        exec_ctx, handshaker_factory, handshake_mgr);
+  }
+}
+
+void grpc_chttp2_server_handshaker_factory_destroy(
+    grpc_exec_ctx *exec_ctx,
+    grpc_chttp2_server_handshaker_factory *handshaker_factory) {
+  if (handshaker_factory != NULL) {
+    handshaker_factory->vtable->destroy(exec_ctx, handshaker_factory);
+  }
+}
+
+
+typedef struct pending_handshake_manager_node {
+  grpc_handshake_manager *handshake_mgr;
+  struct pending_handshake_manager_node *next;
+} pending_handshake_manager_node;
+
+typedef struct {
+  grpc_server *server;
+  grpc_tcp_server *tcp_server;
+  grpc_channel_args *args;
+  grpc_chttp2_server_handshaker_factory *handshaker_factory;
+  gpr_mu mu;
+  bool shutdown;
+  grpc_closure tcp_server_shutdown_complete;
+  grpc_closure *server_destroy_listener_done;
+  pending_handshake_manager_node *pending_handshake_mgrs;
+} server_state;
+
+typedef struct {
+  server_state *server_state;
+  grpc_pollset *accepting_pollset;
+  grpc_tcp_server_acceptor *acceptor;
+  grpc_handshake_manager *handshake_mgr;
+} server_connection_state;
+
+static void pending_handshake_manager_add_locked(
+    server_state *state, grpc_handshake_manager *handshake_mgr) {
+  pending_handshake_manager_node *node = gpr_malloc(sizeof(*node));
+  node->handshake_mgr = handshake_mgr;
+  node->next = state->pending_handshake_mgrs;
+  state->pending_handshake_mgrs = node;
+}
+
+static void pending_handshake_manager_remove_locked(
+    server_state *state, grpc_handshake_manager *handshake_mgr) {
+  pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs;
+  for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
+       node != NULL; node = node->next) {
+    if (node->handshake_mgr == handshake_mgr) {
+      *prev_node = node->next;
+      gpr_free(node);
+      break;
+    }
+    prev_node = &node->next;
+  }
+}
+
+static void pending_handshake_manager_shutdown_locked(grpc_exec_ctx *exec_ctx,
+                                                      server_state *state) {
+  pending_handshake_manager_node *prev_node = NULL;
+  for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
+       node != NULL; node = node->next) {
+    grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr);
+    gpr_free(prev_node);
+    prev_node = node;
+  }
+  gpr_free(prev_node);
+  state->pending_handshake_mgrs = NULL;
+}
+
+static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
+                              grpc_error *error) {
+  grpc_handshaker_args *args = arg;
+  server_connection_state *connection_state = args->user_data;
+  gpr_mu_lock(&connection_state->server_state->mu);
+  if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) {
+    const char *error_str = grpc_error_string(error);
+    gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
+    grpc_error_free_string(error_str);
+    if (error == GRPC_ERROR_NONE) {
+      // We were shut down after handshaking completed successfully, so
+      // destroy the endpoint here.
+      // TODO(ctiller): It is currently necessary to shutdown endpoints
+      // before destroying them, even if we know that there are no
+      // pending read/write callbacks.  This should be fixed, at which
+      // point this can be removed.
+      grpc_endpoint_shutdown(exec_ctx, args->endpoint);
+      grpc_endpoint_destroy(exec_ctx, args->endpoint);
+      grpc_channel_args_destroy(args->args);
+      grpc_slice_buffer_destroy(args->read_buffer);
+      gpr_free(args->read_buffer);
+    }
+  } else {
+    grpc_transport *transport =
+        grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 0);
+    grpc_server_setup_transport(
+        exec_ctx, connection_state->server_state->server, transport,
+        connection_state->accepting_pollset, args->args);
+    grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer);
+    grpc_channel_args_destroy(args->args);
+  }
+  pending_handshake_manager_remove_locked(connection_state->server_state,
+                                          connection_state->handshake_mgr);
+  gpr_mu_unlock(&connection_state->server_state->mu);
+  grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
+  grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server);
+  gpr_free(connection_state);
+}
+
+static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
+                      grpc_pollset *accepting_pollset,
+                      grpc_tcp_server_acceptor *acceptor) {
+  server_state *state = arg;
+  gpr_mu_lock(&state->mu);
+  if (state->shutdown) {
+    gpr_mu_unlock(&state->mu);
+    grpc_endpoint_destroy(exec_ctx, tcp);
+    return;
+  }
+  grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create();
+  pending_handshake_manager_add_locked(state, handshake_mgr);
+  gpr_mu_unlock(&state->mu);
+  grpc_tcp_server_ref(state->tcp_server);
+  server_connection_state *connection_state =
+      gpr_malloc(sizeof(*connection_state));
+  connection_state->server_state = state;
+  connection_state->accepting_pollset = accepting_pollset;
+  connection_state->acceptor = acceptor;
+  connection_state->handshake_mgr = handshake_mgr;
+  grpc_chttp2_server_handshaker_factory_create_handshakers(
+      exec_ctx, state->handshaker_factory, connection_state->handshake_mgr);
+  // TODO(roth): We should really get this timeout value from channel
+  // args instead of hard-coding it.
+  const gpr_timespec deadline = gpr_time_add(
+      gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
+  grpc_handshake_manager_do_handshake(
+      exec_ctx, connection_state->handshake_mgr, tcp, state->args, deadline,
+      acceptor, on_handshake_done, connection_state);
+}
+
+/* Server callback: start listening on our ports */
+static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server,
+                                  void *arg, grpc_pollset **pollsets,
+                                  size_t pollset_count) {
+  server_state *state = arg;
+  gpr_mu_lock(&state->mu);
+  state->shutdown = false;
+  gpr_mu_unlock(&state->mu);
+  grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count,
+                        on_accept, state);
+}
+
+static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg,
+                                         grpc_error *error) {
+  server_state *state = arg;
+  /* ensure all threads have unlocked */
+  gpr_mu_lock(&state->mu);
+  grpc_closure *destroy_done = state->server_destroy_listener_done;
+  GPR_ASSERT(state->shutdown);
+  pending_handshake_manager_shutdown_locked(exec_ctx, state);
+  gpr_mu_unlock(&state->mu);
+  // Flush queued work before destroying handshaker factory, since that
+  // may do a synchronous unref.
+  grpc_exec_ctx_flush(exec_ctx);
+  grpc_chttp2_server_handshaker_factory_destroy(exec_ctx,
+                                                state->handshaker_factory);
+  if (destroy_done != NULL) {
+    destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error));
+    grpc_exec_ctx_flush(exec_ctx);
+  }
+  grpc_channel_args_destroy(state->args);
+  gpr_mu_destroy(&state->mu);
+  gpr_free(state);
+}
+
+/* Server callback: destroy the tcp listener (so we don't generate further
+   callbacks) */
+static void server_destroy_listener(grpc_exec_ctx *exec_ctx,
+                                    grpc_server *server, void *arg,
+                                    grpc_closure *destroy_done) {
+  server_state *state = arg;
+  gpr_mu_lock(&state->mu);
+  state->shutdown = true;
+  state->server_destroy_listener_done = destroy_done;
+  grpc_tcp_server *tcp_server = state->tcp_server;
+  gpr_mu_unlock(&state->mu);
+  grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server);
+  grpc_tcp_server_unref(exec_ctx, tcp_server);
+}
+
+grpc_error *grpc_chttp2_server_add_port(
+    grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr,
+    grpc_channel_args *args,
+    grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num) {
+  grpc_resolved_addresses *resolved = NULL;
+  grpc_tcp_server *tcp_server = NULL;
+  size_t i;
+  size_t count = 0;
+  int port_temp;
+  grpc_error *err = GRPC_ERROR_NONE;
+  server_state *state = NULL;
+
+  *port_num = -1;
+
+  /* resolve address */
+  err = grpc_blocking_resolve_address(addr, "https", &resolved);
+  if (err != GRPC_ERROR_NONE) {
+    goto error;
+  }
+  state = gpr_malloc(sizeof(*state));
+  memset(state, 0, sizeof(*state));
+  grpc_closure_init(&state->tcp_server_shutdown_complete,
+                    tcp_server_shutdown_complete, state);
+  err =
+      grpc_tcp_server_create(exec_ctx, &state->tcp_server_shutdown_complete,
+                             args, &tcp_server);
+  if (err != GRPC_ERROR_NONE) {
+    goto error;
+  }
+
+  state->server = server;
+  state->tcp_server = tcp_server;
+  state->args = args;
+  state->handshaker_factory = handshaker_factory;
+  state->shutdown = true;
+  gpr_mu_init(&state->mu);
+
+  const size_t naddrs = resolved->naddrs;
+  grpc_error **errors = gpr_malloc(sizeof(*errors) * naddrs);
+  for (i = 0; i < naddrs; i++) {
+    errors[i] =
+        grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp);
+    if (errors[i] == GRPC_ERROR_NONE) {
+      if (*port_num == -1) {
+        *port_num = port_temp;
+      } else {
+        GPR_ASSERT(*port_num == port_temp);
+      }
+      count++;
+    }
+  }
+  if (count == 0) {
+    char *msg;
+    gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
+                 naddrs);
+    err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
+    gpr_free(msg);
+    goto error;
+  } else if (count != naddrs) {
+    char *msg;
+    gpr_asprintf(&msg, "Only %" PRIuPTR
+                       " addresses added out of total %" PRIuPTR " resolved",
+                 count, naddrs);
+    err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
+    gpr_free(msg);
+
+    const char *warning_message = grpc_error_string(err);
+    gpr_log(GPR_INFO, "WARNING: %s", warning_message);
+    grpc_error_free_string(warning_message);
+    /* we managed to bind some addresses: continue */
+  }
+  grpc_resolved_addresses_destroy(resolved);
+
+  /* Register with the server only upon success */
+  grpc_server_add_listener(exec_ctx, server, state, server_start_listener,
+                           server_destroy_listener);
+  goto done;
+
+/* Error path: cleanup and return */
+error:
+  GPR_ASSERT(err != GRPC_ERROR_NONE);
+  if (resolved) {
+    grpc_resolved_addresses_destroy(resolved);
+  }
+  if (tcp_server) {
+    grpc_tcp_server_unref(exec_ctx, tcp_server);
+  }
+  grpc_channel_args_destroy(state->args);
+  grpc_chttp2_server_handshaker_factory_destroy(exec_ctx,
+                                                state->handshaker_factory);
+  gpr_free(state);
+  *port_num = 0;
+
+done:
+  if (errors != NULL) {
+    for (i = 0; i < naddrs; i++) {
+      GRPC_ERROR_UNREF(errors[i]);
+    }
+    gpr_free(errors);
+  }
+  return err;
+}
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.h b/src/core/ext/transport/chttp2/server/chttp2_server.h
new file mode 100644
index 00000000000..b1ff04bcbb8
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+/// A server handshaker factory is used to create handshakers for server
+/// connections.
+typedef struct grpc_chttp2_server_handshaker_factory
+    grpc_chttp2_server_handshaker_factory;
+
+typedef struct {
+  void (*create_handshakers)(
+      grpc_exec_ctx *exec_ctx,
+      grpc_chttp2_server_handshaker_factory *handshaker_factory,
+      grpc_handshake_manager *handshake_mgr);
+  void (*destroy)(grpc_exec_ctx *exec_ctx,
+                  grpc_chttp2_server_handshaker_factory *handshaker_factory);
+} grpc_chttp2_server_handshaker_factory_vtable;
+
+struct grpc_chttp2_server_handshaker_factory {
+  const grpc_chttp2_server_handshaker_factory_vtable *vtable;
+};
+
+void grpc_chttp2_server_handshaker_factory_create_handshakers(
+    grpc_exec_ctx *exec_ctx,
+    grpc_chttp2_server_handshaker_factory *handshaker_factory,
+    grpc_handshake_manager *handshake_mgr);
+
+void grpc_chttp2_server_handshaker_factory_destroy(
+    grpc_exec_ctx *exec_ctx,
+    grpc_chttp2_server_handshaker_factory *handshaker_factory);
+
+/// Adds a port to \a server.  Sets \a port_num to the port number.
+/// If \a handshaker_factory is not NULL, it will be used to create
+/// handshakers for the port.
+/// Takes ownership of \a args and \a handshaker_factory.
+grpc_error *grpc_chttp2_server_add_port(
+    grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr,
+    grpc_channel_args *args,
+    grpc_chttp2_server_handshaker_factory *handshaker_factory,
+    int *port_num);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H */
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
index a4d7fc5f70b..366312bd728 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -33,291 +33,28 @@
 
 #include <grpc/grpc.h>
 
-#include <string.h>
-
-#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
 
-#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/server/chttp2_server.h"
 #include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
 
-typedef struct pending_handshake_manager_node {
-  grpc_handshake_manager *handshake_mgr;
-  struct pending_handshake_manager_node *next;
-} pending_handshake_manager_node;
-
-typedef struct {
-  grpc_server *server;
-  grpc_tcp_server *tcp_server;
-  gpr_mu mu;
-  bool shutdown;
-  grpc_closure tcp_server_shutdown_complete;
-  grpc_closure *server_destroy_listener_done;
-  pending_handshake_manager_node *pending_handshake_mgrs;
-} server_state;
-
-typedef struct {
-  server_state *server_state;
-  grpc_pollset *accepting_pollset;
-  grpc_tcp_server_acceptor *acceptor;
-  grpc_handshake_manager *handshake_mgr;
-} server_connection_state;
-
-static void pending_handshake_manager_add_locked(
-    server_state *state, grpc_handshake_manager *handshake_mgr) {
-  pending_handshake_manager_node *node = gpr_malloc(sizeof(*node));
-  node->handshake_mgr = handshake_mgr;
-  node->next = state->pending_handshake_mgrs;
-  state->pending_handshake_mgrs = node;
-}
-
-static void pending_handshake_manager_remove_locked(
-    server_state *state, grpc_handshake_manager *handshake_mgr) {
-  pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs;
-  for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
-       node != NULL; node = node->next) {
-    if (node->handshake_mgr == handshake_mgr) {
-      *prev_node = node->next;
-      gpr_free(node);
-      break;
-    }
-    prev_node = &node->next;
-  }
-}
-
-static void pending_handshake_manager_shutdown_locked(grpc_exec_ctx *exec_ctx,
-                                                      server_state *state) {
-  pending_handshake_manager_node *prev_node = NULL;
-  for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
-       node != NULL; node = node->next) {
-    grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr);
-    gpr_free(prev_node);
-    prev_node = node;
-  }
-  gpr_free(prev_node);
-  state->pending_handshake_mgrs = NULL;
-}
-
-static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
-                              grpc_error *error) {
-  grpc_handshaker_args *args = arg;
-  server_connection_state *connection_state = args->user_data;
-  gpr_mu_lock(&connection_state->server_state->mu);
-  if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) {
-    const char *error_str = grpc_error_string(error);
-    gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
-    grpc_error_free_string(error_str);
-    if (error == GRPC_ERROR_NONE) {
-      // We were shut down after handshaking completed successfully, so
-      // destroy the endpoint here.
-      // TODO(ctiller): It is currently necessary to shutdown endpoints
-      // before destroying them, even if we know that there are no
-      // pending read/write callbacks.  This should be fixed, at which
-      // point this can be removed.
-      grpc_endpoint_shutdown(exec_ctx, args->endpoint);
-      grpc_endpoint_destroy(exec_ctx, args->endpoint);
-      grpc_channel_args_destroy(args->args);
-      grpc_slice_buffer_destroy(args->read_buffer);
-      gpr_free(args->read_buffer);
-    }
-  } else {
-    grpc_transport *transport =
-        grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 0);
-    grpc_server_setup_transport(
-        exec_ctx, connection_state->server_state->server, transport,
-        connection_state->accepting_pollset,
-        grpc_server_get_channel_args(connection_state->server_state->server));
-    grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer);
-    grpc_channel_args_destroy(args->args);
-  }
-  pending_handshake_manager_remove_locked(connection_state->server_state,
-                                          connection_state->handshake_mgr);
-  gpr_mu_unlock(&connection_state->server_state->mu);
-  grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
-  grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server);
-  gpr_free(connection_state);
-}
-
-static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
-                      grpc_pollset *accepting_pollset,
-                      grpc_tcp_server_acceptor *acceptor) {
-  server_state *state = arg;
-  gpr_mu_lock(&state->mu);
-  if (state->shutdown) {
-    gpr_mu_unlock(&state->mu);
-    grpc_endpoint_destroy(exec_ctx, tcp);
-    return;
-  }
-  grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create();
-  pending_handshake_manager_add_locked(state, handshake_mgr);
-  gpr_mu_unlock(&state->mu);
-  grpc_tcp_server_ref(state->tcp_server);
-  server_connection_state *connection_state =
-      gpr_malloc(sizeof(*connection_state));
-  connection_state->server_state = state;
-  connection_state->accepting_pollset = accepting_pollset;
-  connection_state->acceptor = acceptor;
-  connection_state->handshake_mgr = handshake_mgr;
-  // TODO(roth): We should really get this timeout value from channel
-  // args instead of hard-coding it.
-  const gpr_timespec deadline = gpr_time_add(
-      gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
-  grpc_handshake_manager_do_handshake(
-      exec_ctx, connection_state->handshake_mgr, tcp,
-      grpc_server_get_channel_args(state->server), deadline, acceptor,
-      on_handshake_done, connection_state);
-}
-
-/* Server callback: start listening on our ports */
-static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server,
-                                  void *arg, grpc_pollset **pollsets,
-                                  size_t pollset_count) {
-  server_state *state = arg;
-  gpr_mu_lock(&state->mu);
-  state->shutdown = false;
-  gpr_mu_unlock(&state->mu);
-  grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count,
-                        on_accept, state);
-}
-
-static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg,
-                                         grpc_error *error) {
-  server_state *state = arg;
-  /* ensure all threads have unlocked */
-  gpr_mu_lock(&state->mu);
-  grpc_closure *destroy_done = state->server_destroy_listener_done;
-  GPR_ASSERT(state->shutdown);
-  pending_handshake_manager_shutdown_locked(exec_ctx, state);
-  gpr_mu_unlock(&state->mu);
-  // Invoke callback.
-  if (destroy_done != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, destroy_done, GRPC_ERROR_REF(error), NULL);
-  }
-  gpr_mu_destroy(&state->mu);
-  gpr_free(state);
-}
-
-/* Server callback: destroy the tcp listener (so we don't generate further
-   callbacks) */
-static void server_destroy_listener(grpc_exec_ctx *exec_ctx,
-                                    grpc_server *server, void *arg,
-                                    grpc_closure *destroy_done) {
-  server_state *state = arg;
-  gpr_mu_lock(&state->mu);
-  state->shutdown = true;
-  state->server_destroy_listener_done = destroy_done;
-  grpc_tcp_server *tcp_server = state->tcp_server;
-  gpr_mu_unlock(&state->mu);
-  grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server);
-  grpc_tcp_server_unref(exec_ctx, tcp_server);
-}
-
 int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
-  grpc_resolved_addresses *resolved = NULL;
-  grpc_tcp_server *tcp_server = NULL;
-  size_t i;
-  size_t count = 0;
-  int port_num = -1;
-  int port_temp;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_error *err = GRPC_ERROR_NONE;
-
+  int port_num = 0;
   GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
                  (server, addr));
-
-  grpc_error **errors = NULL;
-  err = grpc_blocking_resolve_address(addr, "https", &resolved);
-  if (err != GRPC_ERROR_NONE) {
-    goto error;
-  }
-  server_state *state = gpr_malloc(sizeof(*state));
-  memset(state, 0, sizeof(*state));
-  grpc_closure_init(&state->tcp_server_shutdown_complete,
-                    tcp_server_shutdown_complete, state);
-  err =
-      grpc_tcp_server_create(&exec_ctx, &state->tcp_server_shutdown_complete,
-                             grpc_server_get_channel_args(server), &tcp_server);
+  grpc_error* err = grpc_chttp2_server_add_port(
+      &exec_ctx, server, addr,
+      grpc_channel_args_copy(grpc_server_get_channel_args(server)),
+      NULL /* handshaker_factory */, &port_num);
   if (err != GRPC_ERROR_NONE) {
-    goto error;
-  }
-
-  state->server = server;
-  state->tcp_server = tcp_server;
-  state->shutdown = true;
-  gpr_mu_init(&state->mu);
-
-  const size_t naddrs = resolved->naddrs;
-  errors = gpr_malloc(sizeof(*errors) * naddrs);
-  for (i = 0; i < naddrs; i++) {
-    errors[i] =
-        grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp);
-    if (errors[i] == GRPC_ERROR_NONE) {
-      if (port_num == -1) {
-        port_num = port_temp;
-      } else {
-        GPR_ASSERT(port_num == port_temp);
-      }
-      count++;
-    }
-  }
-  if (count == 0) {
-    char *msg;
-    gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
-                 naddrs);
-    err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
-    gpr_free(msg);
-    goto error;
-  } else if (count != naddrs) {
-    char *msg;
-    gpr_asprintf(&msg, "Only %" PRIuPTR
-                       " addresses added out of total %" PRIuPTR " resolved",
-                 count, naddrs);
-    err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
-    gpr_free(msg);
-
-    const char *warning_message = grpc_error_string(err);
-    gpr_log(GPR_INFO, "WARNING: %s", warning_message);
-    grpc_error_free_string(warning_message);
-    /* we managed to bind some addresses: continue */
-  }
-  grpc_resolved_addresses_destroy(resolved);
-
-  /* Register with the server only upon success */
-  grpc_server_add_listener(&exec_ctx, server, state, server_start_listener,
-                           server_destroy_listener);
-  goto done;
-
-/* Error path: cleanup and return */
-error:
-  GPR_ASSERT(err != GRPC_ERROR_NONE);
-  if (resolved) {
-    grpc_resolved_addresses_destroy(resolved);
-  }
-  if (tcp_server) {
-    grpc_tcp_server_unref(&exec_ctx, tcp_server);
+    const char *msg = grpc_error_string(err);
+    gpr_log(GPR_ERROR, "%s", msg);
+    grpc_error_free_string(msg);
+    GRPC_ERROR_UNREF(err);
   }
-  port_num = 0;
-
-  const char *msg = grpc_error_string(err);
-  gpr_log(GPR_ERROR, "%s", msg);
-  grpc_error_free_string(msg);
-  GRPC_ERROR_UNREF(err);
-
-done:
   grpc_exec_ctx_finish(&exec_ctx);
-  if (errors != NULL) {
-    for (i = 0; i < naddrs; i++) {
-      GRPC_ERROR_UNREF(errors[i]);
-    }
-  }
-  gpr_free(errors);
   return port_num;
 }
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
index 8d2371c917e..b9a833803bc 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -38,230 +38,62 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/ext/transport/chttp2/server/chttp2_server.h"
+
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/iomgr/endpoint.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/auth_filters.h"
-#include "src/core/lib/security/transport/security_connector.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
 
-typedef struct pending_handshake_manager_node {
-  grpc_handshake_manager *handshake_mgr;
-  struct pending_handshake_manager_node *next;
-} pending_handshake_manager_node;
-
-typedef struct server_secure_state {
-  grpc_server *server;
-  grpc_tcp_server *tcp_server;
-  grpc_server_security_connector *sc;
-  grpc_server_credentials *creds;
-  gpr_mu mu;
-  bool shutdown;
-  grpc_closure tcp_server_shutdown_complete;
-  grpc_closure *server_destroy_listener_done;
-  pending_handshake_manager_node *pending_handshake_mgrs;
-} server_secure_state;
-
-typedef struct server_secure_connection_state {
-  server_secure_state *server_state;
-  grpc_pollset *accepting_pollset;
-  grpc_tcp_server_acceptor *acceptor;
-  grpc_handshake_manager *handshake_mgr;
-} server_secure_connection_state;
-
-static void pending_handshake_manager_add_locked(
-    server_secure_state *state, grpc_handshake_manager *handshake_mgr) {
-  pending_handshake_manager_node *node = gpr_malloc(sizeof(*node));
-  node->handshake_mgr = handshake_mgr;
-  node->next = state->pending_handshake_mgrs;
-  state->pending_handshake_mgrs = node;
-}
-
-static void pending_handshake_manager_remove_locked(
-    server_secure_state *state, grpc_handshake_manager *handshake_mgr) {
-  pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs;
-  for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
-       node != NULL; node = node->next) {
-    if (node->handshake_mgr == handshake_mgr) {
-      *prev_node = node->next;
-      gpr_free(node);
-      break;
-    }
-    prev_node = &node->next;
-  }
-}
+typedef struct {
+  grpc_chttp2_server_handshaker_factory base;
+  grpc_server_security_connector *security_connector;
+} server_security_handshaker_factory;
 
-static void pending_handshake_manager_shutdown_locked(
-    grpc_exec_ctx *exec_ctx, server_secure_state *state) {
-  pending_handshake_manager_node *prev_node = NULL;
-  for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
-       node != NULL; node = node->next) {
-    grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr);
-    gpr_free(prev_node);
-    prev_node = node;
-  }
-  gpr_free(prev_node);
-  state->pending_handshake_mgrs = NULL;
-}
-
-static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
-                              grpc_error *error) {
-  grpc_handshaker_args *args = arg;
-  server_secure_connection_state *connection_state = args->user_data;
-  gpr_mu_lock(&connection_state->server_state->mu);
-  if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) {
-    const char *error_str = grpc_error_string(error);
-    gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
-    grpc_error_free_string(error_str);
-    if (error == GRPC_ERROR_NONE) {
-      // We were shut down after handshaking completed successfully, so
-      // destroy the endpoint here.
-      // TODO(ctiller): It is currently necessary to shutdown endpoints
-      // before destroying them, even if we know that there are no
-      // pending read/write callbacks.  This should be fixed, at which
-      // point this can be removed.
-      grpc_endpoint_shutdown(exec_ctx, args->endpoint);
-      grpc_endpoint_destroy(exec_ctx, args->endpoint);
-      grpc_channel_args_destroy(args->args);
-      grpc_slice_buffer_destroy(args->read_buffer);
-      gpr_free(args->read_buffer);
-    }
-  } else {
-    grpc_arg channel_arg =
-        grpc_server_credentials_to_arg(connection_state->server_state->creds);
-    grpc_channel_args *args_copy =
-        grpc_channel_args_copy_and_add(args->args, &channel_arg, 1);
-    grpc_channel_args_destroy(args->args);
-    grpc_transport *transport =
-        grpc_create_chttp2_transport(exec_ctx, args_copy, args->endpoint, 0);
-    grpc_server_setup_transport(
-        exec_ctx, connection_state->server_state->server, transport,
-        connection_state->accepting_pollset, args_copy);
-    grpc_channel_args_destroy(args_copy);
-    grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer);
-  }
-  pending_handshake_manager_remove_locked(connection_state->server_state,
-                                          connection_state->handshake_mgr);
-  gpr_mu_unlock(&connection_state->server_state->mu);
-  grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
-  grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server);
-  gpr_free(connection_state);
-}
-
-static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
-                      grpc_pollset *accepting_pollset,
-                      grpc_tcp_server_acceptor *acceptor) {
-  server_secure_state *state = arg;
-  gpr_mu_lock(&state->mu);
-  if (state->shutdown) {
-    gpr_mu_unlock(&state->mu);
-    grpc_endpoint_destroy(exec_ctx, tcp);
-    return;
-  }
-  grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create();
-  pending_handshake_manager_add_locked(state, handshake_mgr);
-  gpr_mu_unlock(&state->mu);
-  grpc_tcp_server_ref(state->tcp_server);
-  server_secure_connection_state *connection_state =
-      gpr_malloc(sizeof(*connection_state));
-  connection_state->server_state = state;
-  connection_state->accepting_pollset = accepting_pollset;
-  connection_state->acceptor = acceptor;
-  connection_state->handshake_mgr = handshake_mgr;
+static void server_security_handshaker_factory_create_handshakers(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf,
+    grpc_handshake_manager *handshake_mgr) {
+  server_security_handshaker_factory *handshaker_factory =
+      (server_security_handshaker_factory *)hf;
   grpc_server_security_connector_create_handshakers(
-      exec_ctx, state->sc, connection_state->handshake_mgr);
-  // TODO(roth): We should really get this timeout value from channel
-  // args instead of hard-coding it.
-  const gpr_timespec deadline = gpr_time_add(
-      gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
-  grpc_handshake_manager_do_handshake(
-      exec_ctx, connection_state->handshake_mgr, tcp,
-      grpc_server_get_channel_args(state->server), deadline, acceptor,
-      on_handshake_done, connection_state);
+      exec_ctx, handshaker_factory->security_connector, handshake_mgr);
 }
 
-/* Server callback: start listening on our ports */
-static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server,
-                                  void *arg, grpc_pollset **pollsets,
-                                  size_t pollset_count) {
-  server_secure_state *state = arg;
-  gpr_mu_lock(&state->mu);
-  state->shutdown = false;
-  gpr_mu_unlock(&state->mu);
-  grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count,
-                        on_accept, state);
+static void server_security_handshaker_factory_destroy(
+    grpc_exec_ctx* exec_ctx, grpc_chttp2_server_handshaker_factory *hf) {
+  server_security_handshaker_factory *handshaker_factory =
+      (server_security_handshaker_factory *)hf;
+  GRPC_SECURITY_CONNECTOR_UNREF(&handshaker_factory->security_connector->base,
+                                "server");
 }
 
-static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg,
-                                         grpc_error *error) {
-  server_secure_state *state = arg;
-  /* ensure all threads have unlocked */
-  gpr_mu_lock(&state->mu);
-  grpc_closure *destroy_done = state->server_destroy_listener_done;
-  GPR_ASSERT(state->shutdown);
-  pending_handshake_manager_shutdown_locked(exec_ctx, state);
-  gpr_mu_unlock(&state->mu);
-  /* Flush queued work before a synchronous unref. */
-  grpc_exec_ctx_flush(exec_ctx);
-  GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server");
-  grpc_server_credentials_unref(state->creds);
-  if (destroy_done != NULL) {
-    destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error));
-    grpc_exec_ctx_flush(exec_ctx);
-  }
-  gpr_mu_destroy(&state->mu);
-  gpr_free(state);
-}
-
-static void server_destroy_listener(grpc_exec_ctx *exec_ctx,
-                                    grpc_server *server, void *arg,
-                                    grpc_closure *destroy_done) {
-  server_secure_state *state = arg;
-  gpr_mu_lock(&state->mu);
-  state->shutdown = true;
-  state->server_destroy_listener_done = destroy_done;
-  grpc_tcp_server *tcp_server = state->tcp_server;
-  gpr_mu_unlock(&state->mu);
-  grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server);
-  grpc_tcp_server_unref(exec_ctx, tcp_server);
-}
+static const grpc_chttp2_server_handshaker_factory_vtable
+    server_security_handshaker_factory_vtable = {
+        server_security_handshaker_factory_create_handshakers,
+        server_security_handshaker_factory_destroy};
 
 int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
                                       grpc_server_credentials *creds) {
-  grpc_resolved_addresses *resolved = NULL;
-  grpc_tcp_server *tcp_server = NULL;
-  server_secure_state *state = NULL;
-  size_t i;
-  size_t count = 0;
-  int port_num = -1;
-  int port_temp;
-  grpc_security_status status = GRPC_SECURITY_ERROR;
-  grpc_server_security_connector *sc = NULL;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_error *err = GRPC_ERROR_NONE;
-  grpc_error **errors = NULL;
-
+  grpc_server_security_connector *sc = NULL;
+  int port_num = 0;
   GRPC_API_TRACE(
       "grpc_server_add_secure_http2_port("
       "server=%p, addr=%s, creds=%p)",
       3, (server, addr, creds));
-
-  /* create security context */
+  // Create security context.
   if (creds == NULL) {
     err = GRPC_ERROR_CREATE(
         "No credentials specified for secure server port (creds==NULL)");
-    goto error;
+    goto done;
   }
-  status = grpc_server_credentials_create_security_connector(creds, &sc);
+  grpc_security_status status =
+      grpc_server_credentials_create_security_connector(creds, &sc);
   if (status != GRPC_SECURITY_OK) {
     char *msg;
     gpr_asprintf(&msg,
@@ -270,107 +102,31 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
     err = grpc_error_set_int(GRPC_ERROR_CREATE(msg),
                              GRPC_ERROR_INT_SECURITY_STATUS, status);
     gpr_free(msg);
-    goto error;
+    goto done;
   }
-
-  /* resolve address */
-  err = grpc_blocking_resolve_address(addr, "https", &resolved);
-  if (err != GRPC_ERROR_NONE) {
-    goto error;
-  }
-  state = gpr_malloc(sizeof(*state));
-  memset(state, 0, sizeof(*state));
-  grpc_closure_init(&state->tcp_server_shutdown_complete,
-                    tcp_server_shutdown_complete, state);
-  err =
-      grpc_tcp_server_create(&exec_ctx, &state->tcp_server_shutdown_complete,
-                             grpc_server_get_channel_args(server), &tcp_server);
-  if (err != GRPC_ERROR_NONE) {
-    goto error;
-  }
-
-  state->server = server;
-  state->tcp_server = tcp_server;
-  state->sc = sc;
-  state->creds = grpc_server_credentials_ref(creds);
-  state->shutdown = true;
-  gpr_mu_init(&state->mu);
-
-  errors = gpr_malloc(sizeof(*errors) * resolved->naddrs);
-  for (i = 0; i < resolved->naddrs; i++) {
-    errors[i] =
-        grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp);
-    if (errors[i] == GRPC_ERROR_NONE) {
-      if (port_num == -1) {
-        port_num = port_temp;
-      } else {
-        GPR_ASSERT(port_num == port_temp);
-      }
-      count++;
-    }
-  }
-  if (count == 0) {
-    char *msg;
-    gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
-                 resolved->naddrs);
-    err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
-    gpr_free(msg);
-    goto error;
-  } else if (count != resolved->naddrs) {
-    char *msg;
-    gpr_asprintf(&msg, "Only %" PRIuPTR
-                       " addresses added out of total %" PRIuPTR " resolved",
-                 count, resolved->naddrs);
-    err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
-    gpr_free(msg);
-
-    const char *warning_message = grpc_error_string(err);
-    gpr_log(GPR_INFO, "WARNING: %s", warning_message);
-    grpc_error_free_string(warning_message);
-    /* we managed to bind some addresses: continue */
-  } else {
-    for (i = 0; i < resolved->naddrs; i++) {
-      GRPC_ERROR_UNREF(errors[i]);
-    }
-  }
-  gpr_free(errors);
-  errors = NULL;
-  grpc_resolved_addresses_destroy(resolved);
-
-  /* Register with the server only upon success */
-  grpc_server_add_listener(&exec_ctx, server, state, server_start_listener,
-                           server_destroy_listener);
-
+  // Create handshaker factory.
+  server_security_handshaker_factory* handshaker_factory =
+     gpr_malloc(sizeof(*handshaker_factory));
+  memset(handshaker_factory, 0, sizeof(*handshaker_factory));
+  handshaker_factory->base.vtable = &server_security_handshaker_factory_vtable;
+  handshaker_factory->security_connector = sc;
+  // Create channel args.
+  grpc_arg channel_arg = grpc_server_credentials_to_arg(creds);
+  grpc_channel_args *args = grpc_channel_args_copy_and_add(
+      grpc_server_get_channel_args(server), &channel_arg, 1);
+  // Add server port.
+  err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args,
+                                    &handshaker_factory->base, &port_num);
+done:
   grpc_exec_ctx_finish(&exec_ctx);
-  return port_num;
-
-/* Error path: cleanup and return */
-error:
-  GPR_ASSERT(err != GRPC_ERROR_NONE);
-  if (errors != NULL) {
-    for (i = 0; i < resolved->naddrs; i++) {
-      GRPC_ERROR_UNREF(errors[i]);
-    }
-    gpr_free(errors);
-  }
-  if (resolved) {
-    grpc_resolved_addresses_destroy(resolved);
-  }
-  if (tcp_server) {
-    grpc_tcp_server_unref(&exec_ctx, tcp_server);
-  } else {
-    if (sc) {
-      grpc_exec_ctx_flush(&exec_ctx);
+  if (err != GRPC_ERROR_NONE) {
+    const char *msg = grpc_error_string(err);
+    gpr_log(GPR_ERROR, "%s", msg);
+    grpc_error_free_string(msg);
+    GRPC_ERROR_UNREF(err);
+    if (sc != NULL) {
       GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server");
     }
-    if (state) {
-      gpr_free(state);
-    }
   }
-  grpc_exec_ctx_finish(&exec_ctx);
-  const char *msg = grpc_error_string(err);
-  GRPC_ERROR_UNREF(err);
-  gpr_log(GPR_ERROR, "%s", msg);
-  grpc_error_free_string(msg);
-  return 0;
+  return port_num;
 }
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 3e5aa1416fa..d43f93b94fe 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -237,6 +237,7 @@ CORE_SOURCE_FILES = [
   'src/core/lib/tsi/fake_transport_security.c',
   'src/core/lib/tsi/ssl_transport_security.c',
   'src/core/lib/tsi/transport_security.c',
+  'src/core/ext/transport/chttp2/server/chttp2_server.c',
   'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
   'src/core/ext/client_channel/channel_connectivity.c',
   'src/core/ext/client_channel/client_channel.c',
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index ce29f8e43ca..6572bd4ddf9 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -930,6 +930,7 @@ src/core/lib/tsi/ssl_transport_security.h \
 src/core/lib/tsi/ssl_types.h \
 src/core/lib/tsi/transport_security.h \
 src/core/lib/tsi/transport_security_interface.h \
+src/core/ext/transport/chttp2/server/chttp2_server.h \
 src/core/ext/client_channel/client_channel.h \
 src/core/ext/client_channel/client_channel_factory.h \
 src/core/ext/client_channel/connector.h \
@@ -1129,6 +1130,7 @@ src/core/lib/surface/init_secure.c \
 src/core/lib/tsi/fake_transport_security.c \
 src/core/lib/tsi/ssl_transport_security.c \
 src/core/lib/tsi/transport_security.c \
+src/core/ext/transport/chttp2/server/chttp2_server.c \
 src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
 src/core/ext/client_channel/channel_connectivity.c \
 src/core/ext/client_channel/client_channel.c \
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 19b8a8be2a4..2e6877ccac5 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -7491,6 +7491,26 @@
       "grpc_base", 
       "grpc_transport_chttp2"
     ], 
+    "headers": [
+      "src/core/ext/transport/chttp2/server/chttp2_server.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_transport_chttp2_server", 
+    "src": [
+      "src/core/ext/transport/chttp2/server/chttp2_server.c", 
+      "src/core/ext/transport/chttp2/server/chttp2_server.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "grpc_base", 
+      "grpc_transport_chttp2", 
+      "grpc_transport_chttp2_server"
+    ], 
     "headers": [], 
     "is_filegroup": true, 
     "language": "c", 
@@ -7507,7 +7527,8 @@
       "gpr", 
       "grpc_base", 
       "grpc_secure", 
-      "grpc_transport_chttp2"
+      "grpc_transport_chttp2", 
+      "grpc_transport_chttp2_server"
     ], 
     "headers": [], 
     "is_filegroup": true, 
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index fe7e06aa773..558b5b0c66a 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -439,6 +439,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\ssl_types.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\connector.h" />
@@ -803,6 +804,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_channel\channel_connectivity.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 8fce4ceb419..a40a1b5f1c8 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -490,6 +490,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security.c">
       <Filter>src\core\lib\tsi</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
+      <Filter>src\core\ext\transport\chttp2\server</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\secure\secure_channel_create.c">
       <Filter>src\core\ext\transport\chttp2\client\secure</Filter>
     </ClCompile>
@@ -1157,6 +1160,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security_interface.h">
       <Filter>src\core\lib\tsi</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h">
+      <Filter>src\core\ext\transport\chttp2\server</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h">
       <Filter>src\core\ext\client_channel</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 5e5b7246093..661192101c8 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -405,6 +405,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_channel\client_channel_factory.h" />
@@ -719,6 +720,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 4363f8a8681..466116e6043 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -415,6 +415,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.c">
       <Filter>src\core\ext\transport\chttp2\alpn</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.c">
+      <Filter>src\core\ext\transport\chttp2\server</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c">
       <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
     </ClCompile>
@@ -998,6 +1001,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h">
       <Filter>src\core\ext\transport\chttp2\alpn</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\server\chttp2_server.h">
+      <Filter>src\core\ext\transport\chttp2\server</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
     </ClInclude>