|  | @@ -32,6 +32,7 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include "src/core/ext/filters/http/server/http_server_filter.h"
 | 
	
		
			
				|  |  |  #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 | 
	
		
			
				|  |  | +#include "src/core/ext/transport/chttp2/transport/internal.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/channel/channel_args.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/channel/handshaker.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/channel/handshaker_registry.h"
 | 
	
	
		
			
				|  | @@ -54,12 +55,50 @@ typedef struct {
 | 
	
		
			
				|  |  |  } server_state;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct {
 | 
	
		
			
				|  |  | +  gpr_refcount refs;
 | 
	
		
			
				|  |  |    server_state* svr_state;
 | 
	
		
			
				|  |  |    grpc_pollset* accepting_pollset;
 | 
	
		
			
				|  |  |    grpc_tcp_server_acceptor* acceptor;
 | 
	
		
			
				|  |  |    grpc_handshake_manager* handshake_mgr;
 | 
	
		
			
				|  |  | +  // State for enforcing handshake timeout on receiving HTTP/2 settings.
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport* transport;
 | 
	
		
			
				|  |  | +  grpc_millis deadline;
 | 
	
		
			
				|  |  | +  grpc_timer timer;
 | 
	
		
			
				|  |  | +  grpc_closure on_timeout;
 | 
	
		
			
				|  |  | +  grpc_closure on_receive_settings;
 | 
	
		
			
				|  |  |  } server_connection_state;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void server_connection_state_unref(
 | 
	
		
			
				|  |  | +    grpc_exec_ctx* exec_ctx, server_connection_state* connection_state) {
 | 
	
		
			
				|  |  | +  if (gpr_unref(&connection_state->refs)) {
 | 
	
		
			
				|  |  | +    if (connection_state->transport != nullptr) {
 | 
	
		
			
				|  |  | +      GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, connection_state->transport,
 | 
	
		
			
				|  |  | +                                  "receive settings timeout");
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    gpr_free(connection_state);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | +  server_connection_state* connection_state = (server_connection_state*)arg;
 | 
	
		
			
				|  |  | +  if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    grpc_transport_op* op = grpc_make_transport_op(nullptr);
 | 
	
		
			
				|  |  | +    op->disconnect_with_error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | +        "Did not receive HTTP/2 settings before handshake timeout");
 | 
	
		
			
				|  |  | +    grpc_transport_perform_op(exec_ctx, &connection_state->transport->base, op);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  server_connection_state_unref(exec_ctx, connection_state);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void on_receive_settings(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  | +                                grpc_error* error) {
 | 
	
		
			
				|  |  | +  server_connection_state* connection_state = (server_connection_state*)arg;
 | 
	
		
			
				|  |  | +  if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    grpc_timer_cancel(exec_ctx, &connection_state->timer);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  server_connection_state_unref(exec_ctx, connection_state);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void on_handshake_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_handshaker_args* args = (grpc_handshaker_args*)arg;
 | 
	
	
		
			
				|  | @@ -69,7 +108,6 @@ static void on_handshake_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE || connection_state->svr_state->shutdown) {
 | 
	
		
			
				|  |  |      const char* error_str = grpc_error_string(error);
 | 
	
		
			
				|  |  |      gpr_log(GPR_DEBUG, "Handshaking failed: %s", error_str);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      if (error == GRPC_ERROR_NONE && args->endpoint != NULL) {
 | 
	
		
			
				|  |  |        // We were shut down after handshaking completed successfully, so
 | 
	
		
			
				|  |  |        // destroy the endpoint here.
 | 
	
	
		
			
				|  | @@ -93,11 +131,25 @@ static void on_handshake_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |        grpc_server_setup_transport(
 | 
	
		
			
				|  |  |            exec_ctx, connection_state->svr_state->server, transport,
 | 
	
		
			
				|  |  |            connection_state->accepting_pollset, args->args);
 | 
	
		
			
				|  |  | -// FIXME: set notify_on_receive_settings callback and use it to enforce
 | 
	
		
			
				|  |  | -// handshaking deadline
 | 
	
		
			
				|  |  | -      grpc_chttp2_transport_start_reading(exec_ctx, transport,
 | 
	
		
			
				|  |  | -                                          args->read_buffer, nullptr);
 | 
	
		
			
				|  |  | +      // Use notify_on_receive_settings callback to enforce the
 | 
	
		
			
				|  |  | +      // handshake deadline.
 | 
	
		
			
				|  |  | +      connection_state->transport = (grpc_chttp2_transport*)transport;
 | 
	
		
			
				|  |  | +      gpr_ref(&connection_state->refs);
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&connection_state->on_receive_settings,
 | 
	
		
			
				|  |  | +                        on_receive_settings, connection_state,
 | 
	
		
			
				|  |  | +                        grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  | +      grpc_chttp2_transport_start_reading(
 | 
	
		
			
				|  |  | +          exec_ctx, transport, args->read_buffer,
 | 
	
		
			
				|  |  | +          &connection_state->on_receive_settings);
 | 
	
		
			
				|  |  |        grpc_channel_args_destroy(exec_ctx, args->args);
 | 
	
		
			
				|  |  | +      gpr_ref(&connection_state->refs);
 | 
	
		
			
				|  |  | +      GRPC_CHTTP2_REF_TRANSPORT((grpc_chttp2_transport*)transport,
 | 
	
		
			
				|  |  | +                                "receive settings timeout");
 | 
	
		
			
				|  |  | +      GRPC_CLOSURE_INIT(&connection_state->on_timeout, on_timeout,
 | 
	
		
			
				|  |  | +                        connection_state, grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  | +      grpc_timer_init(exec_ctx, &connection_state->timer,
 | 
	
		
			
				|  |  | +                      connection_state->deadline,
 | 
	
		
			
				|  |  | +                      &connection_state->on_timeout);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    grpc_handshake_manager_pending_list_remove(
 | 
	
	
		
			
				|  | @@ -105,9 +157,9 @@ static void on_handshake_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |        connection_state->handshake_mgr);
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&connection_state->svr_state->mu);
 | 
	
		
			
				|  |  |    grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
 | 
	
		
			
				|  |  | -  grpc_tcp_server_unref(exec_ctx, connection_state->svr_state->tcp_server);
 | 
	
		
			
				|  |  |    gpr_free(connection_state->acceptor);
 | 
	
		
			
				|  |  | -  gpr_free(connection_state);
 | 
	
		
			
				|  |  | +  grpc_tcp_server_unref(exec_ctx, connection_state->svr_state->tcp_server);
 | 
	
		
			
				|  |  | +  server_connection_state_unref(exec_ctx, connection_state);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void on_accept(grpc_exec_ctx* exec_ctx, void* arg, grpc_endpoint* tcp,
 | 
	
	
		
			
				|  | @@ -128,7 +180,8 @@ static void on_accept(grpc_exec_ctx* exec_ctx, void* arg, grpc_endpoint* tcp,
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&state->mu);
 | 
	
		
			
				|  |  |    grpc_tcp_server_ref(state->tcp_server);
 | 
	
		
			
				|  |  |    server_connection_state* connection_state =
 | 
	
		
			
				|  |  | -      (server_connection_state*)gpr_malloc(sizeof(*connection_state));
 | 
	
		
			
				|  |  | +      (server_connection_state*)gpr_zalloc(sizeof(*connection_state));
 | 
	
		
			
				|  |  | +  gpr_ref_init(&connection_state->refs, 1);
 | 
	
		
			
				|  |  |    connection_state->svr_state = state;
 | 
	
		
			
				|  |  |    connection_state->accepting_pollset = accepting_pollset;
 | 
	
		
			
				|  |  |    connection_state->acceptor = acceptor;
 | 
	
	
		
			
				|  | @@ -137,12 +190,13 @@ static void on_accept(grpc_exec_ctx* exec_ctx, void* arg, grpc_endpoint* tcp,
 | 
	
		
			
				|  |  |                         connection_state->handshake_mgr);
 | 
	
		
			
				|  |  |    const grpc_arg* timeout_arg =
 | 
	
		
			
				|  |  |        grpc_channel_args_find(state->args, GRPC_ARG_SERVER_HANDSHAKE_TIMEOUT_MS);
 | 
	
		
			
				|  |  | -  const grpc_millis deadline =
 | 
	
		
			
				|  |  | +  connection_state->deadline =
 | 
	
		
			
				|  |  |        grpc_exec_ctx_now(exec_ctx) +
 | 
	
		
			
				|  |  |        grpc_channel_arg_get_integer(timeout_arg,
 | 
	
		
			
				|  |  |                                     {120 * GPR_MS_PER_SEC, 1, INT_MAX});
 | 
	
		
			
				|  |  |    grpc_handshake_manager_do_handshake(exec_ctx, connection_state->handshake_mgr,
 | 
	
		
			
				|  |  | -                                      tcp, state->args, deadline, acceptor,
 | 
	
		
			
				|  |  | +                                      tcp, state->args,
 | 
	
		
			
				|  |  | +                                      connection_state->deadline, acceptor,
 | 
	
		
			
				|  |  |                                        on_handshake_done, connection_state);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |