blob: dda3b61108bd07e0de574954ae2be5c4f38b463e [file] [log] [blame]
Mark D. Roth14c072c2016-08-26 08:31:34 -07001//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02002// Copyright 2016 gRPC authors.
Mark D. Roth14c072c2016-08-26 08:31:34 -07003//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02004// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
Mark D. Roth14c072c2016-08-26 08:31:34 -07007//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02008// http://www.apache.org/licenses/LICENSE-2.0
Mark D. Roth14c072c2016-08-26 08:31:34 -07009//
Jan Tattermusch7897ae92017-06-07 22:57:36 +020010// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
Mark D. Roth14c072c2016-08-26 08:31:34 -070015//
16
Alexander Polcyndb3e8982018-02-21 16:59:24 -080017#include <grpc/support/port_platform.h>
18
Craig Tiller3be7dd02017-04-03 14:30:03 -070019#include "src/core/ext/filters/deadline/deadline_filter.h"
Mark D. Roth14c072c2016-08-26 08:31:34 -070020
21#include <stdbool.h>
22#include <string.h>
23
Mark D. Rothf28763c2016-09-14 15:18:40 -070024#include <grpc/support/alloc.h>
Mark D. Roth14c072c2016-08-26 08:31:34 -070025#include <grpc/support/log.h>
Mark D. Roth1bbe6cb2016-08-31 08:33:37 -070026#include <grpc/support/sync.h>
Mark D. Roth14c072c2016-08-26 08:31:34 -070027#include <grpc/support/time.h>
28
Craig Tiller3be7dd02017-04-03 14:30:03 -070029#include "src/core/lib/channel/channel_stack_builder.h"
Mark D. Rothf28763c2016-09-14 15:18:40 -070030#include "src/core/lib/iomgr/exec_ctx.h"
Mark D. Roth14c072c2016-08-26 08:31:34 -070031#include "src/core/lib/iomgr/timer.h"
Craig Tillera59c16c2016-10-31 07:25:01 -070032#include "src/core/lib/slice/slice_internal.h"
Craig Tiller3be7dd02017-04-03 14:30:03 -070033#include "src/core/lib/surface/channel_init.h"
Mark D. Roth14c072c2016-08-26 08:31:34 -070034
Mark D. Roth72f6da82016-09-02 13:42:38 -070035//
36// grpc_deadline_state
37//
38
Mark D. Roth76e264b2017-08-25 09:03:33 -070039// The on_complete callback used when sending a cancel_error batch down the
40// filter stack. Yields the call combiner when the batch returns.
Yash Tibrewal8cf14702017-12-06 09:47:54 -080041static void yield_call_combiner(void* arg, grpc_error* ignored) {
Noah Eisenbe82e642018-02-09 09:16:55 -080042 grpc_deadline_state* deadline_state = static_cast<grpc_deadline_state*>(arg);
Yash Tibrewal8cf14702017-12-06 09:47:54 -080043 GRPC_CALL_COMBINER_STOP(deadline_state->call_combiner,
Mark D. Roth76e264b2017-08-25 09:03:33 -070044 "got on_complete from cancel_stream batch");
Yash Tibrewal8cf14702017-12-06 09:47:54 -080045 GRPC_CALL_STACK_UNREF(deadline_state->call_stack, "deadline_timer");
Mark D. Roth76e264b2017-08-25 09:03:33 -070046}
47
48// This is called via the call combiner, so access to deadline_state is
49// synchronized.
Yash Tibrewal8cf14702017-12-06 09:47:54 -080050static void send_cancel_op_in_call_combiner(void* arg, grpc_error* error) {
Noah Eisenbe82e642018-02-09 09:16:55 -080051 grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
Noah Eisen4d20a662018-02-09 09:34:04 -080052 grpc_deadline_state* deadline_state =
53 static_cast<grpc_deadline_state*>(elem->call_data);
Mark D. Roth76e264b2017-08-25 09:03:33 -070054 grpc_transport_stream_op_batch* batch = grpc_make_transport_stream_op(
55 GRPC_CLOSURE_INIT(&deadline_state->timer_callback, yield_call_combiner,
56 deadline_state, grpc_schedule_on_exec_ctx));
57 batch->cancel_stream = true;
58 batch->payload->cancel_stream.cancel_error = GRPC_ERROR_REF(error);
Yash Tibrewal8cf14702017-12-06 09:47:54 -080059 elem->filter->start_transport_stream_op_batch(elem, batch);
Mark D. Roth76e264b2017-08-25 09:03:33 -070060}
61
Mark D. Roth72f6da82016-09-02 13:42:38 -070062// Timer callback.
Yash Tibrewal8cf14702017-12-06 09:47:54 -080063static void timer_callback(void* arg, grpc_error* error) {
Noah Eisenbe82e642018-02-09 09:16:55 -080064 grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
Noah Eisen4d20a662018-02-09 09:34:04 -080065 grpc_deadline_state* deadline_state =
66 static_cast<grpc_deadline_state*>(elem->call_data);
Mark D. Roth72f6da82016-09-02 13:42:38 -070067 if (error != GRPC_ERROR_CANCELLED) {
Mark D. Roth76e264b2017-08-25 09:03:33 -070068 error = grpc_error_set_int(
69 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Deadline Exceeded"),
70 GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_DEADLINE_EXCEEDED);
Yash Tibrewal8cf14702017-12-06 09:47:54 -080071 grpc_call_combiner_cancel(deadline_state->call_combiner,
Mark D. Roth76e264b2017-08-25 09:03:33 -070072 GRPC_ERROR_REF(error));
73 GRPC_CLOSURE_INIT(&deadline_state->timer_callback,
74 send_cancel_op_in_call_combiner, elem,
75 grpc_schedule_on_exec_ctx);
Yash Tibrewal8cf14702017-12-06 09:47:54 -080076 GRPC_CALL_COMBINER_START(deadline_state->call_combiner,
Mark D. Roth76e264b2017-08-25 09:03:33 -070077 &deadline_state->timer_callback, error,
78 "deadline exceeded -- sending cancel_stream op");
79 } else {
Yash Tibrewal8cf14702017-12-06 09:47:54 -080080 GRPC_CALL_STACK_UNREF(deadline_state->call_stack, "deadline_timer");
Mark D. Roth72f6da82016-09-02 13:42:38 -070081 }
Mark D. Roth72f6da82016-09-02 13:42:38 -070082}
83
84// Starts the deadline timer.
Mark D. Roth76e264b2017-08-25 09:03:33 -070085// This is called via the call combiner, so access to deadline_state is
86// synchronized.
Yash Tibrewal8cf14702017-12-06 09:47:54 -080087static void start_timer_if_needed(grpc_call_element* elem,
Craig Tiller89c14282017-07-19 15:32:27 -070088 grpc_millis deadline) {
89 if (deadline == GRPC_MILLIS_INF_FUTURE) {
Craig Tiller4447c2c2017-02-16 12:35:13 -080090 return;
91 }
Noah Eisen4d20a662018-02-09 09:34:04 -080092 grpc_deadline_state* deadline_state =
93 static_cast<grpc_deadline_state*>(elem->call_data);
Craig Tiller4782d922017-11-10 09:53:21 -080094 grpc_closure* closure = nullptr;
Mark D. Roth76e264b2017-08-25 09:03:33 -070095 switch (deadline_state->timer_state) {
Craig Tillerc84886b2017-02-16 13:10:38 -080096 case GRPC_DEADLINE_STATE_PENDING:
Craig Tillerac942f42017-02-22 09:13:14 -080097 // Note: We do not start the timer if there is already a timer
Craig Tillerc84886b2017-02-16 13:10:38 -080098 return;
99 case GRPC_DEADLINE_STATE_FINISHED:
Mark D. Roth76e264b2017-08-25 09:03:33 -0700100 deadline_state->timer_state = GRPC_DEADLINE_STATE_PENDING;
101 // If we've already created and destroyed a timer, we always create a
102 // new closure: we have no other guarantee that the inlined closure is
103 // not in use (it may hold a pending call to timer_callback)
104 closure =
105 GRPC_CLOSURE_CREATE(timer_callback, elem, grpc_schedule_on_exec_ctx);
Craig Tillerc84886b2017-02-16 13:10:38 -0800106 break;
107 case GRPC_DEADLINE_STATE_INITIAL:
Mark D. Roth76e264b2017-08-25 09:03:33 -0700108 deadline_state->timer_state = GRPC_DEADLINE_STATE_PENDING;
109 closure =
110 GRPC_CLOSURE_INIT(&deadline_state->timer_callback, timer_callback,
111 elem, grpc_schedule_on_exec_ctx);
Craig Tillerc84886b2017-02-16 13:10:38 -0800112 break;
Craig Tiller4447c2c2017-02-16 12:35:13 -0800113 }
Craig Tiller4782d922017-11-10 09:53:21 -0800114 GPR_ASSERT(closure != nullptr);
Craig Tillerac942f42017-02-22 09:13:14 -0800115 GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer");
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800116 grpc_timer_init(&deadline_state->timer, deadline, closure);
Mark D. Roth72f6da82016-09-02 13:42:38 -0700117}
118
119// Cancels the deadline timer.
Mark D. Roth76e264b2017-08-25 09:03:33 -0700120// This is called via the call combiner, so access to deadline_state is
121// synchronized.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800122static void cancel_timer_if_needed(grpc_deadline_state* deadline_state) {
Mark D. Roth76e264b2017-08-25 09:03:33 -0700123 if (deadline_state->timer_state == GRPC_DEADLINE_STATE_PENDING) {
124 deadline_state->timer_state = GRPC_DEADLINE_STATE_FINISHED;
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800125 grpc_timer_cancel(&deadline_state->timer);
Craig Tillerac942f42017-02-22 09:13:14 -0800126 } else {
127 // timer was either in STATE_INITAL (nothing to cancel)
128 // OR in STATE_FINISHED (again nothing to cancel)
Craig Tiller4447c2c2017-02-16 12:35:13 -0800129 }
Mark D. Roth72f6da82016-09-02 13:42:38 -0700130}
131
132// Callback run when the call is complete.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800133static void on_complete(void* arg, grpc_error* error) {
Noah Eisenbe82e642018-02-09 09:16:55 -0800134 grpc_deadline_state* deadline_state = static_cast<grpc_deadline_state*>(arg);
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800135 cancel_timer_if_needed(deadline_state);
Mark D. Roth72f6da82016-09-02 13:42:38 -0700136 // Invoke the next callback.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800137 GRPC_CLOSURE_RUN(deadline_state->next_on_complete, GRPC_ERROR_REF(error));
Mark D. Roth72f6da82016-09-02 13:42:38 -0700138}
139
140// Inject our own on_complete callback into op.
141static void inject_on_complete_cb(grpc_deadline_state* deadline_state,
Craig Tillera0f3abd2017-03-31 15:42:16 -0700142 grpc_transport_stream_op_batch* op) {
Mark D. Roth72f6da82016-09-02 13:42:38 -0700143 deadline_state->next_on_complete = op->on_complete;
ncteisen274bbbe2017-06-08 14:57:11 -0700144 GRPC_CLOSURE_INIT(&deadline_state->on_complete, on_complete, deadline_state,
Craig Tiller91031da2016-12-28 15:44:25 -0800145 grpc_schedule_on_exec_ctx);
Mark D. Roth72f6da82016-09-02 13:42:38 -0700146 op->on_complete = &deadline_state->on_complete;
147}
148
Mark D. Rothf28763c2016-09-14 15:18:40 -0700149// Callback and associated state for starting the timer after call stack
150// initialization has been completed.
151struct start_timer_after_init_state {
Mark D. Roth76e264b2017-08-25 09:03:33 -0700152 bool in_call_combiner;
Mark D. Rothf28763c2016-09-14 15:18:40 -0700153 grpc_call_element* elem;
Craig Tiller89c14282017-07-19 15:32:27 -0700154 grpc_millis deadline;
Mark D. Rothf28763c2016-09-14 15:18:40 -0700155 grpc_closure closure;
156};
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800157static void start_timer_after_init(void* arg, grpc_error* error) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700158 struct start_timer_after_init_state* state =
Noah Eisenbe82e642018-02-09 09:16:55 -0800159 static_cast<struct start_timer_after_init_state*>(arg);
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700160 grpc_deadline_state* deadline_state =
Noah Eisenbe82e642018-02-09 09:16:55 -0800161 static_cast<grpc_deadline_state*>(state->elem->call_data);
Mark D. Roth76e264b2017-08-25 09:03:33 -0700162 if (!state->in_call_combiner) {
163 // We are initially called without holding the call combiner, so we
164 // need to bounce ourselves into it.
165 state->in_call_combiner = true;
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800166 GRPC_CALL_COMBINER_START(deadline_state->call_combiner, &state->closure,
167 GRPC_ERROR_REF(error),
Mark D. Roth76e264b2017-08-25 09:03:33 -0700168 "scheduling deadline timer");
169 return;
170 }
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800171 start_timer_if_needed(state->elem, state->deadline);
Mark D. Rothf28763c2016-09-14 15:18:40 -0700172 gpr_free(state);
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800173 GRPC_CALL_COMBINER_STOP(deadline_state->call_combiner,
Mark D. Roth76e264b2017-08-25 09:03:33 -0700174 "done scheduling deadline timer");
Mark D. Rothf28763c2016-09-14 15:18:40 -0700175}
176
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800177void grpc_deadline_state_init(grpc_call_element* elem,
Craig Tiller71d6ce62017-04-06 09:10:09 -0700178 grpc_call_stack* call_stack,
Mark D. Roth76e264b2017-08-25 09:03:33 -0700179 grpc_call_combiner* call_combiner,
Craig Tiller89c14282017-07-19 15:32:27 -0700180 grpc_millis deadline) {
Noah Eisen4d20a662018-02-09 09:34:04 -0800181 grpc_deadline_state* deadline_state =
182 static_cast<grpc_deadline_state*>(elem->call_data);
Craig Tiller71d6ce62017-04-06 09:10:09 -0700183 deadline_state->call_stack = call_stack;
Mark D. Roth76e264b2017-08-25 09:03:33 -0700184 deadline_state->call_combiner = call_combiner;
Mark D. Rothf28763c2016-09-14 15:18:40 -0700185 // Deadline will always be infinite on servers, so the timer will only be
186 // set on clients with a finite deadline.
Craig Tiller89c14282017-07-19 15:32:27 -0700187 if (deadline != GRPC_MILLIS_INF_FUTURE) {
Mark D. Rothf28763c2016-09-14 15:18:40 -0700188 // When the deadline passes, we indicate the failure by sending down
189 // an op with cancel_error set. However, we can't send down any ops
190 // until after the call stack is fully initialized. If we start the
191 // timer here, we have no guarantee that the timer won't pop before
192 // call stack initialization is finished. To avoid that problem, we
193 // create a closure to start the timer, and we schedule that closure
194 // to be run after call stack initialization is done.
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700195 struct start_timer_after_init_state* state =
Noah Eisen4d20a662018-02-09 09:34:04 -0800196 static_cast<struct start_timer_after_init_state*>(
197 gpr_zalloc(sizeof(*state)));
Mark D. Rothf28763c2016-09-14 15:18:40 -0700198 state->elem = elem;
199 state->deadline = deadline;
ncteisen274bbbe2017-06-08 14:57:11 -0700200 GRPC_CLOSURE_INIT(&state->closure, start_timer_after_init, state,
Craig Tiller91031da2016-12-28 15:44:25 -0800201 grpc_schedule_on_exec_ctx);
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800202 GRPC_CLOSURE_SCHED(&state->closure, GRPC_ERROR_NONE);
Mark D. Rothf28763c2016-09-14 15:18:40 -0700203 }
Mark D. Roth72f6da82016-09-02 13:42:38 -0700204}
205
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800206void grpc_deadline_state_destroy(grpc_call_element* elem) {
Noah Eisen4d20a662018-02-09 09:34:04 -0800207 grpc_deadline_state* deadline_state =
208 static_cast<grpc_deadline_state*>(elem->call_data);
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800209 cancel_timer_if_needed(deadline_state);
Craig Tiller71d6ce62017-04-06 09:10:09 -0700210}
211
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800212void grpc_deadline_state_reset(grpc_call_element* elem,
Craig Tiller89c14282017-07-19 15:32:27 -0700213 grpc_millis new_deadline) {
Noah Eisen4d20a662018-02-09 09:34:04 -0800214 grpc_deadline_state* deadline_state =
215 static_cast<grpc_deadline_state*>(elem->call_data);
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800216 cancel_timer_if_needed(deadline_state);
217 start_timer_if_needed(elem, new_deadline);
Mark D. Roth72f6da82016-09-02 13:42:38 -0700218}
219
Craig Tillera0f3abd2017-03-31 15:42:16 -0700220void grpc_deadline_state_client_start_transport_stream_op_batch(
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800221 grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
Noah Eisen4d20a662018-02-09 09:34:04 -0800222 grpc_deadline_state* deadline_state =
223 static_cast<grpc_deadline_state*>(elem->call_data);
Craig Tiller759965c2017-03-02 08:50:18 -0800224 if (op->cancel_stream) {
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800225 cancel_timer_if_needed(deadline_state);
Mark D. Roth72f6da82016-09-02 13:42:38 -0700226 } else {
Mark D. Roth72f6da82016-09-02 13:42:38 -0700227 // Make sure we know when the call is complete, so that we can cancel
228 // the timer.
Craig Tiller759965c2017-03-02 08:50:18 -0800229 if (op->recv_trailing_metadata) {
Mark D. Roth72f6da82016-09-02 13:42:38 -0700230 inject_on_complete_cb(deadline_state, op);
231 }
232 }
233}
234
235//
236// filter code
237//
238
Mark D. Roth72f6da82016-09-02 13:42:38 -0700239// Constructor for channel_data. Used for both client and server filters.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800240static grpc_error* init_channel_elem(grpc_channel_element* elem,
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800241 grpc_channel_element_args* args) {
Mark D. Roth72f6da82016-09-02 13:42:38 -0700242 GPR_ASSERT(!args->is_last);
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800243 return GRPC_ERROR_NONE;
Mark D. Roth72f6da82016-09-02 13:42:38 -0700244}
245
246// Destructor for channel_data. Used for both client and server filters.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800247static void destroy_channel_elem(grpc_channel_element* elem) {}
Mark D. Roth72f6da82016-09-02 13:42:38 -0700248
Mark D. Roth14c072c2016-08-26 08:31:34 -0700249// Call data used for both client and server filter.
250typedef struct base_call_data {
Mark D. Roth72f6da82016-09-02 13:42:38 -0700251 grpc_deadline_state deadline_state;
Mark D. Roth14c072c2016-08-26 08:31:34 -0700252} base_call_data;
253
254// Additional call data used only for the server filter.
255typedef struct server_call_data {
256 base_call_data base; // Must be first.
257 // The closure for receiving initial metadata.
258 grpc_closure recv_initial_metadata_ready;
259 // Received initial metadata batch.
260 grpc_metadata_batch* recv_initial_metadata;
261 // The original recv_initial_metadata_ready closure, which we chain to
262 // after our own closure is invoked.
263 grpc_closure* next_recv_initial_metadata_ready;
264} server_call_data;
265
Mark D. Roth14c072c2016-08-26 08:31:34 -0700266// Constructor for call_data. Used for both client and server filters.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800267static grpc_error* init_call_elem(grpc_call_element* elem,
Craig Tillerc52ba3a2017-02-15 22:57:43 -0800268 const grpc_call_element_args* args) {
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800269 grpc_deadline_state_init(elem, args->call_stack, args->call_combiner,
270 args->deadline);
Mark D. Roth14c072c2016-08-26 08:31:34 -0700271 return GRPC_ERROR_NONE;
272}
273
274// Destructor for call_data. Used for both client and server filters.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800275static void destroy_call_elem(grpc_call_element* elem,
Mark D. Roth14c072c2016-08-26 08:31:34 -0700276 const grpc_call_final_info* final_info,
Craig Tillere7a17022017-03-13 10:20:38 -0700277 grpc_closure* ignored) {
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800278 grpc_deadline_state_destroy(elem);
Mark D. Rothd2b45332016-08-26 11:18:00 -0700279}
280
Mark D. Roth14c072c2016-08-26 08:31:34 -0700281// Method for starting a call op for client filter.
Craig Tillere1b51da2017-03-31 15:44:33 -0700282static void client_start_transport_stream_op_batch(
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800283 grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
284 grpc_deadline_state_client_start_transport_stream_op_batch(elem, op);
Mark D. Roth14c072c2016-08-26 08:31:34 -0700285 // Chain to next filter.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800286 grpc_call_next_op(elem, op);
Mark D. Roth14c072c2016-08-26 08:31:34 -0700287}
288
289// Callback for receiving initial metadata on the server.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800290static void recv_initial_metadata_ready(void* arg, grpc_error* error) {
Noah Eisenbe82e642018-02-09 09:16:55 -0800291 grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
292 server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
Mark D. Roth14c072c2016-08-26 08:31:34 -0700293 // Get deadline from metadata and start the timer if needed.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800294 start_timer_if_needed(elem, calld->recv_initial_metadata->deadline);
Mark D. Roth14c072c2016-08-26 08:31:34 -0700295 // Invoke the next callback.
296 calld->next_recv_initial_metadata_ready->cb(
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800297 calld->next_recv_initial_metadata_ready->cb_arg, error);
Mark D. Roth14c072c2016-08-26 08:31:34 -0700298}
299
300// Method for starting a call op for server filter.
Craig Tillere1b51da2017-03-31 15:44:33 -0700301static void server_start_transport_stream_op_batch(
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800302 grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
Noah Eisenbe82e642018-02-09 09:16:55 -0800303 server_call_data* calld = static_cast<server_call_data*>(elem->call_data);
Craig Tiller759965c2017-03-02 08:50:18 -0800304 if (op->cancel_stream) {
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800305 cancel_timer_if_needed(&calld->base.deadline_state);
Mark D. Roth1bbe6cb2016-08-31 08:33:37 -0700306 } else {
307 // If we're receiving initial metadata, we need to get the deadline
308 // from the recv_initial_metadata_ready callback. So we inject our
309 // own callback into that hook.
Craig Tiller759965c2017-03-02 08:50:18 -0800310 if (op->recv_initial_metadata) {
311 calld->next_recv_initial_metadata_ready =
312 op->payload->recv_initial_metadata.recv_initial_metadata_ready;
313 calld->recv_initial_metadata =
314 op->payload->recv_initial_metadata.recv_initial_metadata;
ncteisen274bbbe2017-06-08 14:57:11 -0700315 GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
Craig Tiller91031da2016-12-28 15:44:25 -0800316 recv_initial_metadata_ready, elem,
317 grpc_schedule_on_exec_ctx);
Craig Tiller759965c2017-03-02 08:50:18 -0800318 op->payload->recv_initial_metadata.recv_initial_metadata_ready =
319 &calld->recv_initial_metadata_ready;
Mark D. Roth1bbe6cb2016-08-31 08:33:37 -0700320 }
321 // Make sure we know when the call is complete, so that we can cancel
322 // the timer.
323 // Note that we trigger this on recv_trailing_metadata, even though
324 // the client never sends trailing metadata, because this is the
325 // hook that tells us when the call is complete on the server side.
Craig Tiller759965c2017-03-02 08:50:18 -0800326 if (op->recv_trailing_metadata) {
Mark D. Roth72f6da82016-09-02 13:42:38 -0700327 inject_on_complete_cb(&calld->base.deadline_state, op);
Mark D. Roth1bbe6cb2016-08-31 08:33:37 -0700328 }
Mark D. Rothd2b45332016-08-26 11:18:00 -0700329 }
Mark D. Roth14c072c2016-08-26 08:31:34 -0700330 // Chain to next filter.
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800331 grpc_call_next_op(elem, op);
Mark D. Roth14c072c2016-08-26 08:31:34 -0700332}
333
334const grpc_channel_filter grpc_client_deadline_filter = {
Craig Tillera0f3abd2017-03-31 15:42:16 -0700335 client_start_transport_stream_op_batch,
Mark D. Roth14c072c2016-08-26 08:31:34 -0700336 grpc_channel_next_op,
337 sizeof(base_call_data),
338 init_call_elem,
339 grpc_call_stack_ignore_set_pollset_or_pollset_set,
340 destroy_call_elem,
Mark D. Rothb3405f0a2016-09-09 08:46:28 -0700341 0, // sizeof(channel_data)
Mark D. Roth14c072c2016-08-26 08:31:34 -0700342 init_channel_elem,
343 destroy_channel_elem,
Mark D. Rothb2d24882016-10-27 15:44:07 -0700344 grpc_channel_next_get_info,
Mark D. Roth14c072c2016-08-26 08:31:34 -0700345 "deadline",
346};
347
348const grpc_channel_filter grpc_server_deadline_filter = {
Craig Tillera0f3abd2017-03-31 15:42:16 -0700349 server_start_transport_stream_op_batch,
Mark D. Roth14c072c2016-08-26 08:31:34 -0700350 grpc_channel_next_op,
351 sizeof(server_call_data),
352 init_call_elem,
353 grpc_call_stack_ignore_set_pollset_or_pollset_set,
354 destroy_call_elem,
Mark D. Rothb3405f0a2016-09-09 08:46:28 -0700355 0, // sizeof(channel_data)
Mark D. Roth14c072c2016-08-26 08:31:34 -0700356 init_channel_elem,
357 destroy_channel_elem,
Mark D. Rothb2d24882016-10-27 15:44:07 -0700358 grpc_channel_next_get_info,
Mark D. Roth14c072c2016-08-26 08:31:34 -0700359 "deadline",
360};
Craig Tiller3be7dd02017-04-03 14:30:03 -0700361
362bool grpc_deadline_checking_enabled(const grpc_channel_args* channel_args) {
Craig Tiller41f2ed62017-04-06 09:33:48 -0700363 return grpc_channel_arg_get_bool(
364 grpc_channel_args_find(channel_args, GRPC_ARG_ENABLE_DEADLINE_CHECKS),
365 !grpc_channel_args_want_minimal_stack(channel_args));
Craig Tiller3be7dd02017-04-03 14:30:03 -0700366}
367
Yash Tibrewal8cf14702017-12-06 09:47:54 -0800368static bool maybe_add_deadline_filter(grpc_channel_stack_builder* builder,
Craig Tiller3be7dd02017-04-03 14:30:03 -0700369 void* arg) {
370 return grpc_deadline_checking_enabled(
371 grpc_channel_stack_builder_get_channel_arguments(builder))
Craig Tillered380162017-07-11 08:34:26 -0700372 ? grpc_channel_stack_builder_prepend_filter(
Noah Eisen4d20a662018-02-09 09:34:04 -0800373 builder, static_cast<const grpc_channel_filter*>(arg),
374 nullptr, nullptr)
Craig Tiller3be7dd02017-04-03 14:30:03 -0700375 : true;
376}
377
ncteisenadbfbd52017-11-16 15:35:45 -0800378void grpc_deadline_filter_init(void) {
Craig Tiller3be7dd02017-04-03 14:30:03 -0700379 grpc_channel_init_register_stage(
380 GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
381 maybe_add_deadline_filter, (void*)&grpc_client_deadline_filter);
382 grpc_channel_init_register_stage(
383 GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
384 maybe_add_deadline_filter, (void*)&grpc_server_deadline_filter);
385}
386
ncteisenadbfbd52017-11-16 15:35:45 -0800387void grpc_deadline_filter_shutdown(void) {}