blob: 29498056220162d9a6ee98f55fff83093e146e44 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/core/surface/call.h"
35#include "src/core/channel/channel_stack.h"
ctiller18b49ab2014-12-09 14:39:16 -080036#include "src/core/iomgr/alarm.h"
Craig Tiller485d7762015-01-23 12:54:05 -080037#include "src/core/support/string.h"
Craig Tiller1e0d4c42015-01-30 16:17:29 -080038#include "src/core/surface/byte_buffer_queue.h"
ctiller18b49ab2014-12-09 14:39:16 -080039#include "src/core/surface/channel.h"
40#include "src/core/surface/completion_queue.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080041#include <grpc/support/alloc.h>
42#include <grpc/support/log.h>
Craig Tiller6902ad22015-04-16 08:01:49 -070043#include <assert.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080044
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48
Craig Tiller566316f2015-02-02 15:25:32 -080049typedef struct legacy_state legacy_state;
50static void destroy_legacy_state(legacy_state *ls);
Craig Tillercce17ac2015-01-20 09:29:28 -080051
Craig Tiller8eb9d472015-01-27 17:00:03 -080052typedef enum { REQ_INITIAL = 0, REQ_READY, REQ_DONE } req_state;
53
54typedef enum {
55 SEND_NOTHING,
56 SEND_INITIAL_METADATA,
Craig Tiller7bd9b992015-02-04 08:38:02 -080057 SEND_BUFFERED_INITIAL_METADATA,
Craig Tiller8eb9d472015-01-27 17:00:03 -080058 SEND_MESSAGE,
Craig Tiller7bd9b992015-02-04 08:38:02 -080059 SEND_BUFFERED_MESSAGE,
Craig Tiller1c141902015-01-31 08:51:54 -080060 SEND_TRAILING_METADATA_AND_FINISH,
Craig Tiller8eb9d472015-01-27 17:00:03 -080061 SEND_FINISH
62} send_action;
63
64typedef struct {
65 grpc_ioreq_completion_func on_complete;
66 void *user_data;
67 grpc_op_error status;
68} completed_request;
69
Craig Tillerc12fee62015-02-03 11:55:50 -080070/* See request_set in grpc_call below for a description */
Craig Tiller6902ad22015-04-16 08:01:49 -070071#define REQSET_EMPTY 'X'
72#define REQSET_DONE 'Y'
73
74#define MAX_SEND_INITIAL_METADATA_COUNT 3
Craig Tiller1e0d4c42015-01-30 16:17:29 -080075
Craig Tillerc18c56e2015-02-02 15:59:13 -080076typedef struct {
Craig Tillerdaceea82015-02-02 16:15:53 -080077 /* Overall status of the operation: starts OK, may degrade to
78 non-OK */
Craig Tiller1e0d4c42015-01-30 16:17:29 -080079 grpc_op_error status;
Craig Tillerdaceea82015-02-02 16:15:53 -080080 /* Completion function to call at the end of the operation */
Craig Tillercce17ac2015-01-20 09:29:28 -080081 grpc_ioreq_completion_func on_complete;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080082 void *user_data;
Craig Tillerd642dcf2015-02-03 20:39:09 -080083 /* a bit mask of which request ops are needed (1u << opid) */
Craig Tillercce17ac2015-01-20 09:29:28 -080084 gpr_uint32 need_mask;
Craig Tillerdaceea82015-02-02 16:15:53 -080085 /* a bit mask of which request ops are now completed */
Craig Tillercce17ac2015-01-20 09:29:28 -080086 gpr_uint32 complete_mask;
Craig Tillerc18c56e2015-02-02 15:59:13 -080087} reqinfo_master;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080088
Craig Tillerdaceea82015-02-02 16:15:53 -080089/* Status data for a request can come from several sources; this
90 enumerates them all, and acts as a priority sorting for which
91 status to return to the application - earlier entries override
92 later ones */
Craig Tiller68752722015-01-29 14:59:54 -080093typedef enum {
Craig Tillerdaceea82015-02-02 16:15:53 -080094 /* Status came from the application layer overriding whatever
95 the wire says */
Craig Tiller68752722015-01-29 14:59:54 -080096 STATUS_FROM_API_OVERRIDE = 0,
Craig Tiller8b282cb2015-04-17 14:57:44 -070097 /* Status was created by some internal channel stack operation */
98 STATUS_FROM_CORE,
Craig Tillerdaceea82015-02-02 16:15:53 -080099 /* Status came from 'the wire' - or somewhere below the surface
100 layer */
Craig Tiller68752722015-01-29 14:59:54 -0800101 STATUS_FROM_WIRE,
Craig Tiller68752722015-01-29 14:59:54 -0800102 STATUS_SOURCE_COUNT
103} status_source;
104
105typedef struct {
Craig Tillerdaceea82015-02-02 16:15:53 -0800106 gpr_uint8 is_set;
Craig Tiller68752722015-01-29 14:59:54 -0800107 grpc_status_code code;
108 grpc_mdstr *details;
109} received_status;
110
Craig Tillerdaceea82015-02-02 16:15:53 -0800111/* How far through the GRPC stream have we read? */
112typedef enum {
113 /* We are still waiting for initial metadata to complete */
Craig Tillerc12fee62015-02-03 11:55:50 -0800114 READ_STATE_INITIAL = 0,
Craig Tillerdaceea82015-02-02 16:15:53 -0800115 /* We have gotten initial metadata, and are reading either
116 messages or trailing metadata */
117 READ_STATE_GOT_INITIAL_METADATA,
118 /* The stream is closed for reading */
119 READ_STATE_READ_CLOSED,
120 /* The stream is closed for reading & writing */
121 READ_STATE_STREAM_CLOSED
122} read_state;
123
Craig Tillerc12fee62015-02-03 11:55:50 -0800124typedef enum {
125 WRITE_STATE_INITIAL = 0,
126 WRITE_STATE_STARTED,
127 WRITE_STATE_WRITE_CLOSED
128} write_state;
129
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800130struct grpc_call {
131 grpc_completion_queue *cq;
132 grpc_channel *channel;
133 grpc_mdctx *metadata_context;
Craig Tillercce17ac2015-01-20 09:29:28 -0800134 /* TODO(ctiller): share with cq if possible? */
135 gpr_mu mu;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800136
Craig Tillere5d683c2015-02-03 16:37:36 -0800137 /* how far through the stream have we read? */
Craig Tillerdaceea82015-02-02 16:15:53 -0800138 read_state read_state;
Craig Tillere5d683c2015-02-03 16:37:36 -0800139 /* how far through the stream have we written? */
Craig Tillerc12fee62015-02-03 11:55:50 -0800140 write_state write_state;
Craig Tillere5d683c2015-02-03 16:37:36 -0800141 /* client or server call */
142 gpr_uint8 is_client;
143 /* is the alarm set */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800144 gpr_uint8 have_alarm;
Craig Tillere5d683c2015-02-03 16:37:36 -0800145 /* are we currently performing a send operation */
Craig Tiller8eb9d472015-01-27 17:00:03 -0800146 gpr_uint8 sending;
Craig Tiller991ca9f2015-03-03 09:59:22 -0800147 /* are we currently completing requests */
148 gpr_uint8 completing;
Craig Tillere5d683c2015-02-03 16:37:36 -0800149 /* pairs with completed_requests */
Craig Tiller8eb9d472015-01-27 17:00:03 -0800150 gpr_uint8 num_completed_requests;
Craig Tillere5d683c2015-02-03 16:37:36 -0800151 /* flag that we need to request more data */
Craig Tiller2e103572015-01-29 14:12:07 -0800152 gpr_uint8 need_more_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800153
Craig Tillere5d683c2015-02-03 16:37:36 -0800154 /* Active ioreqs.
155 request_set and request_data contain one element per active ioreq
156 operation.
Craig Tillerebf94bf2015-02-05 08:48:46 -0800157
Craig Tillere5d683c2015-02-03 16:37:36 -0800158 request_set[op] is an integer specifying a set of operations to which
159 the request belongs:
Craig Tillerebf94bf2015-02-05 08:48:46 -0800160 - if it is < GRPC_IOREQ_OP_COUNT, then this operation is pending
Craig Tillere5d683c2015-02-03 16:37:36 -0800161 completion, and the integer represents to which group of operations
162 the ioreq belongs. Each group is represented by one master, and the
163 integer in request_set is an index into masters to find the master
164 data.
165 - if it is REQSET_EMPTY, the ioreq op is inactive and available to be
166 started
167 - finally, if request_set[op] is REQSET_DONE, then the operation is
168 complete and unavailable to be started again
Craig Tillerebf94bf2015-02-05 08:48:46 -0800169
Craig Tillere5d683c2015-02-03 16:37:36 -0800170 request_data[op] is the request data as supplied by the initiator of
171 a request, and is valid iff request_set[op] <= GRPC_IOREQ_OP_COUNT.
172 The set fields are as per the request type specified by op.
173
Craig Tillerd6731622015-02-03 22:44:13 -0800174 Finally, one element of masters is set per active _set_ of ioreq
Craig Tillere5d683c2015-02-03 16:37:36 -0800175 operations. It describes work left outstanding, result status, and
176 what work to perform upon operation completion. As one ioreq of each
177 op type can be active at once, by convention we choose the first element
Craig Tillerd6731622015-02-03 22:44:13 -0800178 of the group to be the master -- ie the master of in-progress operation
179 op is masters[request_set[op]]. This allows constant time allocation
Craig Tillere5d683c2015-02-03 16:37:36 -0800180 and a strong upper bound of a count of masters to be calculated. */
Craig Tillerc12fee62015-02-03 11:55:50 -0800181 gpr_uint8 request_set[GRPC_IOREQ_OP_COUNT];
182 grpc_ioreq_data request_data[GRPC_IOREQ_OP_COUNT];
Craig Tillerc18c56e2015-02-02 15:59:13 -0800183 reqinfo_master masters[GRPC_IOREQ_OP_COUNT];
Craig Tillere5d683c2015-02-03 16:37:36 -0800184
185 /* Dynamic array of ioreq's that have completed: the count of
186 elements is queued in num_completed_requests.
187 This list is built up under lock(), and flushed entirely during
188 unlock().
189 We know the upper bound of the number of elements as we can only
190 have one ioreq of each type active at once. */
Craig Tiller8eb9d472015-01-27 17:00:03 -0800191 completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
Craig Tillere5d683c2015-02-03 16:37:36 -0800192 /* Incoming buffer of messages */
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800193 grpc_byte_buffer_queue incoming_queue;
Craig Tillere5d683c2015-02-03 16:37:36 -0800194 /* Buffered read metadata waiting to be returned to the application.
195 Element 0 is initial metadata, element 1 is trailing metadata. */
Craig Tillerc12fee62015-02-03 11:55:50 -0800196 grpc_metadata_array buffered_metadata[2];
Craig Tillere5d683c2015-02-03 16:37:36 -0800197 /* All metadata received - unreffed at once at the end of the call */
Craig Tiller3a4749f2015-01-30 07:51:45 -0800198 grpc_mdelem **owned_metadata;
199 size_t owned_metadata_count;
200 size_t owned_metadata_capacity;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800201
Craig Tillere5d683c2015-02-03 16:37:36 -0800202 /* Received call statuses from various sources */
Craig Tiller68752722015-01-29 14:59:54 -0800203 received_status status[STATUS_SOURCE_COUNT];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800204
Craig Tillere5d683c2015-02-03 16:37:36 -0800205 /* Deadline alarm - if have_alarm is non-zero */
Craig Tillercce17ac2015-01-20 09:29:28 -0800206 grpc_alarm alarm;
207
Craig Tillere5d683c2015-02-03 16:37:36 -0800208 /* Call refcount - to keep the call alive during asynchronous operations */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800209 gpr_refcount internal_refcount;
Craig Tillercce17ac2015-01-20 09:29:28 -0800210
Craig Tiller6902ad22015-04-16 08:01:49 -0700211 grpc_linked_mdelem send_initial_metadata[MAX_SEND_INITIAL_METADATA_COUNT];
212 grpc_linked_mdelem status_link;
213 grpc_linked_mdelem details_link;
214 size_t send_initial_metadata_count;
215 gpr_timespec send_deadline;
216
Craig Tillerebf94bf2015-02-05 08:48:46 -0800217 /* Data that the legacy api needs to track. To be deleted at some point
Craig Tillere5d683c2015-02-03 16:37:36 -0800218 soon */
Craig Tillercce17ac2015-01-20 09:29:28 -0800219 legacy_state *legacy_state;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800220};
221
Craig Tiller87d5b192015-04-16 14:37:57 -0700222#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800223#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
224#define CALL_ELEM_FROM_CALL(call, idx) \
225 grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
226#define CALL_FROM_TOP_ELEM(top_elem) \
227 CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem))
228
Craig Tillercce17ac2015-01-20 09:29:28 -0800229#define SWAP(type, x, y) \
230 do { \
231 type temp = x; \
232 x = y; \
233 y = temp; \
234 } while (0)
235
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800236static void do_nothing(void *ignored, grpc_op_error also_ignored) {}
Craig Tiller8eb9d472015-01-27 17:00:03 -0800237static send_action choose_send_action(grpc_call *call);
238static void enact_send_action(grpc_call *call, send_action sa);
Craig Tiller6902ad22015-04-16 08:01:49 -0700239static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800240
Craig Tillerfb189f82015-02-03 12:07:07 -0800241grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
Craig Tiller87d5b192015-04-16 14:37:57 -0700242 const void *server_transport_data,
243 grpc_mdelem **add_initial_metadata,
244 size_t add_initial_metadata_count,
245 gpr_timespec send_deadline) {
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800246 size_t i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800247 grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
248 grpc_call *call =
249 gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
Craig Tillercce17ac2015-01-20 09:29:28 -0800250 memset(call, 0, sizeof(grpc_call));
251 gpr_mu_init(&call->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800252 call->channel = channel;
Craig Tillerfb189f82015-02-03 12:07:07 -0800253 call->cq = cq;
Craig Tillercce17ac2015-01-20 09:29:28 -0800254 call->is_client = server_transport_data == NULL;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800255 for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800256 call->request_set[i] = REQSET_EMPTY;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800257 }
Craig Tiller23aa6c42015-01-27 17:16:12 -0800258 if (call->is_client) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800259 call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE;
260 call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE;
Craig Tiller23aa6c42015-01-27 17:16:12 -0800261 }
Craig Tiller6902ad22015-04-16 08:01:49 -0700262 GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT);
263 for (i = 0; i < add_initial_metadata_count; i++) {
264 call->send_initial_metadata[i].md = add_initial_metadata[i];
265 }
266 call->send_initial_metadata_count = add_initial_metadata_count;
267 call->send_deadline = send_deadline;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800268 grpc_channel_internal_ref(channel);
269 call->metadata_context = grpc_channel_get_metadata_context(channel);
Craig Tillera4541102015-01-29 11:46:11 -0800270 /* one ref is dropped in response to destroy, the other in
271 stream_closed */
272 gpr_ref_init(&call->internal_refcount, 2);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800273 grpc_call_stack_init(channel_stack, server_transport_data,
274 CALL_STACK_FROM_CALL(call));
Craig Tiller6902ad22015-04-16 08:01:49 -0700275 if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) {
276 set_deadline_alarm(call, send_deadline);
277 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800278 return call;
279}
280
Craig Tiller166e2502015-02-03 20:14:41 -0800281void grpc_call_set_completion_queue(grpc_call *call,
282 grpc_completion_queue *cq) {
283 call->cq = cq;
284}
285
Craig Tiller24be0f72015-02-10 14:04:22 -0800286grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
287 return call->cq;
288}
289
Craig Tiller928fbc82015-01-29 15:06:42 -0800290void grpc_call_internal_ref(grpc_call *c) { gpr_ref(&c->internal_refcount); }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800291
Craig Tilleraef25da2015-01-29 17:19:45 -0800292static void destroy_call(void *call, int ignored_success) {
Craig Tiller566316f2015-02-02 15:25:32 -0800293 size_t i;
Craig Tilleraef25da2015-01-29 17:19:45 -0800294 grpc_call *c = call;
Craig Tillera4541102015-01-29 11:46:11 -0800295 grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
296 grpc_channel_internal_unref(c->channel);
297 gpr_mu_destroy(&c->mu);
Craig Tiller68752722015-01-29 14:59:54 -0800298 for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
299 if (c->status[i].details) {
300 grpc_mdstr_unref(c->status[i].details);
301 }
Craig Tillera4541102015-01-29 11:46:11 -0800302 }
Craig Tiller3a4749f2015-01-30 07:51:45 -0800303 for (i = 0; i < c->owned_metadata_count; i++) {
304 grpc_mdelem_unref(c->owned_metadata[i]);
305 }
306 gpr_free(c->owned_metadata);
Craig Tillerc12fee62015-02-03 11:55:50 -0800307 for (i = 0; i < GPR_ARRAY_SIZE(c->buffered_metadata); i++) {
308 gpr_free(c->buffered_metadata[i].metadata);
309 }
Craig Tillereb40a532015-04-17 16:46:20 -0700310 for (i = 0; i < c->send_initial_metadata_count; i++) {
311 grpc_mdelem_unref(c->send_initial_metadata[i].md);
312 }
Craig Tillera4541102015-01-29 11:46:11 -0800313 if (c->legacy_state) {
Craig Tiller566316f2015-02-02 15:25:32 -0800314 destroy_legacy_state(c->legacy_state);
Craig Tillera4541102015-01-29 11:46:11 -0800315 }
Craig Tiller37bbead2015-02-05 08:43:49 -0800316 grpc_bbq_destroy(&c->incoming_queue);
Craig Tillera4541102015-01-29 11:46:11 -0800317 gpr_free(c);
318}
319
Craig Tilleraef25da2015-01-29 17:19:45 -0800320void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800321 if (gpr_unref(&c->internal_refcount)) {
Craig Tilleraef25da2015-01-29 17:19:45 -0800322 if (allow_immediate_deletion) {
323 destroy_call(c, 1);
324 } else {
325 grpc_iomgr_add_callback(destroy_call, c);
326 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800327 }
328}
329
Craig Tiller928fbc82015-01-29 15:06:42 -0800330static void set_status_code(grpc_call *call, status_source source,
331 gpr_uint32 status) {
Craig Tiller8b976d02015-02-05 21:41:23 -0800332 int flush;
333
Craig Tillerdaceea82015-02-02 16:15:53 -0800334 call->status[source].is_set = 1;
Craig Tiller68752722015-01-29 14:59:54 -0800335 call->status[source].code = status;
Craig Tiller30547562015-02-05 17:04:51 -0800336
Craig Tiller8b976d02015-02-05 21:41:23 -0800337 if (call->is_client) {
338 flush = status == GRPC_STATUS_CANCELLED;
339 } else {
340 flush = status != GRPC_STATUS_OK;
341 }
342
343 if (flush && !grpc_bbq_empty(&call->incoming_queue)) {
Craig Tiller30547562015-02-05 17:04:51 -0800344 grpc_bbq_flush(&call->incoming_queue);
345 }
Craig Tiller68752722015-01-29 14:59:54 -0800346}
347
Craig Tiller928fbc82015-01-29 15:06:42 -0800348static void set_status_details(grpc_call *call, status_source source,
349 grpc_mdstr *status) {
Craig Tiller68752722015-01-29 14:59:54 -0800350 if (call->status[source].details != NULL) {
351 grpc_mdstr_unref(call->status[source].details);
352 }
353 call->status[source].details = status;
354}
355
Craig Tillercce17ac2015-01-20 09:29:28 -0800356static grpc_call_error bind_cq(grpc_call *call, grpc_completion_queue *cq) {
357 if (call->cq) return GRPC_CALL_ERROR_ALREADY_INVOKED;
358 call->cq = cq;
359 return GRPC_CALL_OK;
360}
361
362static void request_more_data(grpc_call *call) {
363 grpc_call_op op;
364
365 /* call down */
366 op.type = GRPC_REQUEST_DATA;
367 op.dir = GRPC_CALL_DOWN;
368 op.flags = 0;
369 op.done_cb = do_nothing;
370 op.user_data = NULL;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700371 op.bind_pollset = NULL;
Craig Tillercce17ac2015-01-20 09:29:28 -0800372
373 grpc_call_execute_op(call, &op);
374}
375
Craig Tillerc12fee62015-02-03 11:55:50 -0800376static int is_op_live(grpc_call *call, grpc_ioreq_op op) {
377 gpr_uint8 set = call->request_set[op];
378 reqinfo_master *master;
379 if (set >= GRPC_IOREQ_OP_COUNT) return 0;
380 master = &call->masters[set];
Craig Tillerd642dcf2015-02-03 20:39:09 -0800381 return (master->complete_mask & (1u << op)) == 0;
Craig Tillerc12fee62015-02-03 11:55:50 -0800382}
383
Craig Tiller8eb9d472015-01-27 17:00:03 -0800384static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); }
Craig Tillercce17ac2015-01-20 09:29:28 -0800385
Craig Tiller8eb9d472015-01-27 17:00:03 -0800386static void unlock(grpc_call *call) {
Craig Tiller2f38be62015-01-29 10:26:22 -0800387 send_action sa = SEND_NOTHING;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800388 completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
Craig Tiller991ca9f2015-03-03 09:59:22 -0800389 int completing_requests = 0;
Craig Tillercffbcb72015-01-29 23:16:33 -0800390 int need_more_data =
Craig Tillerebf94bf2015-02-05 08:48:46 -0800391 call->need_more_data &&
Craig Tillerd9e64132015-02-20 08:58:01 -0800392 (call->write_state >= WRITE_STATE_STARTED || !call->is_client);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800393 int i;
394
Craig Tillercffbcb72015-01-29 23:16:33 -0800395 if (need_more_data) {
396 call->need_more_data = 0;
397 }
Craig Tiller2e103572015-01-29 14:12:07 -0800398
Craig Tiller991ca9f2015-03-03 09:59:22 -0800399 if (!call->completing && call->num_completed_requests != 0) {
400 completing_requests = call->num_completed_requests;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800401 memcpy(completed_requests, call->completed_requests,
402 sizeof(completed_requests));
403 call->num_completed_requests = 0;
Craig Tiller991ca9f2015-03-03 09:59:22 -0800404 call->completing = 1;
Craig Tiller461be402015-03-05 04:59:18 +0000405 grpc_call_internal_ref(call);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800406 }
407
408 if (!call->sending) {
409 sa = choose_send_action(call);
410 if (sa != SEND_NOTHING) {
411 call->sending = 1;
Craig Tillera4541102015-01-29 11:46:11 -0800412 grpc_call_internal_ref(call);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800413 }
414 }
415
416 gpr_mu_unlock(&call->mu);
417
Craig Tiller2e103572015-01-29 14:12:07 -0800418 if (need_more_data) {
419 request_more_data(call);
420 }
421
Craig Tiller8eb9d472015-01-27 17:00:03 -0800422 if (sa != SEND_NOTHING) {
423 enact_send_action(call, sa);
424 }
425
Craig Tiller991ca9f2015-03-03 09:59:22 -0800426 if (completing_requests > 0) {
427 for (i = 0; i < completing_requests; i++) {
428 completed_requests[i].on_complete(call, completed_requests[i].status,
429 completed_requests[i].user_data);
430 }
431 lock(call);
432 call->completing = 0;
433 unlock(call);
Craig Tiller461be402015-03-05 04:59:18 +0000434 grpc_call_internal_unref(call, 0);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800435 }
436}
Craig Tillercce17ac2015-01-20 09:29:28 -0800437
Craig Tillerfb189f82015-02-03 12:07:07 -0800438static void get_final_status(grpc_call *call, grpc_ioreq_data out) {
Craig Tiller68752722015-01-29 14:59:54 -0800439 int i;
440 for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
Craig Tillerdaceea82015-02-02 16:15:53 -0800441 if (call->status[i].is_set) {
Craig Tillerfb189f82015-02-03 12:07:07 -0800442 out.recv_status.set_value(call->status[i].code,
443 out.recv_status.user_data);
444 return;
445 }
446 }
Craig Tillerde343162015-02-09 23:37:22 -0800447 if (call->is_client) {
448 out.recv_status.set_value(GRPC_STATUS_UNKNOWN, out.recv_status.user_data);
449 } else {
450 out.recv_status.set_value(GRPC_STATUS_OK, out.recv_status.user_data);
451 }
Craig Tillerfb189f82015-02-03 12:07:07 -0800452}
453
454static void get_final_details(grpc_call *call, grpc_ioreq_data out) {
455 int i;
456 for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
457 if (call->status[i].is_set) {
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800458 if (call->status[i].details) {
459 gpr_slice details = call->status[i].details->slice;
460 size_t len = GPR_SLICE_LENGTH(details);
Craig Tillerfb189f82015-02-03 12:07:07 -0800461 if (len + 1 > *out.recv_status_details.details_capacity) {
462 *out.recv_status_details.details_capacity = GPR_MAX(
463 len + 1, *out.recv_status_details.details_capacity * 3 / 2);
464 *out.recv_status_details.details =
465 gpr_realloc(*out.recv_status_details.details,
466 *out.recv_status_details.details_capacity);
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800467 }
Craig Tillerfb189f82015-02-03 12:07:07 -0800468 memcpy(*out.recv_status_details.details, GPR_SLICE_START_PTR(details),
469 len);
470 (*out.recv_status_details.details)[len] = 0;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800471 } else {
472 goto no_details;
473 }
Craig Tiller68752722015-01-29 14:59:54 -0800474 return;
475 }
476 }
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800477
478no_details:
Craig Tillerfb189f82015-02-03 12:07:07 -0800479 if (0 == *out.recv_status_details.details_capacity) {
480 *out.recv_status_details.details_capacity = 8;
481 *out.recv_status_details.details =
482 gpr_malloc(*out.recv_status_details.details_capacity);
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800483 }
Craig Tillerfb189f82015-02-03 12:07:07 -0800484 **out.recv_status_details.details = 0;
Craig Tiller68752722015-01-29 14:59:54 -0800485}
486
Craig Tillerc12fee62015-02-03 11:55:50 -0800487static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op,
488 grpc_op_error status) {
489 completed_request *cr;
490 gpr_uint8 master_set = call->request_set[op];
491 reqinfo_master *master;
492 size_t i;
493 /* ioreq is live: we need to do something */
494 master = &call->masters[master_set];
Craig Tillerd642dcf2015-02-03 20:39:09 -0800495 master->complete_mask |= 1u << op;
Craig Tillerc12fee62015-02-03 11:55:50 -0800496 if (status != GRPC_OP_OK) {
497 master->status = status;
498 master->complete_mask = master->need_mask;
499 }
500 if (master->complete_mask == master->need_mask) {
501 for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
502 if (call->request_set[i] != master_set) {
503 continue;
504 }
505 call->request_set[i] = REQSET_DONE;
506 switch ((grpc_ioreq_op)i) {
507 case GRPC_IOREQ_RECV_MESSAGE:
508 case GRPC_IOREQ_SEND_MESSAGE:
509 if (master->status == GRPC_OP_OK) {
510 call->request_set[i] = REQSET_EMPTY;
511 } else {
512 call->write_state = WRITE_STATE_WRITE_CLOSED;
513 }
514 break;
515 case GRPC_IOREQ_RECV_CLOSE:
516 case GRPC_IOREQ_SEND_INITIAL_METADATA:
517 case GRPC_IOREQ_SEND_TRAILING_METADATA:
518 case GRPC_IOREQ_SEND_STATUS:
519 case GRPC_IOREQ_SEND_CLOSE:
520 break;
521 case GRPC_IOREQ_RECV_STATUS:
Craig Tillerfb189f82015-02-03 12:07:07 -0800522 get_final_status(call, call->request_data[GRPC_IOREQ_RECV_STATUS]);
523 break;
524 case GRPC_IOREQ_RECV_STATUS_DETAILS:
525 get_final_details(call,
526 call->request_data[GRPC_IOREQ_RECV_STATUS_DETAILS]);
Craig Tillerc12fee62015-02-03 11:55:50 -0800527 break;
528 case GRPC_IOREQ_RECV_INITIAL_METADATA:
529 SWAP(grpc_metadata_array, call->buffered_metadata[0],
530 *call->request_data[GRPC_IOREQ_RECV_INITIAL_METADATA]
531 .recv_metadata);
532 break;
533 case GRPC_IOREQ_RECV_TRAILING_METADATA:
534 SWAP(grpc_metadata_array, call->buffered_metadata[1],
535 *call->request_data[GRPC_IOREQ_RECV_TRAILING_METADATA]
536 .recv_metadata);
537 break;
538 case GRPC_IOREQ_OP_COUNT:
539 abort();
540 break;
541 }
542 }
543 cr = &call->completed_requests[call->num_completed_requests++];
544 cr->status = master->status;
545 cr->on_complete = master->on_complete;
546 cr->user_data = master->user_data;
547 }
548}
549
Craig Tillercce17ac2015-01-20 09:29:28 -0800550static void finish_ioreq_op(grpc_call *call, grpc_ioreq_op op,
551 grpc_op_error status) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800552 if (is_op_live(call, op)) {
553 finish_live_ioreq_op(call, op, status);
Craig Tillercce17ac2015-01-20 09:29:28 -0800554 }
555}
556
murgatroid9904c44792015-02-12 12:20:46 -0800557static void finish_send_op(grpc_call *call, grpc_ioreq_op op, write_state ws,
Craig Tiller1c141902015-01-31 08:51:54 -0800558 grpc_op_error error) {
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800559 lock(call);
560 finish_ioreq_op(call, op, error);
561 call->sending = 0;
murgatroid9904c44792015-02-12 12:20:46 -0800562 call->write_state = ws;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800563 unlock(call);
564 grpc_call_internal_unref(call, 0);
565}
566
Craig Tillercce17ac2015-01-20 09:29:28 -0800567static void finish_write_step(void *pc, grpc_op_error error) {
murgatroid9904c44792015-02-12 12:20:46 -0800568 finish_send_op(pc, GRPC_IOREQ_SEND_MESSAGE, WRITE_STATE_STARTED, error);
Craig Tillercce17ac2015-01-20 09:29:28 -0800569}
570
571static void finish_finish_step(void *pc, grpc_op_error error) {
murgatroid9904c44792015-02-12 12:20:46 -0800572 finish_send_op(pc, GRPC_IOREQ_SEND_CLOSE, WRITE_STATE_WRITE_CLOSED, error);
Craig Tillercce17ac2015-01-20 09:29:28 -0800573}
574
Craig Tiller62ac1552015-01-27 15:41:44 -0800575static void finish_start_step(void *pc, grpc_op_error error) {
Craig Tillerd9e64132015-02-20 08:58:01 -0800576 finish_send_op(pc, GRPC_IOREQ_SEND_INITIAL_METADATA, WRITE_STATE_STARTED,
577 error);
Craig Tiller62ac1552015-01-27 15:41:44 -0800578}
579
Craig Tiller8eb9d472015-01-27 17:00:03 -0800580static send_action choose_send_action(grpc_call *call) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800581 switch (call->write_state) {
582 case WRITE_STATE_INITIAL:
Craig Tillerdcde31f2015-02-04 12:47:58 -0800583 if (is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) {
Craig Tillerd9e64132015-02-20 08:58:01 -0800584 if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE) ||
585 is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
Craig Tillerde648622015-02-05 09:32:10 -0800586 return SEND_BUFFERED_INITIAL_METADATA;
587 } else {
588 return SEND_INITIAL_METADATA;
589 }
Craig Tillerc12fee62015-02-03 11:55:50 -0800590 }
Craig Tiller8eb9d472015-01-27 17:00:03 -0800591 return SEND_NOTHING;
Craig Tillerc12fee62015-02-03 11:55:50 -0800592 case WRITE_STATE_STARTED:
Craig Tillerdcde31f2015-02-04 12:47:58 -0800593 if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) {
Craig Tillerde648622015-02-05 09:32:10 -0800594 if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
595 return SEND_BUFFERED_MESSAGE;
596 } else {
597 return SEND_MESSAGE;
598 }
Craig Tiller119dcf02015-02-05 09:33:30 -0800599 } else if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
Craig Tiller7a9d7922015-01-31 09:35:20 -0800600 finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, GRPC_OP_OK);
601 finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, GRPC_OP_OK);
Craig Tillerde648622015-02-05 09:32:10 -0800602 if (call->is_client) {
603 return SEND_FINISH;
604 } else {
605 return SEND_TRAILING_METADATA_AND_FINISH;
606 }
Craig Tiller1c141902015-01-31 08:51:54 -0800607 }
Craig Tillerc12fee62015-02-03 11:55:50 -0800608 return SEND_NOTHING;
609 case WRITE_STATE_WRITE_CLOSED:
610 return SEND_NOTHING;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800611 }
Craig Tillerc12fee62015-02-03 11:55:50 -0800612 gpr_log(GPR_ERROR, "should never reach here");
613 abort();
614 return SEND_NOTHING;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800615}
616
Craig Tiller87d5b192015-04-16 14:37:57 -0700617static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count,
618 grpc_metadata *metadata) {
Craig Tiller6902ad22015-04-16 08:01:49 -0700619 size_t i;
620 grpc_mdelem_list out;
621 if (count == 0) {
622 out.head = out.tail = NULL;
623 return out;
624 }
625 for (i = 0; i < count; i++) {
626 grpc_metadata *md = &metadata[i];
Craig Tiller87d5b192015-04-16 14:37:57 -0700627 grpc_metadata *next_md = (i == count - 1) ? NULL : &metadata[i + 1];
628 grpc_metadata *prev_md = (i == 0) ? NULL : &metadata[i - 1];
629 grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
Craig Tillerd2b11fa2015-04-21 13:45:19 -0700630 GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
Craig Tiller87d5b192015-04-16 14:37:57 -0700631 l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key,
632 (const gpr_uint8 *)md->value,
633 md->value_length);
634 l->next = next_md ? (grpc_linked_mdelem *)&next_md->internal_data : NULL;
635 l->prev = prev_md ? (grpc_linked_mdelem *)&prev_md->internal_data : NULL;
Craig Tiller6902ad22015-04-16 08:01:49 -0700636 }
Craig Tiller87d5b192015-04-16 14:37:57 -0700637 out.head = (grpc_linked_mdelem *)&(metadata[0].internal_data);
638 out.tail = (grpc_linked_mdelem *)&(metadata[count - 1].internal_data);
Craig Tiller6902ad22015-04-16 08:01:49 -0700639 return out;
Craig Tillera5d4e772015-01-29 11:52:37 -0800640}
641
Craig Tiller8eb9d472015-01-27 17:00:03 -0800642static void enact_send_action(grpc_call *call, send_action sa) {
643 grpc_ioreq_data data;
Craig Tiller62ac1552015-01-27 15:41:44 -0800644 grpc_call_op op;
Craig Tiller4acdbb32015-01-29 21:02:52 -0800645 size_t i;
Craig Tiller7bd9b992015-02-04 08:38:02 -0800646 gpr_uint32 flags = 0;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800647 char status_str[GPR_LTOA_MIN_BUFSIZE];
Craig Tiller62ac1552015-01-27 15:41:44 -0800648
Craig Tiller8eb9d472015-01-27 17:00:03 -0800649 switch (sa) {
650 case SEND_NOTHING:
651 abort();
652 break;
Craig Tiller7bd9b992015-02-04 08:38:02 -0800653 case SEND_BUFFERED_INITIAL_METADATA:
654 flags |= GRPC_WRITE_BUFFER_HINT;
655 /* fallthrough */
Craig Tiller8eb9d472015-01-27 17:00:03 -0800656 case SEND_INITIAL_METADATA:
Craig Tillerc12fee62015-02-03 11:55:50 -0800657 data = call->request_data[GRPC_IOREQ_SEND_INITIAL_METADATA];
Craig Tiller6902ad22015-04-16 08:01:49 -0700658 op.type = GRPC_SEND_METADATA;
659 op.dir = GRPC_CALL_DOWN;
660 op.flags = flags;
Craig Tiller87d5b192015-04-16 14:37:57 -0700661 op.data.metadata.list = chain_metadata_from_app(
662 call, data.send_metadata.count, data.send_metadata.metadata);
Craig Tiller6902ad22015-04-16 08:01:49 -0700663 op.data.metadata.garbage.head = op.data.metadata.garbage.tail = NULL;
664 op.data.metadata.deadline = call->send_deadline;
665 for (i = 0; i < call->send_initial_metadata_count; i++) {
Craig Tiller205aee12015-04-16 14:46:41 -0700666 grpc_metadata_batch_link_head(&op.data.metadata,
Craig Tiller76f5d462015-04-17 14:58:12 -0700667 &call->send_initial_metadata[i]);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800668 }
Craig Tillereb40a532015-04-17 16:46:20 -0700669 call->send_initial_metadata_count = 0;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800670 op.done_cb = finish_start_step;
671 op.user_data = call;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700672 op.bind_pollset = grpc_cq_pollset(call->cq);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800673 grpc_call_execute_op(call, &op);
674 break;
Craig Tiller7bd9b992015-02-04 08:38:02 -0800675 case SEND_BUFFERED_MESSAGE:
676 flags |= GRPC_WRITE_BUFFER_HINT;
677 /* fallthrough */
Craig Tiller8eb9d472015-01-27 17:00:03 -0800678 case SEND_MESSAGE:
Craig Tillerc12fee62015-02-03 11:55:50 -0800679 data = call->request_data[GRPC_IOREQ_SEND_MESSAGE];
Craig Tiller8eb9d472015-01-27 17:00:03 -0800680 op.type = GRPC_SEND_MESSAGE;
681 op.dir = GRPC_CALL_DOWN;
Craig Tiller7bd9b992015-02-04 08:38:02 -0800682 op.flags = flags;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800683 op.data.message = data.send_message;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800684 op.done_cb = finish_write_step;
685 op.user_data = call;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700686 op.bind_pollset = NULL;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800687 grpc_call_execute_op(call, &op);
688 break;
Craig Tiller1c141902015-01-31 08:51:54 -0800689 case SEND_TRAILING_METADATA_AND_FINISH:
690 /* send trailing metadata */
Craig Tillerc12fee62015-02-03 11:55:50 -0800691 data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA];
Craig Tiller6902ad22015-04-16 08:01:49 -0700692 op.type = GRPC_SEND_METADATA;
693 op.dir = GRPC_CALL_DOWN;
694 op.flags = flags;
Craig Tiller87d5b192015-04-16 14:37:57 -0700695 op.data.metadata.list = chain_metadata_from_app(
696 call, data.send_metadata.count, data.send_metadata.metadata);
Craig Tiller6902ad22015-04-16 08:01:49 -0700697 op.data.metadata.garbage.head = op.data.metadata.garbage.tail = NULL;
698 op.data.metadata.deadline = call->send_deadline;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700699 op.bind_pollset = NULL;
Craig Tiller1c141902015-01-31 08:51:54 -0800700 /* send status */
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800701 /* TODO(ctiller): cache common status values */
Craig Tillerc12fee62015-02-03 11:55:50 -0800702 data = call->request_data[GRPC_IOREQ_SEND_STATUS];
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800703 gpr_ltoa(data.send_status.code, status_str);
Craig Tiller205aee12015-04-16 14:46:41 -0700704 grpc_metadata_batch_add_tail(
Craig Tiller87d5b192015-04-16 14:37:57 -0700705 &op.data.metadata, &call->status_link,
706 grpc_mdelem_from_metadata_strings(
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800707 call->metadata_context,
708 grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)),
709 grpc_mdstr_from_string(call->metadata_context, status_str)));
710 if (data.send_status.details) {
Craig Tiller205aee12015-04-16 14:46:41 -0700711 grpc_metadata_batch_add_tail(
Craig Tiller87d5b192015-04-16 14:37:57 -0700712 &op.data.metadata, &call->details_link,
Craig Tiller1c141902015-01-31 08:51:54 -0800713 grpc_mdelem_from_metadata_strings(
714 call->metadata_context,
715 grpc_mdstr_ref(grpc_channel_get_message_string(call->channel)),
716 grpc_mdstr_from_string(call->metadata_context,
717 data.send_status.details)));
Craig Tillerabcf6522015-01-28 15:44:24 -0800718 }
Craig Tiller6902ad22015-04-16 08:01:49 -0700719 op.done_cb = do_nothing;
720 op.user_data = NULL;
721 grpc_call_execute_op(call, &op);
Craig Tiller1c141902015-01-31 08:51:54 -0800722 /* fallthrough: see choose_send_action for details */
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800723 case SEND_FINISH:
Craig Tiller8eb9d472015-01-27 17:00:03 -0800724 op.type = GRPC_SEND_FINISH;
725 op.dir = GRPC_CALL_DOWN;
726 op.flags = 0;
727 op.done_cb = finish_finish_step;
728 op.user_data = call;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700729 op.bind_pollset = NULL;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800730 grpc_call_execute_op(call, &op);
731 break;
Craig Tiller62ac1552015-01-27 15:41:44 -0800732 }
Craig Tillercce17ac2015-01-20 09:29:28 -0800733}
734
735static grpc_call_error start_ioreq_error(grpc_call *call,
736 gpr_uint32 mutated_ops,
737 grpc_call_error ret) {
738 size_t i;
739 for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
Craig Tillerd642dcf2015-02-03 20:39:09 -0800740 if (mutated_ops & (1u << i)) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800741 call->request_set[i] = REQSET_EMPTY;
Craig Tillercce17ac2015-01-20 09:29:28 -0800742 }
743 }
Craig Tillercce17ac2015-01-20 09:29:28 -0800744 return ret;
745}
746
Craig Tillerc12fee62015-02-03 11:55:50 -0800747static void finish_read_ops(grpc_call *call) {
748 int empty;
749
750 if (is_op_live(call, GRPC_IOREQ_RECV_MESSAGE)) {
751 empty =
752 (NULL == (*call->request_data[GRPC_IOREQ_RECV_MESSAGE].recv_message =
753 grpc_bbq_pop(&call->incoming_queue)));
754 if (!empty) {
755 finish_live_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_OK);
756 empty = grpc_bbq_empty(&call->incoming_queue);
757 }
758 } else {
759 empty = grpc_bbq_empty(&call->incoming_queue);
760 }
761
762 switch (call->read_state) {
763 case READ_STATE_STREAM_CLOSED:
764 if (empty) {
765 finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, GRPC_OP_OK);
766 }
767 /* fallthrough */
768 case READ_STATE_READ_CLOSED:
769 if (empty) {
770 finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_OK);
771 }
772 finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, GRPC_OP_OK);
Craig Tillerfb189f82015-02-03 12:07:07 -0800773 finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, GRPC_OP_OK);
Craig Tillerc12fee62015-02-03 11:55:50 -0800774 finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, GRPC_OP_OK);
775 /* fallthrough */
776 case READ_STATE_GOT_INITIAL_METADATA:
777 finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_OK);
778 /* fallthrough */
779 case READ_STATE_INITIAL:
780 /* do nothing */
781 break;
782 }
783}
784
785static void early_out_write_ops(grpc_call *call) {
786 switch (call->write_state) {
787 case WRITE_STATE_WRITE_CLOSED:
788 finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, GRPC_OP_ERROR);
789 finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, GRPC_OP_ERROR);
790 finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, GRPC_OP_ERROR);
791 finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, GRPC_OP_OK);
792 /* fallthrough */
793 case WRITE_STATE_STARTED:
794 finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, GRPC_OP_ERROR);
795 /* fallthrough */
796 case WRITE_STATE_INITIAL:
797 /* do nothing */
798 break;
799 }
800}
801
Craig Tiller8eb9d472015-01-27 17:00:03 -0800802static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
803 size_t nreqs,
804 grpc_ioreq_completion_func completion,
Craig Tiller9cc61412015-02-02 14:02:52 -0800805 void *user_data) {
Craig Tillercce17ac2015-01-20 09:29:28 -0800806 size_t i;
807 gpr_uint32 have_ops = 0;
Craig Tillercce17ac2015-01-20 09:29:28 -0800808 grpc_ioreq_op op;
Craig Tillerc18c56e2015-02-02 15:59:13 -0800809 reqinfo_master *master;
Craig Tillercce17ac2015-01-20 09:29:28 -0800810 grpc_ioreq_data data;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800811 gpr_uint8 set;
812
813 if (nreqs == 0) {
814 return GRPC_CALL_OK;
815 }
816
817 set = reqs[0].op;
Craig Tillercce17ac2015-01-20 09:29:28 -0800818
819 for (i = 0; i < nreqs; i++) {
820 op = reqs[i].op;
Craig Tillerc12fee62015-02-03 11:55:50 -0800821 if (call->request_set[op] < GRPC_IOREQ_OP_COUNT) {
Craig Tillercce17ac2015-01-20 09:29:28 -0800822 return start_ioreq_error(call, have_ops,
823 GRPC_CALL_ERROR_TOO_MANY_OPERATIONS);
Craig Tillerc12fee62015-02-03 11:55:50 -0800824 } else if (call->request_set[op] == REQSET_DONE) {
Craig Tiller1c141902015-01-31 08:51:54 -0800825 return start_ioreq_error(call, have_ops, GRPC_CALL_ERROR_ALREADY_INVOKED);
Craig Tillercce17ac2015-01-20 09:29:28 -0800826 }
Craig Tillerd642dcf2015-02-03 20:39:09 -0800827 have_ops |= 1u << op;
Craig Tillercce17ac2015-01-20 09:29:28 -0800828 data = reqs[i].data;
829
Craig Tillerc12fee62015-02-03 11:55:50 -0800830 call->request_data[op] = data;
831 call->request_set[op] = set;
Craig Tillercce17ac2015-01-20 09:29:28 -0800832 }
833
Craig Tillerc18c56e2015-02-02 15:59:13 -0800834 master = &call->masters[set];
835 master->status = GRPC_OP_OK;
Craig Tillercce17ac2015-01-20 09:29:28 -0800836 master->need_mask = have_ops;
Craig Tiller1b409442015-01-29 14:36:17 -0800837 master->complete_mask = 0;
Craig Tillercce17ac2015-01-20 09:29:28 -0800838 master->on_complete = completion;
839 master->user_data = user_data;
840
Craig Tillerd642dcf2015-02-03 20:39:09 -0800841 if (have_ops & (1u << GRPC_IOREQ_RECV_MESSAGE)) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800842 call->need_more_data = 1;
Craig Tiller23aa6c42015-01-27 17:16:12 -0800843 }
844
Craig Tillerc12fee62015-02-03 11:55:50 -0800845 finish_read_ops(call);
846 early_out_write_ops(call);
847
Craig Tillercce17ac2015-01-20 09:29:28 -0800848 return GRPC_CALL_OK;
849}
850
Craig Tillercce17ac2015-01-20 09:29:28 -0800851grpc_call_error grpc_call_start_ioreq_and_call_back(
852 grpc_call *call, const grpc_ioreq *reqs, size_t nreqs,
853 grpc_ioreq_completion_func on_complete, void *user_data) {
Craig Tiller8eb9d472015-01-27 17:00:03 -0800854 grpc_call_error err;
855 lock(call);
Craig Tiller9cc61412015-02-02 14:02:52 -0800856 err = start_ioreq(call, reqs, nreqs, on_complete, user_data);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800857 unlock(call);
858 return err;
Craig Tillercce17ac2015-01-20 09:29:28 -0800859}
860
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800861void grpc_call_destroy(grpc_call *c) {
ctillerc6d61c42014-12-15 14:52:08 -0800862 int cancel;
Craig Tiller9724de82015-01-28 17:06:29 -0800863 lock(c);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800864 if (c->have_alarm) {
ctiller18b49ab2014-12-09 14:39:16 -0800865 grpc_alarm_cancel(&c->alarm);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800866 c->have_alarm = 0;
867 }
Craig Tillerdaceea82015-02-02 16:15:53 -0800868 cancel = c->read_state != READ_STATE_STREAM_CLOSED;
Craig Tiller9724de82015-01-28 17:06:29 -0800869 unlock(c);
ctillerc6d61c42014-12-15 14:52:08 -0800870 if (cancel) grpc_call_cancel(c);
Craig Tilleraef25da2015-01-29 17:19:45 -0800871 grpc_call_internal_unref(c, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800872}
873
874grpc_call_error grpc_call_cancel(grpc_call *c) {
875 grpc_call_element *elem;
876 grpc_call_op op;
877
878 op.type = GRPC_CANCEL_OP;
879 op.dir = GRPC_CALL_DOWN;
880 op.flags = 0;
881 op.done_cb = do_nothing;
882 op.user_data = NULL;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700883 op.bind_pollset = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800884
885 elem = CALL_ELEM_FROM_CALL(c, 0);
ctillerf962f522014-12-10 15:28:27 -0800886 elem->filter->call_op(elem, NULL, &op);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800887
888 return GRPC_CALL_OK;
889}
890
Craig Tiller6046dc32015-01-14 12:55:45 -0800891grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
892 grpc_status_code status,
893 const char *description) {
894 grpc_mdstr *details =
895 description ? grpc_mdstr_from_string(c->metadata_context, description)
896 : NULL;
Craig Tiller9724de82015-01-28 17:06:29 -0800897 lock(c);
Craig Tiller68752722015-01-29 14:59:54 -0800898 set_status_code(c, STATUS_FROM_API_OVERRIDE, status);
899 set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
Craig Tiller9724de82015-01-28 17:06:29 -0800900 unlock(c);
Craig Tillerd248c242015-01-14 11:49:12 -0800901 return grpc_call_cancel(c);
902}
903
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800904void grpc_call_execute_op(grpc_call *call, grpc_call_op *op) {
905 grpc_call_element *elem;
906 GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
907 elem = CALL_ELEM_FROM_CALL(call, 0);
ctillerf962f522014-12-10 15:28:27 -0800908 elem->filter->call_op(elem, NULL, op);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800909}
910
Craig Tiller566316f2015-02-02 15:25:32 -0800911grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
912 return CALL_FROM_TOP_ELEM(elem);
913}
914
915static void call_alarm(void *arg, int success) {
916 grpc_call *call = arg;
917 if (success) {
918 if (call->is_client) {
919 grpc_call_cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED,
920 "Deadline Exceeded");
921 } else {
922 grpc_call_cancel(call);
923 }
924 }
925 grpc_call_internal_unref(call, 1);
926}
927
Craig Tiller6902ad22015-04-16 08:01:49 -0700928static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) {
Craig Tiller566316f2015-02-02 15:25:32 -0800929 if (call->have_alarm) {
930 gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice");
931 }
932 grpc_call_internal_ref(call);
933 call->have_alarm = 1;
934 grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now());
935}
936
Craig Tiller6902ad22015-04-16 08:01:49 -0700937static void set_read_state_locked(grpc_call *call, read_state state) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800938 GPR_ASSERT(call->read_state < state);
939 call->read_state = state;
940 finish_read_ops(call);
Craig Tiller6902ad22015-04-16 08:01:49 -0700941}
942
943static void set_read_state(grpc_call *call, read_state state) {
944 lock(call);
945 set_read_state_locked(call, state);
Craig Tillerc12fee62015-02-03 11:55:50 -0800946 unlock(call);
Craig Tiller566316f2015-02-02 15:25:32 -0800947}
948
949void grpc_call_read_closed(grpc_call_element *elem) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800950 set_read_state(CALL_FROM_TOP_ELEM(elem), READ_STATE_READ_CLOSED);
Craig Tiller566316f2015-02-02 15:25:32 -0800951}
952
953void grpc_call_stream_closed(grpc_call_element *elem) {
954 grpc_call *call = CALL_FROM_TOP_ELEM(elem);
Craig Tillerc12fee62015-02-03 11:55:50 -0800955 set_read_state(call, READ_STATE_STREAM_CLOSED);
Craig Tiller566316f2015-02-02 15:25:32 -0800956 grpc_call_internal_unref(call, 0);
957}
958
959/* we offset status by a small amount when storing it into transport metadata
960 as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
961 */
962#define STATUS_OFFSET 1
963static void destroy_status(void *ignored) {}
964
965static gpr_uint32 decode_status(grpc_mdelem *md) {
966 gpr_uint32 status;
967 void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
968 if (user_data) {
Craig Tiller87d5b192015-04-16 14:37:57 -0700969 status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET;
Craig Tiller566316f2015-02-02 15:25:32 -0800970 } else {
971 if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
972 GPR_SLICE_LENGTH(md->value->slice),
973 &status)) {
974 status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
975 }
976 grpc_mdelem_set_user_data(md, destroy_status,
977 (void *)(gpr_intptr)(status + STATUS_OFFSET));
978 }
979 return status;
980}
981
982void grpc_call_recv_message(grpc_call_element *elem,
983 grpc_byte_buffer *byte_buffer) {
984 grpc_call *call = CALL_FROM_TOP_ELEM(elem);
985 lock(call);
Craig Tillerc12fee62015-02-03 11:55:50 -0800986 grpc_bbq_push(&call->incoming_queue, byte_buffer);
987 finish_read_ops(call);
Craig Tiller566316f2015-02-02 15:25:32 -0800988 unlock(call);
989}
990
Craig Tiller76f5d462015-04-17 14:58:12 -0700991void grpc_call_recv_synthetic_status(grpc_call_element *elem,
992 grpc_status_code status,
993 const char *message) {
Craig Tiller8b282cb2015-04-17 14:57:44 -0700994 grpc_call *call = CALL_FROM_TOP_ELEM(elem);
995 lock(call);
996 set_status_code(call, STATUS_FROM_CORE, status);
Craig Tiller76f5d462015-04-17 14:58:12 -0700997 set_status_details(call, STATUS_FROM_CORE,
998 grpc_mdstr_from_string(call->metadata_context, message));
Craig Tiller8b282cb2015-04-17 14:57:44 -0700999 unlock(call);
1000}
1001
Craig Tiller76f5d462015-04-17 14:58:12 -07001002int grpc_call_recv_metadata(grpc_call_element *elem, grpc_metadata_batch *md) {
Craig Tiller566316f2015-02-02 15:25:32 -08001003 grpc_call *call = CALL_FROM_TOP_ELEM(elem);
Craig Tiller6902ad22015-04-16 08:01:49 -07001004 grpc_linked_mdelem *l;
Craig Tiller566316f2015-02-02 15:25:32 -08001005 grpc_metadata_array *dest;
1006 grpc_metadata *mdusr;
Craig Tiller6902ad22015-04-16 08:01:49 -07001007 int is_trailing;
Craig Tiller8b282cb2015-04-17 14:57:44 -07001008 grpc_mdctx *mdctx = call->metadata_context;
Craig Tiller566316f2015-02-02 15:25:32 -08001009
1010 lock(call);
Craig Tiller6902ad22015-04-16 08:01:49 -07001011 is_trailing = call->read_state >= READ_STATE_GOT_INITIAL_METADATA;
Craig Tiller48b02ec2015-04-21 13:58:36 -07001012 for (l = md->list.head; l != NULL; l = l->next) {
Craig Tiller6902ad22015-04-16 08:01:49 -07001013 grpc_mdelem *md = l->md;
1014 grpc_mdstr *key = md->key;
1015 if (key == grpc_channel_get_status_string(call->channel)) {
1016 set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
Craig Tiller6902ad22015-04-16 08:01:49 -07001017 } else if (key == grpc_channel_get_message_string(call->channel)) {
1018 set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
Craig Tiller6902ad22015-04-16 08:01:49 -07001019 } else {
1020 dest = &call->buffered_metadata[is_trailing];
1021 if (dest->count == dest->capacity) {
1022 dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
1023 dest->metadata =
1024 gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
1025 }
1026 mdusr = &dest->metadata[dest->count++];
1027 mdusr->key = grpc_mdstr_as_c_string(md->key);
1028 mdusr->value = grpc_mdstr_as_c_string(md->value);
1029 mdusr->value_length = GPR_SLICE_LENGTH(md->value->slice);
1030 if (call->owned_metadata_count == call->owned_metadata_capacity) {
Craig Tiller87d5b192015-04-16 14:37:57 -07001031 call->owned_metadata_capacity =
1032 GPR_MAX(call->owned_metadata_capacity + 8,
1033 call->owned_metadata_capacity * 2);
Craig Tiller6902ad22015-04-16 08:01:49 -07001034 call->owned_metadata =
1035 gpr_realloc(call->owned_metadata,
1036 sizeof(grpc_mdelem *) * call->owned_metadata_capacity);
1037 }
1038 call->owned_metadata[call->owned_metadata_count++] = md;
Craig Tiller8b282cb2015-04-17 14:57:44 -07001039 l->md = 0;
Craig Tiller566316f2015-02-02 15:25:32 -08001040 }
Craig Tiller6902ad22015-04-16 08:01:49 -07001041 }
1042 if (gpr_time_cmp(md->deadline, gpr_inf_future) != 0) {
1043 set_deadline_alarm(call, md->deadline);
1044 }
1045 if (!is_trailing) {
1046 set_read_state_locked(call, READ_STATE_GOT_INITIAL_METADATA);
Craig Tiller566316f2015-02-02 15:25:32 -08001047 }
1048 unlock(call);
Craig Tiller6902ad22015-04-16 08:01:49 -07001049
Craig Tiller8b282cb2015-04-17 14:57:44 -07001050 grpc_mdctx_lock(mdctx);
1051 for (l = md->list.head; l; l = l->next) {
1052 if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
1053 }
1054 for (l = md->garbage.head; l; l = l->next) {
1055 grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
1056 }
1057 grpc_mdctx_unlock(mdctx);
1058
Craig Tiller6902ad22015-04-16 08:01:49 -07001059 return !is_trailing;
Craig Tiller566316f2015-02-02 15:25:32 -08001060}
1061
1062grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
1063 return CALL_STACK_FROM_CALL(call);
1064}
1065
1066/*
Craig Tillerfb189f82015-02-03 12:07:07 -08001067 * BATCH API IMPLEMENTATION
1068 */
1069
1070static void set_status_value_directly(grpc_status_code status, void *dest) {
1071 *(grpc_status_code *)dest = status;
1072}
1073
1074static void set_cancelled_value(grpc_status_code status, void *dest) {
1075 *(grpc_status_code *)dest = (status != GRPC_STATUS_OK);
1076}
1077
Craig Tiller166e2502015-02-03 20:14:41 -08001078static void finish_batch(grpc_call *call, grpc_op_error result, void *tag) {
1079 grpc_cq_end_op_complete(call->cq, tag, call, do_nothing, NULL, GRPC_OP_OK);
1080}
Craig Tillerfb189f82015-02-03 12:07:07 -08001081
1082grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
1083 size_t nops, void *tag) {
1084 grpc_ioreq reqs[GRPC_IOREQ_OP_COUNT];
1085 size_t in;
1086 size_t out;
1087 const grpc_op *op;
1088 grpc_ioreq *req;
1089
murgatroid99d47946b2015-03-09 14:27:07 -07001090 GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
1091
murgatroid99a8c21e82015-02-12 13:55:53 -08001092 if (nops == 0) {
1093 grpc_cq_begin_op(call->cq, call, GRPC_OP_COMPLETE);
1094 grpc_cq_end_op_complete(call->cq, tag, call, do_nothing, NULL, GRPC_OP_OK);
1095 return GRPC_CALL_OK;
1096 }
1097
Craig Tillerfb189f82015-02-03 12:07:07 -08001098 /* rewrite batch ops into ioreq ops */
1099 for (in = 0, out = 0; in < nops; in++) {
1100 op = &ops[in];
1101 switch (op->op) {
1102 case GRPC_OP_SEND_INITIAL_METADATA:
1103 req = &reqs[out++];
1104 req->op = GRPC_IOREQ_SEND_INITIAL_METADATA;
1105 req->data.send_metadata.count = op->data.send_initial_metadata.count;
1106 req->data.send_metadata.metadata =
1107 op->data.send_initial_metadata.metadata;
1108 break;
1109 case GRPC_OP_SEND_MESSAGE:
1110 req = &reqs[out++];
1111 req->op = GRPC_IOREQ_SEND_MESSAGE;
1112 req->data.send_message = op->data.send_message;
1113 break;
1114 case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
1115 if (!call->is_client) {
1116 return GRPC_CALL_ERROR_NOT_ON_SERVER;
1117 }
1118 req = &reqs[out++];
1119 req->op = GRPC_IOREQ_SEND_CLOSE;
1120 break;
1121 case GRPC_OP_SEND_STATUS_FROM_SERVER:
1122 if (call->is_client) {
1123 return GRPC_CALL_ERROR_NOT_ON_CLIENT;
1124 }
1125 req = &reqs[out++];
1126 req->op = GRPC_IOREQ_SEND_TRAILING_METADATA;
1127 req->data.send_metadata.count =
1128 op->data.send_status_from_server.trailing_metadata_count;
1129 req->data.send_metadata.metadata =
1130 op->data.send_status_from_server.trailing_metadata;
1131 req = &reqs[out++];
1132 req->op = GRPC_IOREQ_SEND_STATUS;
1133 req->data.send_status.code = op->data.send_status_from_server.status;
1134 req->data.send_status.details =
1135 op->data.send_status_from_server.status_details;
1136 req = &reqs[out++];
1137 req->op = GRPC_IOREQ_SEND_CLOSE;
1138 break;
1139 case GRPC_OP_RECV_INITIAL_METADATA:
1140 if (!call->is_client) {
1141 return GRPC_CALL_ERROR_NOT_ON_SERVER;
1142 }
1143 req = &reqs[out++];
1144 req->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
1145 req->data.recv_metadata = op->data.recv_initial_metadata;
1146 break;
1147 case GRPC_OP_RECV_MESSAGE:
1148 req = &reqs[out++];
1149 req->op = GRPC_IOREQ_RECV_MESSAGE;
1150 req->data.recv_message = op->data.recv_message;
1151 break;
1152 case GRPC_OP_RECV_STATUS_ON_CLIENT:
1153 if (!call->is_client) {
1154 return GRPC_CALL_ERROR_NOT_ON_SERVER;
1155 }
1156 req = &reqs[out++];
1157 req->op = GRPC_IOREQ_RECV_STATUS;
1158 req->data.recv_status.set_value = set_status_value_directly;
1159 req->data.recv_status.user_data = op->data.recv_status_on_client.status;
1160 req = &reqs[out++];
1161 req->op = GRPC_IOREQ_RECV_STATUS_DETAILS;
1162 req->data.recv_status_details.details =
1163 op->data.recv_status_on_client.status_details;
1164 req->data.recv_status_details.details_capacity =
1165 op->data.recv_status_on_client.status_details_capacity;
1166 req = &reqs[out++];
1167 req->op = GRPC_IOREQ_RECV_TRAILING_METADATA;
1168 req->data.recv_metadata =
1169 op->data.recv_status_on_client.trailing_metadata;
1170 req = &reqs[out++];
1171 req->op = GRPC_IOREQ_RECV_CLOSE;
1172 break;
1173 case GRPC_OP_RECV_CLOSE_ON_SERVER:
1174 req = &reqs[out++];
1175 req->op = GRPC_IOREQ_RECV_STATUS;
1176 req->data.recv_status.set_value = set_cancelled_value;
1177 req->data.recv_status.user_data =
1178 op->data.recv_close_on_server.cancelled;
1179 req = &reqs[out++];
1180 req->op = GRPC_IOREQ_RECV_CLOSE;
1181 break;
1182 }
1183 }
1184
1185 grpc_cq_begin_op(call->cq, call, GRPC_OP_COMPLETE);
1186
1187 return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_batch,
1188 tag);
1189}
1190
1191/*
Craig Tiller566316f2015-02-02 15:25:32 -08001192 * LEGACY API IMPLEMENTATION
1193 * All this code will disappear as soon as wrappings are updated
1194 */
1195
1196struct legacy_state {
1197 gpr_uint8 md_out_buffer;
1198 size_t md_out_count[2];
1199 size_t md_out_capacity[2];
1200 grpc_metadata *md_out[2];
1201 grpc_byte_buffer *msg_out;
1202
1203 /* input buffers */
1204 grpc_metadata_array initial_md_in;
1205 grpc_metadata_array trailing_md_in;
1206
1207 size_t details_capacity;
1208 char *details;
1209 grpc_status_code status;
1210
Craig Tiller37bbead2015-02-05 08:43:49 -08001211 char *send_details;
1212
Craig Tiller566316f2015-02-02 15:25:32 -08001213 size_t msg_in_read_idx;
1214 grpc_byte_buffer *msg_in;
1215
1216 void *finished_tag;
1217};
1218
1219static legacy_state *get_legacy_state(grpc_call *call) {
1220 if (call->legacy_state == NULL) {
1221 call->legacy_state = gpr_malloc(sizeof(legacy_state));
1222 memset(call->legacy_state, 0, sizeof(legacy_state));
1223 }
1224 return call->legacy_state;
1225}
1226
1227static void destroy_legacy_state(legacy_state *ls) {
1228 size_t i, j;
1229 for (i = 0; i < 2; i++) {
1230 for (j = 0; j < ls->md_out_count[i]; j++) {
Craig Tiller4f972732015-02-05 12:40:20 -08001231 gpr_free((char *)ls->md_out[i][j].key);
1232 gpr_free((char *)ls->md_out[i][j].value);
Craig Tiller566316f2015-02-02 15:25:32 -08001233 }
1234 gpr_free(ls->md_out[i]);
1235 }
1236 gpr_free(ls->initial_md_in.metadata);
1237 gpr_free(ls->trailing_md_in.metadata);
Craig Tillerea3697b2015-02-05 08:40:18 -08001238 gpr_free(ls->details);
Craig Tiller37bbead2015-02-05 08:43:49 -08001239 gpr_free(ls->send_details);
Craig Tiller566316f2015-02-02 15:25:32 -08001240 gpr_free(ls);
1241}
1242
Craig Tiller40d2a432015-02-02 15:29:14 -08001243grpc_call_error grpc_call_add_metadata_old(grpc_call *call,
1244 grpc_metadata *metadata,
1245 gpr_uint32 flags) {
Craig Tiller62ac1552015-01-27 15:41:44 -08001246 legacy_state *ls;
1247 grpc_metadata *mdout;
1248
Craig Tiller8eb9d472015-01-27 17:00:03 -08001249 lock(call);
Craig Tiller62ac1552015-01-27 15:41:44 -08001250 ls = get_legacy_state(call);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001251
Craig Tiller1c141902015-01-31 08:51:54 -08001252 if (ls->md_out_count[ls->md_out_buffer] ==
1253 ls->md_out_capacity[ls->md_out_buffer]) {
Craig Tillerc689ca32015-01-30 10:59:52 -08001254 ls->md_out_capacity[ls->md_out_buffer] =
Craig Tiller1c141902015-01-31 08:51:54 -08001255 GPR_MAX(ls->md_out_capacity[ls->md_out_buffer] * 3 / 2,
1256 ls->md_out_capacity[ls->md_out_buffer] + 8);
1257 ls->md_out[ls->md_out_buffer] = gpr_realloc(
1258 ls->md_out[ls->md_out_buffer],
1259 sizeof(grpc_metadata) * ls->md_out_capacity[ls->md_out_buffer]);
Craig Tillercce17ac2015-01-20 09:29:28 -08001260 }
Craig Tillerc689ca32015-01-30 10:59:52 -08001261 mdout = &ls->md_out[ls->md_out_buffer][ls->md_out_count[ls->md_out_buffer]++];
Craig Tiller62ac1552015-01-27 15:41:44 -08001262 mdout->key = gpr_strdup(metadata->key);
1263 mdout->value = gpr_malloc(metadata->value_length);
1264 mdout->value_length = metadata->value_length;
Craig Tiller4f972732015-02-05 12:40:20 -08001265 memcpy((char *)mdout->value, metadata->value, metadata->value_length);
klempnerc463f742014-12-19 13:03:35 -08001266
Craig Tiller8eb9d472015-01-27 17:00:03 -08001267 unlock(call);
Craig Tiller62ac1552015-01-27 15:41:44 -08001268
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001269 return GRPC_CALL_OK;
1270}
1271
Craig Tiller50524cc2015-01-29 23:00:00 -08001272static void finish_status(grpc_call *call, grpc_op_error status,
1273 void *ignored) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001274 legacy_state *ls;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001275
Craig Tiller8eb9d472015-01-27 17:00:03 -08001276 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001277 ls = get_legacy_state(call);
Craig Tiller7a9d7922015-01-31 09:35:20 -08001278 grpc_cq_end_finished(call->cq, ls->finished_tag, call, do_nothing, NULL,
1279 ls->status, ls->details, ls->trailing_md_in.metadata,
1280 ls->trailing_md_in.count);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001281 unlock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001282}
Craig Tiller80fa15c2015-01-13 16:10:49 -08001283
Craig Tillercce17ac2015-01-20 09:29:28 -08001284static void finish_recv_metadata(grpc_call *call, grpc_op_error status,
1285 void *tag) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001286 legacy_state *ls;
1287
Craig Tiller8eb9d472015-01-27 17:00:03 -08001288 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001289 ls = get_legacy_state(call);
1290 if (status == GRPC_OP_OK) {
1291 grpc_cq_end_client_metadata_read(call->cq, tag, call, do_nothing, NULL,
Craig Tiller1c141902015-01-31 08:51:54 -08001292 ls->initial_md_in.count,
1293 ls->initial_md_in.metadata);
Craig Tillercce17ac2015-01-20 09:29:28 -08001294
Craig Tiller62ac1552015-01-27 15:41:44 -08001295 } else {
1296 grpc_cq_end_client_metadata_read(call->cq, tag, call, do_nothing, NULL, 0,
1297 NULL);
1298 }
Craig Tiller8eb9d472015-01-27 17:00:03 -08001299 unlock(call);
Craig Tiller62ac1552015-01-27 15:41:44 -08001300}
1301
Craig Tiller50524cc2015-01-29 23:00:00 -08001302static void finish_send_metadata(grpc_call *call, grpc_op_error status,
1303 void *tag) {}
Craig Tiller80fa15c2015-01-13 16:10:49 -08001304
Craig Tiller40d2a432015-02-02 15:29:14 -08001305grpc_call_error grpc_call_invoke_old(grpc_call *call, grpc_completion_queue *cq,
1306 void *metadata_read_tag,
1307 void *finished_tag, gpr_uint32 flags) {
Craig Tillerfb189f82015-02-03 12:07:07 -08001308 grpc_ioreq reqs[4];
Craig Tillerfa8f4012015-01-29 16:16:58 -08001309 legacy_state *ls;
Craig Tillercce17ac2015-01-20 09:29:28 -08001310 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001311
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001312 grpc_cq_begin_op(cq, call, GRPC_CLIENT_METADATA_READ);
Craig Tillercce17ac2015-01-20 09:29:28 -08001313 grpc_cq_begin_op(cq, call, GRPC_FINISHED);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001314
Craig Tiller8eb9d472015-01-27 17:00:03 -08001315 lock(call);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001316 ls = get_legacy_state(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001317 err = bind_cq(call, cq);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001318 if (err != GRPC_CALL_OK) goto done;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001319
Craig Tiller50524cc2015-01-29 23:00:00 -08001320 ls->finished_tag = finished_tag;
1321
Craig Tillerfa8f4012015-01-29 16:16:58 -08001322 reqs[0].op = GRPC_IOREQ_SEND_INITIAL_METADATA;
Craig Tillerc689ca32015-01-30 10:59:52 -08001323 reqs[0].data.send_metadata.count = ls->md_out_count[ls->md_out_buffer];
1324 reqs[0].data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
1325 ls->md_out_buffer++;
Craig Tiller9cc61412015-02-02 14:02:52 -08001326 err = start_ioreq(call, reqs, 1, finish_send_metadata, NULL);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001327 if (err != GRPC_CALL_OK) goto done;
Craig Tiller9724de82015-01-28 17:06:29 -08001328
Craig Tillerfa8f4012015-01-29 16:16:58 -08001329 reqs[0].op = GRPC_IOREQ_RECV_INITIAL_METADATA;
Craig Tiller03d5bf72015-01-30 12:01:30 -08001330 reqs[0].data.recv_metadata = &ls->initial_md_in;
Craig Tiller9cc61412015-02-02 14:02:52 -08001331 err = start_ioreq(call, reqs, 1, finish_recv_metadata, metadata_read_tag);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001332 if (err != GRPC_CALL_OK) goto done;
1333
1334 reqs[0].op = GRPC_IOREQ_RECV_TRAILING_METADATA;
Craig Tiller03d5bf72015-01-30 12:01:30 -08001335 reqs[0].data.recv_metadata = &ls->trailing_md_in;
Craig Tillerfa8f4012015-01-29 16:16:58 -08001336 reqs[1].op = GRPC_IOREQ_RECV_STATUS;
Craig Tillerfb189f82015-02-03 12:07:07 -08001337 reqs[1].data.recv_status.user_data = &ls->status;
1338 reqs[1].data.recv_status.set_value = set_status_value_directly;
1339 reqs[2].op = GRPC_IOREQ_RECV_STATUS_DETAILS;
1340 reqs[2].data.recv_status_details.details = &ls->details;
1341 reqs[2].data.recv_status_details.details_capacity = &ls->details_capacity;
1342 reqs[3].op = GRPC_IOREQ_RECV_CLOSE;
1343 err = start_ioreq(call, reqs, 4, finish_status, NULL);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001344 if (err != GRPC_CALL_OK) goto done;
1345
1346done:
Craig Tiller8eb9d472015-01-27 17:00:03 -08001347 unlock(call);
1348 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001349}
1350
Craig Tiller40d2a432015-02-02 15:29:14 -08001351grpc_call_error grpc_call_server_accept_old(grpc_call *call,
1352 grpc_completion_queue *cq,
1353 void *finished_tag) {
Craig Tiller05140d02015-01-30 16:43:40 -08001354 grpc_ioreq reqs[2];
Craig Tiller8eb9d472015-01-27 17:00:03 -08001355 grpc_call_error err;
Craig Tiller05140d02015-01-30 16:43:40 -08001356 legacy_state *ls;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001357
1358 /* inform the completion queue of an incoming operation (corresponding to
1359 finished_tag) */
1360 grpc_cq_begin_op(cq, call, GRPC_FINISHED);
1361
Craig Tiller8884d7f2015-01-29 10:46:45 -08001362 lock(call);
Craig Tiller05140d02015-01-30 16:43:40 -08001363 ls = get_legacy_state(call);
1364
Craig Tiller8eb9d472015-01-27 17:00:03 -08001365 err = bind_cq(call, cq);
Craig Tiller970781b2015-02-08 14:38:31 -08001366 if (err != GRPC_CALL_OK) {
1367 unlock(call);
1368 return err;
1369 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001370
Craig Tiller05140d02015-01-30 16:43:40 -08001371 ls->finished_tag = finished_tag;
Craig Tiller50524cc2015-01-29 23:00:00 -08001372
Craig Tiller05140d02015-01-30 16:43:40 -08001373 reqs[0].op = GRPC_IOREQ_RECV_STATUS;
Craig Tillerfb189f82015-02-03 12:07:07 -08001374 reqs[0].data.recv_status.user_data = &ls->status;
1375 reqs[0].data.recv_status.set_value = set_status_value_directly;
Craig Tiller05140d02015-01-30 16:43:40 -08001376 reqs[1].op = GRPC_IOREQ_RECV_CLOSE;
Craig Tiller9cc61412015-02-02 14:02:52 -08001377 err = start_ioreq(call, reqs, 2, finish_status, NULL);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001378 unlock(call);
1379 return err;
nnoble0c475f02014-12-05 15:37:39 -08001380}
1381
Craig Tillerabcf6522015-01-28 15:44:24 -08001382static void finish_send_initial_metadata(grpc_call *call, grpc_op_error status,
1383 void *tag) {}
Craig Tiller39fd4282015-01-28 09:12:31 -08001384
Craig Tiller40d2a432015-02-02 15:29:14 -08001385grpc_call_error grpc_call_server_end_initial_metadata_old(grpc_call *call,
1386 gpr_uint32 flags) {
Craig Tiller39fd4282015-01-28 09:12:31 -08001387 grpc_ioreq req;
1388 grpc_call_error err;
1389 legacy_state *ls;
1390
1391 lock(call);
1392 ls = get_legacy_state(call);
1393 req.op = GRPC_IOREQ_SEND_INITIAL_METADATA;
Craig Tillerc689ca32015-01-30 10:59:52 -08001394 req.data.send_metadata.count = ls->md_out_count[ls->md_out_buffer];
1395 req.data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
Craig Tiller9cc61412015-02-02 14:02:52 -08001396 err = start_ioreq(call, &req, 1, finish_send_initial_metadata, NULL);
Craig Tiller39fd4282015-01-28 09:12:31 -08001397 unlock(call);
Craig Tillerabcf6522015-01-28 15:44:24 -08001398
Craig Tiller39fd4282015-01-28 09:12:31 -08001399 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001400}
1401
Craig Tiller68f55a02015-01-30 07:54:48 -08001402static void finish_read_event(void *p, grpc_op_error error) {
Craig Tiller8f4f6e22015-01-31 20:01:37 -08001403 if (p) grpc_byte_buffer_destroy(p);
Craig Tiller68f55a02015-01-30 07:54:48 -08001404}
1405
Craig Tillercce17ac2015-01-20 09:29:28 -08001406static void finish_read(grpc_call *call, grpc_op_error error, void *tag) {
1407 legacy_state *ls;
Craig Tiller05140d02015-01-30 16:43:40 -08001408 grpc_byte_buffer *msg;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001409 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001410 ls = get_legacy_state(call);
Craig Tiller05140d02015-01-30 16:43:40 -08001411 msg = ls->msg_in;
1412 grpc_cq_end_read(call->cq, tag, call, finish_read_event, msg, msg);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001413 unlock(call);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001414}
1415
Craig Tiller40d2a432015-02-02 15:29:14 -08001416grpc_call_error grpc_call_start_read_old(grpc_call *call, void *tag) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001417 legacy_state *ls;
1418 grpc_ioreq req;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001419 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001420
1421 grpc_cq_begin_op(call->cq, call, GRPC_READ);
1422
Craig Tiller8eb9d472015-01-27 17:00:03 -08001423 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001424 ls = get_legacy_state(call);
Craig Tiller05140d02015-01-30 16:43:40 -08001425 req.op = GRPC_IOREQ_RECV_MESSAGE;
1426 req.data.recv_message = &ls->msg_in;
Craig Tiller9cc61412015-02-02 14:02:52 -08001427 err = start_ioreq(call, &req, 1, finish_read, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001428 unlock(call);
1429 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001430}
1431
Craig Tillercce17ac2015-01-20 09:29:28 -08001432static void finish_write(grpc_call *call, grpc_op_error status, void *tag) {
Craig Tillera4541102015-01-29 11:46:11 -08001433 lock(call);
1434 grpc_byte_buffer_destroy(get_legacy_state(call)->msg_out);
1435 unlock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001436 grpc_cq_end_write_accepted(call->cq, tag, call, do_nothing, NULL, status);
1437}
1438
Craig Tiller40d2a432015-02-02 15:29:14 -08001439grpc_call_error grpc_call_start_write_old(grpc_call *call,
1440 grpc_byte_buffer *byte_buffer,
1441 void *tag, gpr_uint32 flags) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001442 grpc_ioreq req;
1443 legacy_state *ls;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001444 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001445
1446 grpc_cq_begin_op(call->cq, call, GRPC_WRITE_ACCEPTED);
1447
Craig Tiller8eb9d472015-01-27 17:00:03 -08001448 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001449 ls = get_legacy_state(call);
Craig Tillera4541102015-01-29 11:46:11 -08001450 ls->msg_out = grpc_byte_buffer_copy(byte_buffer);
Craig Tiller05140d02015-01-30 16:43:40 -08001451 req.op = GRPC_IOREQ_SEND_MESSAGE;
1452 req.data.send_message = ls->msg_out;
Craig Tiller9cc61412015-02-02 14:02:52 -08001453 err = start_ioreq(call, &req, 1, finish_write, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001454 unlock(call);
1455
1456 return err;
Craig Tillercce17ac2015-01-20 09:29:28 -08001457}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001458
Craig Tillercce17ac2015-01-20 09:29:28 -08001459static void finish_finish(grpc_call *call, grpc_op_error status, void *tag) {
1460 grpc_cq_end_finish_accepted(call->cq, tag, call, do_nothing, NULL, status);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001461}
1462
Craig Tiller40d2a432015-02-02 15:29:14 -08001463grpc_call_error grpc_call_writes_done_old(grpc_call *call, void *tag) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001464 grpc_ioreq req;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001465 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001466 grpc_cq_begin_op(call->cq, call, GRPC_FINISH_ACCEPTED);
1467
Craig Tiller8eb9d472015-01-27 17:00:03 -08001468 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001469 req.op = GRPC_IOREQ_SEND_CLOSE;
Craig Tiller9cc61412015-02-02 14:02:52 -08001470 err = start_ioreq(call, &req, 1, finish_finish, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001471 unlock(call);
1472
1473 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001474}
1475
Craig Tiller40d2a432015-02-02 15:29:14 -08001476grpc_call_error grpc_call_start_write_status_old(grpc_call *call,
1477 grpc_status_code status,
1478 const char *details,
1479 void *tag) {
Craig Tiller05140d02015-01-30 16:43:40 -08001480 grpc_ioreq reqs[3];
Craig Tiller8eb9d472015-01-27 17:00:03 -08001481 grpc_call_error err;
Craig Tillerfa8f4012015-01-29 16:16:58 -08001482 legacy_state *ls;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001483 grpc_cq_begin_op(call->cq, call, GRPC_FINISH_ACCEPTED);
1484
Craig Tiller8eb9d472015-01-27 17:00:03 -08001485 lock(call);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001486 ls = get_legacy_state(call);
Craig Tillerf31d14c2015-01-28 09:26:42 -08001487 reqs[0].op = GRPC_IOREQ_SEND_TRAILING_METADATA;
Craig Tillerc689ca32015-01-30 10:59:52 -08001488 reqs[0].data.send_metadata.count = ls->md_out_count[ls->md_out_buffer];
1489 reqs[0].data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
Craig Tiller1c141902015-01-31 08:51:54 -08001490 reqs[1].op = GRPC_IOREQ_SEND_STATUS;
Craig Tiller05140d02015-01-30 16:43:40 -08001491 reqs[1].data.send_status.code = status;
Craig Tiller37bbead2015-02-05 08:43:49 -08001492 reqs[1].data.send_status.details = ls->send_details = gpr_strdup(details);
Craig Tiller1c141902015-01-31 08:51:54 -08001493 reqs[2].op = GRPC_IOREQ_SEND_CLOSE;
Craig Tiller9cc61412015-02-02 14:02:52 -08001494 err = start_ioreq(call, reqs, 3, finish_finish, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001495 unlock(call);
1496
1497 return err;
Craig Tiller190d3602015-02-18 09:23:38 -08001498}