|  | @@ -152,10 +152,14 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |                                grpc_error *error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                     grpc_chttp2_transport *t);
 | 
	
		
			
				|  |  |  static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
 | 
	
		
			
				|  |  |                                    grpc_error *error);
 | 
	
		
			
				|  |  |  static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
 | 
	
		
			
				|  |  |                                     grpc_error *error);
 | 
	
		
			
				|  |  | +static void next_bdp_ping_timer_expired_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                               void *tp, grpc_error *error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |                           grpc_error *error);
 | 
	
	
		
			
				|  | @@ -220,6 +224,7 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    t->flow_control.bdp_estimator.Destroy();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(t->closed_with_error);
 | 
	
		
			
				|  |  |    gpr_free(t->ping_acks);
 | 
	
		
			
				|  |  |    gpr_free(t->peer_string);
 | 
	
		
			
				|  |  |    gpr_free(t);
 | 
	
	
		
			
				|  | @@ -305,6 +310,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |                      grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_INIT(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t,
 | 
	
		
			
				|  |  |                      grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  | +  GRPC_CLOSURE_INIT(&t->next_bdp_ping_timer_expired_locked,
 | 
	
		
			
				|  |  | +                    next_bdp_ping_timer_expired_locked, t,
 | 
	
		
			
				|  |  | +                    grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_INIT(&t->init_keepalive_ping_locked, init_keepalive_ping_locked,
 | 
	
		
			
				|  |  |                      t, grpc_combiner_scheduler(t->combiner));
 | 
	
		
			
				|  |  |    GRPC_CLOSURE_INIT(&t->start_keepalive_ping_locked,
 | 
	
	
		
			
				|  | @@ -564,6 +572,11 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |      t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DISABLED;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  if (t->flow_control.enable_bdp_probe) {
 | 
	
		
			
				|  |  | +    GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
 | 
	
		
			
				|  |  | +    schedule_bdp_ping_locked(exec_ctx, t);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    grpc_chttp2_act_on_flowctl_action(
 | 
	
		
			
				|  |  |        exec_ctx,
 | 
	
		
			
				|  |  |        grpc_chttp2_flowctl_get_action(exec_ctx, &t->flow_control, NULL), t,
 | 
	
	
		
			
				|  | @@ -597,7 +610,9 @@ static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
 | 
	
		
			
				|  |  |  static void close_transport_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                     grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |                                     grpc_error *error) {
 | 
	
		
			
				|  |  | -  if (!t->closed) {
 | 
	
		
			
				|  |  | +  end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  if (t->closed_with_error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      if (!grpc_error_has_clear_grpc_status(error)) {
 | 
	
		
			
				|  |  |        error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
 | 
	
		
			
				|  |  |                                   GRPC_STATUS_UNAVAILABLE);
 | 
	
	
		
			
				|  | @@ -612,13 +627,16 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |            grpc_error_add_child(t->close_transport_on_writes_finished, error);
 | 
	
		
			
				|  |  |        return;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    t->closed = 1;
 | 
	
		
			
				|  |  | +    GPR_ASSERT(error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | +    t->closed_with_error = GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  |      connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN,
 | 
	
		
			
				|  |  |                             GRPC_ERROR_REF(error), "close_transport");
 | 
	
		
			
				|  |  | -    grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |      if (t->ping_state.is_delayed_ping_timer_set) {
 | 
	
		
			
				|  |  |        grpc_timer_cancel(exec_ctx, &t->ping_state.delayed_ping_timer);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    if (t->have_next_bdp_ping_timer) {
 | 
	
		
			
				|  |  | +      grpc_timer_cancel(exec_ctx, &t->next_bdp_ping_timer);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      switch (t->keepalive_state) {
 | 
	
		
			
				|  |  |        case GRPC_CHTTP2_KEEPALIVE_STATE_WAITING:
 | 
	
		
			
				|  |  |          grpc_timer_cancel(exec_ctx, &t->keepalive_ping_timer);
 | 
	
	
		
			
				|  | @@ -638,8 +656,8 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |      while (grpc_chttp2_list_pop_writable_stream(t, &s)) {
 | 
	
		
			
				|  |  |        GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | -    cancel_pings(exec_ctx, t, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    GPR_ASSERT(t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE);
 | 
	
		
			
				|  |  | +    grpc_endpoint_shutdown(exec_ctx, t->ep, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -942,7 +960,8 @@ void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  void grpc_chttp2_mark_stream_writable(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                        grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |                                        grpc_chttp2_stream *s) {
 | 
	
		
			
				|  |  | -  if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) {
 | 
	
		
			
				|  |  | +  if (t->closed_with_error == GRPC_ERROR_NONE &&
 | 
	
		
			
				|  |  | +      grpc_chttp2_list_add_writable_stream(t, s)) {
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -995,7 +1014,7 @@ static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt,
 | 
	
		
			
				|  |  |    grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
 | 
	
		
			
				|  |  |    GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE);
 | 
	
		
			
				|  |  |    grpc_chttp2_begin_write_result r;
 | 
	
		
			
				|  |  | -  if (t->closed) {
 | 
	
		
			
				|  |  | +  if (t->closed_with_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      r.writing = false;
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      r = grpc_chttp2_begin_write(exec_ctx, t);
 | 
	
	
		
			
				|  | @@ -1458,7 +1477,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        if (!s->write_closed) {
 | 
	
		
			
				|  |  |          if (t->is_client) {
 | 
	
		
			
				|  |  | -          if (!t->closed) {
 | 
	
		
			
				|  |  | +          if (t->closed_with_error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |              GPR_ASSERT(s->id == 0);
 | 
	
		
			
				|  |  |              grpc_chttp2_list_add_waiting_for_concurrency(t, s);
 | 
	
		
			
				|  |  |              maybe_start_some_streams(exec_ctx, t);
 | 
	
	
		
			
				|  | @@ -1466,7 +1485,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
 | 
	
		
			
				|  |  |              grpc_chttp2_cancel_stream(
 | 
	
		
			
				|  |  |                  exec_ctx, t, s,
 | 
	
		
			
				|  |  |                  grpc_error_set_int(
 | 
	
		
			
				|  |  | -                    GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"),
 | 
	
		
			
				|  |  | +                    GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | +                        "Transport closed", &t->closed_with_error, 1),
 | 
	
		
			
				|  |  |                      GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |          } else {
 | 
	
	
		
			
				|  | @@ -1688,6 +1708,7 @@ static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |    /* callback remaining pings: they're not allowed to call into the transpot,
 | 
	
		
			
				|  |  |       and maybe they hold resources that need to be freed */
 | 
	
		
			
				|  |  |    grpc_chttp2_ping_queue *pq = &t->ping_queue;
 | 
	
		
			
				|  |  | +  GPR_ASSERT(error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |    for (size_t j = 0; j < GRPC_CHTTP2_PCL_COUNT; j++) {
 | 
	
		
			
				|  |  |      grpc_closure_list_fail_all(&pq->lists[j], GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |      GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[j]);
 | 
	
	
		
			
				|  | @@ -1697,6 +1718,12 @@ static void cancel_pings(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |                               grpc_closure *on_initiate, grpc_closure *on_ack) {
 | 
	
		
			
				|  |  | +  if (t->closed_with_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    GRPC_CLOSURE_SCHED(exec_ctx, on_initiate,
 | 
	
		
			
				|  |  | +                       GRPC_ERROR_REF(t->closed_with_error));
 | 
	
		
			
				|  |  | +    GRPC_CLOSURE_SCHED(exec_ctx, on_ack, GRPC_ERROR_REF(t->closed_with_error));
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    grpc_chttp2_ping_queue *pq = &t->ping_queue;
 | 
	
		
			
				|  |  |    grpc_closure_list_append(&pq->lists[GRPC_CHTTP2_PCL_INITIATE], on_initiate,
 | 
	
		
			
				|  |  |                             GRPC_ERROR_NONE);
 | 
	
	
		
			
				|  | @@ -1755,7 +1782,9 @@ void grpc_chttp2_add_ping_strike(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                      GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
 | 
	
		
			
				|  |  |      /*The transport will be closed after the write is done */
 | 
	
		
			
				|  |  |      close_transport_locked(
 | 
	
		
			
				|  |  | -        exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"));
 | 
	
		
			
				|  |  | +        exec_ctx, t, grpc_error_set_int(
 | 
	
		
			
				|  |  | +                         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Too many pings"),
 | 
	
		
			
				|  |  | +                         GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2434,12 +2463,6 @@ void grpc_chttp2_act_on_flowctl_action(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                   GRPC_CHTTP2_INITIATE_WRITE_SEND_SETTINGS);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  if (action.need_ping) {
 | 
	
		
			
				|  |  | -    GRPC_CHTTP2_REF_TRANSPORT(t, "bdp_ping");
 | 
	
		
			
				|  |  | -    t->flow_control.bdp_estimator->SchedulePing();
 | 
	
		
			
				|  |  | -    send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked,
 | 
	
		
			
				|  |  | -                     &t->finish_bdp_ping_locked);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
 | 
	
	
		
			
				|  | @@ -2489,7 +2512,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    GPR_SWAP(grpc_error *, err, error);
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(err);
 | 
	
		
			
				|  |  | -  if (!t->closed) {
 | 
	
		
			
				|  |  | +  if (t->closed_with_error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      GPR_TIMER_BEGIN("reading_action.parse", 0);
 | 
	
		
			
				|  |  |      size_t i = 0;
 | 
	
		
			
				|  |  |      grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
 | 
	
	
		
			
				|  | @@ -2529,13 +2552,14 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GPR_TIMER_BEGIN("post_reading_action_locked", 0);
 | 
	
		
			
				|  |  |    bool keep_reading = false;
 | 
	
		
			
				|  |  | -  if (error == GRPC_ERROR_NONE && t->closed) {
 | 
	
		
			
				|  |  | -    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed");
 | 
	
		
			
				|  |  | +  if (error == GRPC_ERROR_NONE && t->closed_with_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | +        "Transport closed", &t->closed_with_error, 1);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |      t->endpoint_reading = 0;
 | 
	
		
			
				|  |  | -  } else if (!t->closed) {
 | 
	
		
			
				|  |  | +  } else if (t->closed_with_error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      keep_reading = true;
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading");
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -2560,11 +2584,21 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
 | 
	
		
			
				|  |  |    GPR_TIMER_END("reading_action_locked", 0);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// t is reffed prior to calling the first time, and once the callback chain
 | 
	
		
			
				|  |  | +// that kicks off finishes, it's unreffed
 | 
	
		
			
				|  |  | +static void schedule_bdp_ping_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                     grpc_chttp2_transport *t) {
 | 
	
		
			
				|  |  | +  t->flow_control.bdp_estimator->SchedulePing();
 | 
	
		
			
				|  |  | +  send_ping_locked(exec_ctx, t, &t->start_bdp_ping_locked,
 | 
	
		
			
				|  |  | +                   &t->finish_bdp_ping_locked);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void start_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
 | 
	
		
			
				|  |  |                                    grpc_error *error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
 | 
	
		
			
				|  |  |    if (GRPC_TRACER_ON(grpc_http_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_DEBUG, "%s: Start BDP ping", t->peer_string);
 | 
	
		
			
				|  |  | +    gpr_log(GPR_DEBUG, "%s: Start BDP ping err=%s", t->peer_string,
 | 
	
		
			
				|  |  | +            grpc_error_string(error));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    /* Reset the keepalive ping timer */
 | 
	
		
			
				|  |  |    if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING) {
 | 
	
	
		
			
				|  | @@ -2577,11 +2611,30 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
 | 
	
		
			
				|  |  |                                     grpc_error *error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
 | 
	
		
			
				|  |  |    if (GRPC_TRACER_ON(grpc_http_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_DEBUG, "%s: Complete BDP ping", t->peer_string);
 | 
	
		
			
				|  |  | +    gpr_log(GPR_DEBUG, "%s: Complete BDP ping err=%s", t->peer_string,
 | 
	
		
			
				|  |  | +            grpc_error_string(error));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  t->flow_control.bdp_estimator->CompletePing(exec_ctx);
 | 
	
		
			
				|  |  | +  if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  grpc_millis next_ping = t->flow_control.bdp_estimator->CompletePing(exec_ctx);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(!t->have_next_bdp_ping_timer);
 | 
	
		
			
				|  |  | +  t->have_next_bdp_ping_timer = true;
 | 
	
		
			
				|  |  | +  grpc_timer_init(exec_ctx, &t->next_bdp_ping_timer, next_ping,
 | 
	
		
			
				|  |  | +                  &t->next_bdp_ping_timer_expired_locked);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
 | 
	
		
			
				|  |  | +static void next_bdp_ping_timer_expired_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                               void *tp, grpc_error *error) {
 | 
	
		
			
				|  |  | +  grpc_chttp2_transport *t = (grpc_chttp2_transport *)tp;
 | 
	
		
			
				|  |  | +  GPR_ASSERT(t->have_next_bdp_ping_timer);
 | 
	
		
			
				|  |  | +  t->have_next_bdp_ping_timer = false;
 | 
	
		
			
				|  |  | +  if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping");
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  schedule_bdp_ping_locked(exec_ctx, t);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args,
 | 
	
	
		
			
				|  | @@ -2646,7 +2699,7 @@ static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |                                         grpc_error *error) {
 | 
	
		
			
				|  |  |    grpc_chttp2_transport *t = (grpc_chttp2_transport *)arg;
 | 
	
		
			
				|  |  |    GPR_ASSERT(t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_WAITING);
 | 
	
		
			
				|  |  | -  if (t->destroying || t->closed) {
 | 
	
		
			
				|  |  | +  if (t->destroying || t->closed_with_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
 | 
	
		
			
				|  |  |    } else if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      if (t->keepalive_permit_without_calls ||
 | 
	
	
		
			
				|  | @@ -2704,8 +2757,11 @@ static void keepalive_watchdog_fired_locked(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |    if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) {
 | 
	
		
			
				|  |  |      if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |        t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_DYING;
 | 
	
		
			
				|  |  | -      close_transport_locked(exec_ctx, t, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -                                              "keepalive watchdog timeout"));
 | 
	
		
			
				|  |  | +      close_transport_locked(
 | 
	
		
			
				|  |  | +          exec_ctx, t,
 | 
	
		
			
				|  |  | +          grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | +                                 "keepalive watchdog timeout"),
 | 
	
		
			
				|  |  | +                             GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_INTERNAL));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      /* The watchdog timer should have been cancelled by
 |