blob: a65bfb8903968ca5b6deff23e636af766d2ba6de [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 Tiller58ce3f02015-04-22 07:54:24 -070084 gpr_uint16 need_mask;
Craig Tillerdaceea82015-02-02 16:15:53 -080085 /* a bit mask of which request ops are now completed */
Craig Tiller58ce3f02015-04-22 07:54:24 -070086 gpr_uint16 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 Tiller629b0ed2015-04-22 11:14:26 -0700147 /* are we currently performing a recv operation */
148 gpr_uint8 receiving;
Craig Tiller991ca9f2015-03-03 09:59:22 -0800149 /* are we currently completing requests */
150 gpr_uint8 completing;
Craig Tillere5d683c2015-02-03 16:37:36 -0800151 /* pairs with completed_requests */
Craig Tiller8eb9d472015-01-27 17:00:03 -0800152 gpr_uint8 num_completed_requests;
Craig Tiller629b0ed2015-04-22 11:14:26 -0700153 /* are we currently reading a message? */
154 gpr_uint8 reading_message;
Craig Tiller83f88d92015-04-21 16:02:05 -0700155 /* flags with bits corresponding to write states allowing us to determine
156 what was sent */
Craig Tiller58ce3f02015-04-22 07:54:24 -0700157 gpr_uint16 last_send_contains;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800158
Craig Tillere5d683c2015-02-03 16:37:36 -0800159 /* Active ioreqs.
160 request_set and request_data contain one element per active ioreq
161 operation.
Craig Tillerebf94bf2015-02-05 08:48:46 -0800162
Craig Tillere5d683c2015-02-03 16:37:36 -0800163 request_set[op] is an integer specifying a set of operations to which
164 the request belongs:
Craig Tillerebf94bf2015-02-05 08:48:46 -0800165 - if it is < GRPC_IOREQ_OP_COUNT, then this operation is pending
Craig Tillere5d683c2015-02-03 16:37:36 -0800166 completion, and the integer represents to which group of operations
167 the ioreq belongs. Each group is represented by one master, and the
168 integer in request_set is an index into masters to find the master
169 data.
170 - if it is REQSET_EMPTY, the ioreq op is inactive and available to be
171 started
172 - finally, if request_set[op] is REQSET_DONE, then the operation is
173 complete and unavailable to be started again
Craig Tillerebf94bf2015-02-05 08:48:46 -0800174
Craig Tillere5d683c2015-02-03 16:37:36 -0800175 request_data[op] is the request data as supplied by the initiator of
176 a request, and is valid iff request_set[op] <= GRPC_IOREQ_OP_COUNT.
177 The set fields are as per the request type specified by op.
178
Craig Tillerd6731622015-02-03 22:44:13 -0800179 Finally, one element of masters is set per active _set_ of ioreq
Craig Tillere5d683c2015-02-03 16:37:36 -0800180 operations. It describes work left outstanding, result status, and
181 what work to perform upon operation completion. As one ioreq of each
182 op type can be active at once, by convention we choose the first element
Craig Tillerd6731622015-02-03 22:44:13 -0800183 of the group to be the master -- ie the master of in-progress operation
184 op is masters[request_set[op]]. This allows constant time allocation
Craig Tillere5d683c2015-02-03 16:37:36 -0800185 and a strong upper bound of a count of masters to be calculated. */
Craig Tillerc12fee62015-02-03 11:55:50 -0800186 gpr_uint8 request_set[GRPC_IOREQ_OP_COUNT];
187 grpc_ioreq_data request_data[GRPC_IOREQ_OP_COUNT];
Craig Tillerc18c56e2015-02-02 15:59:13 -0800188 reqinfo_master masters[GRPC_IOREQ_OP_COUNT];
Craig Tillere5d683c2015-02-03 16:37:36 -0800189
190 /* Dynamic array of ioreq's that have completed: the count of
191 elements is queued in num_completed_requests.
192 This list is built up under lock(), and flushed entirely during
193 unlock().
194 We know the upper bound of the number of elements as we can only
195 have one ioreq of each type active at once. */
Craig Tiller8eb9d472015-01-27 17:00:03 -0800196 completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
Craig Tillere5d683c2015-02-03 16:37:36 -0800197 /* Incoming buffer of messages */
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800198 grpc_byte_buffer_queue incoming_queue;
Craig Tillere5d683c2015-02-03 16:37:36 -0800199 /* Buffered read metadata waiting to be returned to the application.
200 Element 0 is initial metadata, element 1 is trailing metadata. */
Craig Tillerc12fee62015-02-03 11:55:50 -0800201 grpc_metadata_array buffered_metadata[2];
Craig Tillere5d683c2015-02-03 16:37:36 -0800202 /* All metadata received - unreffed at once at the end of the call */
Craig Tiller3a4749f2015-01-30 07:51:45 -0800203 grpc_mdelem **owned_metadata;
204 size_t owned_metadata_count;
205 size_t owned_metadata_capacity;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800206
Craig Tillere5d683c2015-02-03 16:37:36 -0800207 /* Received call statuses from various sources */
Craig Tiller68752722015-01-29 14:59:54 -0800208 received_status status[STATUS_SOURCE_COUNT];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800209
Craig Tillere5d683c2015-02-03 16:37:36 -0800210 /* Deadline alarm - if have_alarm is non-zero */
Craig Tillercce17ac2015-01-20 09:29:28 -0800211 grpc_alarm alarm;
212
Craig Tillere5d683c2015-02-03 16:37:36 -0800213 /* Call refcount - to keep the call alive during asynchronous operations */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800214 gpr_refcount internal_refcount;
Craig Tillercce17ac2015-01-20 09:29:28 -0800215
Craig Tiller6902ad22015-04-16 08:01:49 -0700216 grpc_linked_mdelem send_initial_metadata[MAX_SEND_INITIAL_METADATA_COUNT];
217 grpc_linked_mdelem status_link;
218 grpc_linked_mdelem details_link;
219 size_t send_initial_metadata_count;
220 gpr_timespec send_deadline;
221
Craig Tiller83f88d92015-04-21 16:02:05 -0700222 grpc_stream_op_buffer send_ops;
223 grpc_stream_op_buffer recv_ops;
224 grpc_stream_state recv_state;
225
Craig Tiller629b0ed2015-04-22 11:14:26 -0700226 gpr_slice_buffer incoming_message;
227 gpr_uint32 incoming_message_length;
228
Craig Tillerebf94bf2015-02-05 08:48:46 -0800229 /* Data that the legacy api needs to track. To be deleted at some point
Craig Tillere5d683c2015-02-03 16:37:36 -0800230 soon */
Craig Tillercce17ac2015-01-20 09:29:28 -0800231 legacy_state *legacy_state;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800232};
233
Craig Tiller87d5b192015-04-16 14:37:57 -0700234#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800235#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
236#define CALL_ELEM_FROM_CALL(call, idx) \
237 grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
238#define CALL_FROM_TOP_ELEM(top_elem) \
239 CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem))
240
Craig Tillercce17ac2015-01-20 09:29:28 -0800241#define SWAP(type, x, y) \
242 do { \
243 type temp = x; \
244 x = y; \
245 y = temp; \
246 } while (0)
247
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800248static void do_nothing(void *ignored, grpc_op_error also_ignored) {}
Craig Tiller6902ad22015-04-16 08:01:49 -0700249static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline);
Craig Tiller83f88d92015-04-21 16:02:05 -0700250static void call_on_done_recv(void *call, int success);
251static void call_on_done_send(void *call, int success);
252static int fill_send_ops(grpc_call *call, grpc_transport_op *op);
253static void execute_op(grpc_call *call, grpc_transport_op *op);
Craig Tiller629b0ed2015-04-22 11:14:26 -0700254static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata);
255static void finish_read_ops(grpc_call *call);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800256
Craig Tillerfb189f82015-02-03 12:07:07 -0800257grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
Craig Tiller87d5b192015-04-16 14:37:57 -0700258 const void *server_transport_data,
259 grpc_mdelem **add_initial_metadata,
260 size_t add_initial_metadata_count,
261 gpr_timespec send_deadline) {
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800262 size_t i;
Craig Tiller7e8489a2015-04-23 12:41:16 -0700263 grpc_transport_op initial_op;
264 grpc_transport_op *initial_op_ptr = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800265 grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
266 grpc_call *call =
267 gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
Craig Tillercce17ac2015-01-20 09:29:28 -0800268 memset(call, 0, sizeof(grpc_call));
269 gpr_mu_init(&call->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800270 call->channel = channel;
Craig Tillerfb189f82015-02-03 12:07:07 -0800271 call->cq = cq;
Craig Tillercce17ac2015-01-20 09:29:28 -0800272 call->is_client = server_transport_data == NULL;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800273 for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800274 call->request_set[i] = REQSET_EMPTY;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800275 }
Craig Tiller23aa6c42015-01-27 17:16:12 -0800276 if (call->is_client) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800277 call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE;
278 call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE;
Craig Tiller23aa6c42015-01-27 17:16:12 -0800279 }
Craig Tiller6902ad22015-04-16 08:01:49 -0700280 GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT);
281 for (i = 0; i < add_initial_metadata_count; i++) {
282 call->send_initial_metadata[i].md = add_initial_metadata[i];
283 }
284 call->send_initial_metadata_count = add_initial_metadata_count;
285 call->send_deadline = send_deadline;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800286 grpc_channel_internal_ref(channel);
287 call->metadata_context = grpc_channel_get_metadata_context(channel);
Craig Tillerfbf5be22015-04-22 16:17:09 -0700288 grpc_sopb_init(&call->send_ops);
289 grpc_sopb_init(&call->recv_ops);
Craig Tillerfa4f9942015-04-23 15:22:09 -0700290 gpr_slice_buffer_init(&call->incoming_message);
Craig Tiller9c71b6f2015-04-24 16:02:00 -0700291 /* dropped in destroy */
292 gpr_ref_init(&call->internal_refcount, 1);
Craig Tiller7e8489a2015-04-23 12:41:16 -0700293 /* server hack: start reads immediately so we can get initial metadata.
294 TODO(ctiller): figure out a cleaner solution */
295 if (!call->is_client) {
296 memset(&initial_op, 0, sizeof(initial_op));
297 initial_op.recv_ops = &call->recv_ops;
298 initial_op.recv_state = &call->recv_state;
299 initial_op.on_done_recv = call_on_done_recv;
300 initial_op.recv_user_data = call;
301 call->receiving = 1;
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700302 grpc_call_internal_ref(call);
Craig Tiller7e8489a2015-04-23 12:41:16 -0700303 initial_op_ptr = &initial_op;
304 }
305 grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800306 CALL_STACK_FROM_CALL(call));
Craig Tiller6902ad22015-04-16 08:01:49 -0700307 if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) {
308 set_deadline_alarm(call, send_deadline);
309 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800310 return call;
311}
312
Craig Tiller166e2502015-02-03 20:14:41 -0800313void grpc_call_set_completion_queue(grpc_call *call,
314 grpc_completion_queue *cq) {
315 call->cq = cq;
316}
317
Craig Tiller24be0f72015-02-10 14:04:22 -0800318grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
319 return call->cq;
320}
321
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700322void grpc_call_internal_ref(grpc_call *c) {
Craig Tiller916b1522015-04-24 16:00:06 -0700323 gpr_ref(&c->internal_refcount); }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800324
Craig Tilleraef25da2015-01-29 17:19:45 -0800325static void destroy_call(void *call, int ignored_success) {
Craig Tiller566316f2015-02-02 15:25:32 -0800326 size_t i;
Craig Tilleraef25da2015-01-29 17:19:45 -0800327 grpc_call *c = call;
Craig Tillera4541102015-01-29 11:46:11 -0800328 grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
329 grpc_channel_internal_unref(c->channel);
330 gpr_mu_destroy(&c->mu);
Craig Tiller68752722015-01-29 14:59:54 -0800331 for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
332 if (c->status[i].details) {
333 grpc_mdstr_unref(c->status[i].details);
334 }
Craig Tillera4541102015-01-29 11:46:11 -0800335 }
Craig Tiller3a4749f2015-01-30 07:51:45 -0800336 for (i = 0; i < c->owned_metadata_count; i++) {
337 grpc_mdelem_unref(c->owned_metadata[i]);
338 }
339 gpr_free(c->owned_metadata);
Craig Tillerc12fee62015-02-03 11:55:50 -0800340 for (i = 0; i < GPR_ARRAY_SIZE(c->buffered_metadata); i++) {
341 gpr_free(c->buffered_metadata[i].metadata);
342 }
Craig Tillereb40a532015-04-17 16:46:20 -0700343 for (i = 0; i < c->send_initial_metadata_count; i++) {
344 grpc_mdelem_unref(c->send_initial_metadata[i].md);
345 }
Craig Tillera4541102015-01-29 11:46:11 -0800346 if (c->legacy_state) {
Craig Tiller566316f2015-02-02 15:25:32 -0800347 destroy_legacy_state(c->legacy_state);
Craig Tillera4541102015-01-29 11:46:11 -0800348 }
Craig Tiller37bbead2015-02-05 08:43:49 -0800349 grpc_bbq_destroy(&c->incoming_queue);
Craig Tillerfbf5be22015-04-22 16:17:09 -0700350 grpc_sopb_destroy(&c->send_ops);
351 grpc_sopb_destroy(&c->recv_ops);
Craig Tillerfa4f9942015-04-23 15:22:09 -0700352 gpr_slice_buffer_destroy(&c->incoming_message);
Craig Tillera4541102015-01-29 11:46:11 -0800353 gpr_free(c);
354}
355
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700356void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800357 if (gpr_unref(&c->internal_refcount)) {
Craig Tilleraef25da2015-01-29 17:19:45 -0800358 if (allow_immediate_deletion) {
359 destroy_call(c, 1);
360 } else {
361 grpc_iomgr_add_callback(destroy_call, c);
362 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800363 }
364}
365
Craig Tiller928fbc82015-01-29 15:06:42 -0800366static void set_status_code(grpc_call *call, status_source source,
367 gpr_uint32 status) {
Craig Tiller8b976d02015-02-05 21:41:23 -0800368 int flush;
369
Craig Tillerdaceea82015-02-02 16:15:53 -0800370 call->status[source].is_set = 1;
Craig Tiller68752722015-01-29 14:59:54 -0800371 call->status[source].code = status;
Craig Tiller30547562015-02-05 17:04:51 -0800372
Craig Tiller8b976d02015-02-05 21:41:23 -0800373 if (call->is_client) {
374 flush = status == GRPC_STATUS_CANCELLED;
375 } else {
376 flush = status != GRPC_STATUS_OK;
377 }
378
379 if (flush && !grpc_bbq_empty(&call->incoming_queue)) {
Craig Tiller30547562015-02-05 17:04:51 -0800380 grpc_bbq_flush(&call->incoming_queue);
381 }
Craig Tiller68752722015-01-29 14:59:54 -0800382}
383
Craig Tiller928fbc82015-01-29 15:06:42 -0800384static void set_status_details(grpc_call *call, status_source source,
385 grpc_mdstr *status) {
Craig Tiller68752722015-01-29 14:59:54 -0800386 if (call->status[source].details != NULL) {
387 grpc_mdstr_unref(call->status[source].details);
388 }
389 call->status[source].details = status;
390}
391
Craig Tillercce17ac2015-01-20 09:29:28 -0800392static grpc_call_error bind_cq(grpc_call *call, grpc_completion_queue *cq) {
393 if (call->cq) return GRPC_CALL_ERROR_ALREADY_INVOKED;
394 call->cq = cq;
395 return GRPC_CALL_OK;
396}
397
Craig Tillerc12fee62015-02-03 11:55:50 -0800398static int is_op_live(grpc_call *call, grpc_ioreq_op op) {
399 gpr_uint8 set = call->request_set[op];
400 reqinfo_master *master;
401 if (set >= GRPC_IOREQ_OP_COUNT) return 0;
402 master = &call->masters[set];
Craig Tillerd642dcf2015-02-03 20:39:09 -0800403 return (master->complete_mask & (1u << op)) == 0;
Craig Tillerc12fee62015-02-03 11:55:50 -0800404}
405
Craig Tiller8eb9d472015-01-27 17:00:03 -0800406static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); }
Craig Tillercce17ac2015-01-20 09:29:28 -0800407
Craig Tiller629b0ed2015-04-22 11:14:26 -0700408static int need_more_data(grpc_call *call) {
409 return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) ||
410 is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) ||
411 is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) ||
412 is_op_live(call, GRPC_IOREQ_RECV_STATUS) ||
413 is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) ||
Craig Tiller65f9f812015-04-24 16:53:20 -0700414 (is_op_live(call, GRPC_IOREQ_RECV_CLOSE) && grpc_bbq_empty(&call->incoming_queue)) ||
Craig Tiller916b1522015-04-24 16:00:06 -0700415 (call->write_state == WRITE_STATE_INITIAL && !call->is_client && call->read_state != READ_STATE_STREAM_CLOSED);
Craig Tiller629b0ed2015-04-22 11:14:26 -0700416}
417
Craig Tiller8eb9d472015-01-27 17:00:03 -0800418static void unlock(grpc_call *call) {
Craig Tiller83f88d92015-04-21 16:02:05 -0700419 grpc_transport_op op;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800420 completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
Craig Tiller991ca9f2015-03-03 09:59:22 -0800421 int completing_requests = 0;
Craig Tiller83f88d92015-04-21 16:02:05 -0700422 int start_op = 0;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800423 int i;
424
Craig Tiller83f88d92015-04-21 16:02:05 -0700425 memset(&op, 0, sizeof(op));
426
Craig Tiller1a727fd2015-04-24 13:21:22 -0700427 if (!call->receiving && need_more_data(call)) {
Craig Tiller83f88d92015-04-21 16:02:05 -0700428 op.recv_ops = &call->recv_ops;
429 op.recv_state = &call->recv_state;
430 op.on_done_recv = call_on_done_recv;
431 op.recv_user_data = call;
Craig Tiller629b0ed2015-04-22 11:14:26 -0700432 call->receiving = 1;
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700433 grpc_call_internal_ref(call);
Craig Tiller83f88d92015-04-21 16:02:05 -0700434 start_op = 1;
435 }
436
437 if (!call->sending) {
438 if (fill_send_ops(call, &op)) {
439 call->sending = 1;
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700440 grpc_call_internal_ref(call);
Craig Tiller83f88d92015-04-21 16:02:05 -0700441 start_op = 1;
442 }
Craig Tillercffbcb72015-01-29 23:16:33 -0800443 }
Craig Tiller2e103572015-01-29 14:12:07 -0800444
Craig Tiller991ca9f2015-03-03 09:59:22 -0800445 if (!call->completing && call->num_completed_requests != 0) {
446 completing_requests = call->num_completed_requests;
Craig Tiller8eb9d472015-01-27 17:00:03 -0800447 memcpy(completed_requests, call->completed_requests,
448 sizeof(completed_requests));
449 call->num_completed_requests = 0;
Craig Tiller991ca9f2015-03-03 09:59:22 -0800450 call->completing = 1;
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700451 grpc_call_internal_ref(call);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800452 }
453
Craig Tiller8eb9d472015-01-27 17:00:03 -0800454 gpr_mu_unlock(&call->mu);
455
Craig Tiller83f88d92015-04-21 16:02:05 -0700456 if (start_op) {
457 execute_op(call, &op);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800458 }
459
Craig Tiller991ca9f2015-03-03 09:59:22 -0800460 if (completing_requests > 0) {
461 for (i = 0; i < completing_requests; i++) {
462 completed_requests[i].on_complete(call, completed_requests[i].status,
463 completed_requests[i].user_data);
464 }
465 lock(call);
466 call->completing = 0;
467 unlock(call);
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700468 grpc_call_internal_unref(call, 0);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800469 }
470}
Craig Tillercce17ac2015-01-20 09:29:28 -0800471
Craig Tillerfb189f82015-02-03 12:07:07 -0800472static void get_final_status(grpc_call *call, grpc_ioreq_data out) {
Craig Tiller68752722015-01-29 14:59:54 -0800473 int i;
474 for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
Craig Tillerdaceea82015-02-02 16:15:53 -0800475 if (call->status[i].is_set) {
Craig Tillerfb189f82015-02-03 12:07:07 -0800476 out.recv_status.set_value(call->status[i].code,
477 out.recv_status.user_data);
478 return;
479 }
480 }
Craig Tillerde343162015-02-09 23:37:22 -0800481 if (call->is_client) {
482 out.recv_status.set_value(GRPC_STATUS_UNKNOWN, out.recv_status.user_data);
483 } else {
484 out.recv_status.set_value(GRPC_STATUS_OK, out.recv_status.user_data);
485 }
Craig Tillerfb189f82015-02-03 12:07:07 -0800486}
487
488static void get_final_details(grpc_call *call, grpc_ioreq_data out) {
489 int i;
490 for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
491 if (call->status[i].is_set) {
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800492 if (call->status[i].details) {
493 gpr_slice details = call->status[i].details->slice;
494 size_t len = GPR_SLICE_LENGTH(details);
Craig Tillerfb189f82015-02-03 12:07:07 -0800495 if (len + 1 > *out.recv_status_details.details_capacity) {
496 *out.recv_status_details.details_capacity = GPR_MAX(
497 len + 1, *out.recv_status_details.details_capacity * 3 / 2);
498 *out.recv_status_details.details =
499 gpr_realloc(*out.recv_status_details.details,
500 *out.recv_status_details.details_capacity);
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800501 }
Craig Tillerfb189f82015-02-03 12:07:07 -0800502 memcpy(*out.recv_status_details.details, GPR_SLICE_START_PTR(details),
503 len);
504 (*out.recv_status_details.details)[len] = 0;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800505 } else {
506 goto no_details;
507 }
Craig Tiller68752722015-01-29 14:59:54 -0800508 return;
509 }
510 }
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800511
512no_details:
Craig Tillerfb189f82015-02-03 12:07:07 -0800513 if (0 == *out.recv_status_details.details_capacity) {
514 *out.recv_status_details.details_capacity = 8;
515 *out.recv_status_details.details =
516 gpr_malloc(*out.recv_status_details.details_capacity);
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800517 }
Craig Tillerfb189f82015-02-03 12:07:07 -0800518 **out.recv_status_details.details = 0;
Craig Tiller68752722015-01-29 14:59:54 -0800519}
520
Craig Tillerc12fee62015-02-03 11:55:50 -0800521static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op,
522 grpc_op_error status) {
523 completed_request *cr;
524 gpr_uint8 master_set = call->request_set[op];
525 reqinfo_master *master;
526 size_t i;
527 /* ioreq is live: we need to do something */
528 master = &call->masters[master_set];
Craig Tillerd642dcf2015-02-03 20:39:09 -0800529 master->complete_mask |= 1u << op;
Craig Tillerc12fee62015-02-03 11:55:50 -0800530 if (status != GRPC_OP_OK) {
531 master->status = status;
Craig Tillerc12fee62015-02-03 11:55:50 -0800532 }
533 if (master->complete_mask == master->need_mask) {
534 for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
535 if (call->request_set[i] != master_set) {
536 continue;
537 }
538 call->request_set[i] = REQSET_DONE;
539 switch ((grpc_ioreq_op)i) {
540 case GRPC_IOREQ_RECV_MESSAGE:
541 case GRPC_IOREQ_SEND_MESSAGE:
542 if (master->status == GRPC_OP_OK) {
543 call->request_set[i] = REQSET_EMPTY;
544 } else {
545 call->write_state = WRITE_STATE_WRITE_CLOSED;
546 }
547 break;
548 case GRPC_IOREQ_RECV_CLOSE:
549 case GRPC_IOREQ_SEND_INITIAL_METADATA:
550 case GRPC_IOREQ_SEND_TRAILING_METADATA:
551 case GRPC_IOREQ_SEND_STATUS:
552 case GRPC_IOREQ_SEND_CLOSE:
553 break;
554 case GRPC_IOREQ_RECV_STATUS:
Craig Tillerfb189f82015-02-03 12:07:07 -0800555 get_final_status(call, call->request_data[GRPC_IOREQ_RECV_STATUS]);
556 break;
557 case GRPC_IOREQ_RECV_STATUS_DETAILS:
558 get_final_details(call,
559 call->request_data[GRPC_IOREQ_RECV_STATUS_DETAILS]);
Craig Tillerc12fee62015-02-03 11:55:50 -0800560 break;
561 case GRPC_IOREQ_RECV_INITIAL_METADATA:
562 SWAP(grpc_metadata_array, call->buffered_metadata[0],
563 *call->request_data[GRPC_IOREQ_RECV_INITIAL_METADATA]
564 .recv_metadata);
565 break;
566 case GRPC_IOREQ_RECV_TRAILING_METADATA:
567 SWAP(grpc_metadata_array, call->buffered_metadata[1],
568 *call->request_data[GRPC_IOREQ_RECV_TRAILING_METADATA]
569 .recv_metadata);
570 break;
571 case GRPC_IOREQ_OP_COUNT:
572 abort();
573 break;
574 }
575 }
576 cr = &call->completed_requests[call->num_completed_requests++];
577 cr->status = master->status;
578 cr->on_complete = master->on_complete;
579 cr->user_data = master->user_data;
580 }
581}
582
Craig Tillercce17ac2015-01-20 09:29:28 -0800583static void finish_ioreq_op(grpc_call *call, grpc_ioreq_op op,
584 grpc_op_error status) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800585 if (is_op_live(call, op)) {
586 finish_live_ioreq_op(call, op, status);
Craig Tillercce17ac2015-01-20 09:29:28 -0800587 }
588}
589
Craig Tiller58ce3f02015-04-22 07:54:24 -0700590static void call_on_done_send(void *pc, int success) {
591 grpc_call *call = pc;
592 grpc_op_error error = success ? GRPC_OP_OK : GRPC_OP_ERROR;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800593 lock(call);
Craig Tiller58ce3f02015-04-22 07:54:24 -0700594 if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) {
595 finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, error);
596 }
597 if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) {
598 finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, error);
599 }
600 if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_CLOSE)) {
Craig Tiller6e84aba2015-04-23 15:08:17 -0700601 finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, error);
602 finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, error);
Craig Tiller48b9fde2015-04-24 08:04:59 -0700603 finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, GRPC_OP_OK);
Craig Tiller58ce3f02015-04-22 07:54:24 -0700604 }
Craig Tiller3928c7a2015-04-23 16:00:47 -0700605 call->last_send_contains = 0;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800606 call->sending = 0;
607 unlock(call);
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700608 grpc_call_internal_unref(call, 0);
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800609}
610
Craig Tiller629b0ed2015-04-22 11:14:26 -0700611static void finish_message(grpc_call *call) {
612 /* TODO(ctiller): this could be a lot faster if coded directly */
613 grpc_byte_buffer *byte_buffer = grpc_byte_buffer_create(
614 call->incoming_message.slices, call->incoming_message.count);
615 gpr_slice_buffer_reset_and_unref(&call->incoming_message);
616
617 grpc_bbq_push(&call->incoming_queue, byte_buffer);
618
619 GPR_ASSERT(call->incoming_message.count == 0);
620 call->reading_message = 0;
621}
622
623static int begin_message(grpc_call *call, grpc_begin_message msg) {
624 /* can't begin a message when we're still reading a message */
625 if (call->reading_message) {
626 char *message = NULL;
627 gpr_asprintf(
628 &message, "Message terminated early; read %d bytes, expected %d",
629 (int)call->incoming_message.length, (int)call->incoming_message_length);
630 grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
631 gpr_free(message);
632 return 0;
633 }
634 /* stash away parameters, and prepare for incoming slices */
635 if (msg.length > grpc_channel_get_max_message_length(call->channel)) {
636 char *message = NULL;
637 gpr_asprintf(
638 &message,
639 "Maximum message length of %d exceeded by a message of length %d",
640 grpc_channel_get_max_message_length(call->channel), msg.length);
641 grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
642 gpr_free(message);
643 return 0;
644 } else if (msg.length > 0) {
645 call->reading_message = 1;
646 call->incoming_message_length = msg.length;
647 return 1;
648 } else {
649 finish_message(call);
650 return 1;
651 }
652}
653
654static int add_slice_to_message(grpc_call *call, gpr_slice slice) {
655 if (GPR_SLICE_LENGTH(slice) == 0) {
656 gpr_slice_unref(slice);
657 return 1;
658 }
659 /* we have to be reading a message to know what to do here */
660 if (!call->reading_message) {
661 grpc_call_cancel_with_status(
662 call, GRPC_STATUS_INVALID_ARGUMENT,
663 "Received payload data while not reading a message");
664 return 0;
665 }
666 /* append the slice to the incoming buffer */
667 gpr_slice_buffer_add(&call->incoming_message, slice);
668 if (call->incoming_message.length > call->incoming_message_length) {
669 /* if we got too many bytes, complain */
670 char *message = NULL;
671 gpr_asprintf(
672 &message, "Receiving message overflow; read %d bytes, expected %d",
673 (int)call->incoming_message.length, (int)call->incoming_message_length);
674 grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
675 gpr_free(message);
676 return 0;
677 } else if (call->incoming_message.length == call->incoming_message_length) {
678 finish_message(call);
679 return 1;
680 } else {
681 return 1;
682 }
683}
684
685static void call_on_done_recv(void *pc, int success) {
686 grpc_call *call = pc;
687 size_t i;
Craig Tiller629b0ed2015-04-22 11:14:26 -0700688 lock(call);
Craig Tiller6e84aba2015-04-23 15:08:17 -0700689 call->receiving = 0;
Craig Tiller48b9fde2015-04-24 08:04:59 -0700690 if (success) {
691 for (i = 0; success && i < call->recv_ops.nops; i++) {
692 grpc_stream_op *op = &call->recv_ops.ops[i];
693 switch (op->type) {
694 case GRPC_NO_OP:
695 break;
696 case GRPC_OP_METADATA:
697 recv_metadata(call, &op->data.metadata);
698 break;
699 case GRPC_OP_BEGIN_MESSAGE:
700 success = begin_message(call, op->data.begin_message);
701 break;
702 case GRPC_OP_SLICE:
703 success = add_slice_to_message(call, op->data.slice);
704 break;
705 }
Craig Tiller629b0ed2015-04-22 11:14:26 -0700706 }
Craig Tiller48b9fde2015-04-24 08:04:59 -0700707 if (call->recv_state == GRPC_STREAM_RECV_CLOSED) {
708 GPR_ASSERT(call->read_state <= READ_STATE_READ_CLOSED);
709 call->read_state = READ_STATE_READ_CLOSED;
710 }
711 if (call->recv_state == GRPC_STREAM_CLOSED) {
712 GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED);
713 call->read_state = READ_STATE_STREAM_CLOSED;
Craig Tiller48b9fde2015-04-24 08:04:59 -0700714 }
715 finish_read_ops(call);
716 } else {
717 finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_ERROR);
718 finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, GRPC_OP_ERROR);
719 finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, GRPC_OP_ERROR);
720 finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, GRPC_OP_ERROR);
721 finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_ERROR);
722 finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, GRPC_OP_ERROR);
Craig Tiller629b0ed2015-04-22 11:14:26 -0700723 }
Craig Tillerc1f75602015-04-24 11:44:53 -0700724 call->recv_ops.nops = 0;
Craig Tiller629b0ed2015-04-22 11:14:26 -0700725 unlock(call);
726
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700727 grpc_call_internal_unref(call, 0);
Craig Tiller629b0ed2015-04-22 11:14:26 -0700728}
729
Craig Tiller83f88d92015-04-21 16:02:05 -0700730static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count,
731 grpc_metadata *metadata) {
732 size_t i;
733 grpc_mdelem_list out;
734 if (count == 0) {
735 out.head = out.tail = NULL;
736 return out;
737 }
738 for (i = 0; i < count; i++) {
739 grpc_metadata *md = &metadata[i];
740 grpc_metadata *next_md = (i == count - 1) ? NULL : &metadata[i + 1];
741 grpc_metadata *prev_md = (i == 0) ? NULL : &metadata[i - 1];
742 grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
Craig Tillerd2b11fa2015-04-21 13:45:19 -0700743 GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
Craig Tiller83f88d92015-04-21 16:02:05 -0700744 l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key,
745 (const gpr_uint8 *)md->value,
746 md->value_length);
747 l->next = next_md ? (grpc_linked_mdelem *)&next_md->internal_data : NULL;
748 l->prev = prev_md ? (grpc_linked_mdelem *)&prev_md->internal_data : NULL;
749 }
750 out.head = (grpc_linked_mdelem *)&(metadata[0].internal_data);
751 out.tail = (grpc_linked_mdelem *)&(metadata[count - 1].internal_data);
752 return out;
753}
754
Craig Tiller629b0ed2015-04-22 11:14:26 -0700755/* Copy the contents of a byte buffer into stream ops */
756static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
757 grpc_stream_op_buffer *sopb) {
758 size_t i;
759
760 switch (byte_buffer->type) {
761 case GRPC_BB_SLICE_BUFFER:
762 for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) {
763 gpr_slice slice = byte_buffer->data.slice_buffer.slices[i];
764 gpr_slice_ref(slice);
765 grpc_sopb_add_slice(sopb, slice);
766 }
767 break;
768 }
769}
770
Craig Tiller83f88d92015-04-21 16:02:05 -0700771static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
772 grpc_ioreq_data data;
773 grpc_metadata_batch mdb;
774 size_t i;
Craig Tiller58ce3f02015-04-22 07:54:24 -0700775 char status_str[GPR_LTOA_MIN_BUFSIZE];
Craig Tiller83f88d92015-04-21 16:02:05 -0700776 GPR_ASSERT(op->send_ops == NULL);
777
778 switch (call->write_state) {
779 case WRITE_STATE_INITIAL:
780 if (!is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) {
781 break;
782 }
783 data = call->request_data[GRPC_IOREQ_SEND_INITIAL_METADATA];
Craig Tiller629b0ed2015-04-22 11:14:26 -0700784 mdb.list = chain_metadata_from_app(call, data.send_metadata.count,
785 data.send_metadata.metadata);
Craig Tiller83f88d92015-04-21 16:02:05 -0700786 mdb.garbage.head = mdb.garbage.tail = NULL;
787 mdb.deadline = call->send_deadline;
788 for (i = 0; i < call->send_initial_metadata_count; i++) {
Craig Tiller629b0ed2015-04-22 11:14:26 -0700789 grpc_metadata_batch_link_head(&mdb, &call->send_initial_metadata[i]);
Craig Tiller83f88d92015-04-21 16:02:05 -0700790 }
791 grpc_sopb_add_metadata(&call->send_ops, mdb);
792 op->send_ops = &call->send_ops;
793 op->bind_pollset = grpc_cq_pollset(call->cq);
Craig Tiller58ce3f02015-04-22 07:54:24 -0700794 call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA;
795 call->write_state = WRITE_STATE_STARTED;
Craig Tillerc1f75602015-04-24 11:44:53 -0700796 call->send_initial_metadata_count = 0;
Craig Tiller629b0ed2015-04-22 11:14:26 -0700797 /* fall through intended */
Craig Tiller83f88d92015-04-21 16:02:05 -0700798 case WRITE_STATE_STARTED:
799 if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) {
800 data = call->request_data[GRPC_IOREQ_SEND_MESSAGE];
Craig Tiller629b0ed2015-04-22 11:14:26 -0700801 grpc_sopb_add_begin_message(
802 &call->send_ops, grpc_byte_buffer_length(data.send_message), 0);
803 copy_byte_buffer_to_stream_ops(data.send_message, &call->send_ops);
Craig Tiller58ce3f02015-04-22 07:54:24 -0700804 op->send_ops = &call->send_ops;
805 call->last_send_contains |= 1 << GRPC_IOREQ_SEND_MESSAGE;
806 }
807 if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
808 op->is_last_send = 1;
809 op->send_ops = &call->send_ops;
810 call->last_send_contains |= 1 << GRPC_IOREQ_SEND_CLOSE;
811 call->write_state = WRITE_STATE_WRITE_CLOSED;
812 if (!call->is_client) {
813 /* send trailing metadata */
814 data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA];
Craig Tiller629b0ed2015-04-22 11:14:26 -0700815 mdb.list = chain_metadata_from_app(call, data.send_metadata.count,
816 data.send_metadata.metadata);
Craig Tiller58ce3f02015-04-22 07:54:24 -0700817 mdb.garbage.head = mdb.garbage.tail = NULL;
Craig Tillerd393f102015-04-23 16:11:51 -0700818 mdb.deadline = gpr_inf_future;
Craig Tiller58ce3f02015-04-22 07:54:24 -0700819 /* send status */
820 /* TODO(ctiller): cache common status values */
821 data = call->request_data[GRPC_IOREQ_SEND_STATUS];
822 gpr_ltoa(data.send_status.code, status_str);
823 grpc_metadata_batch_add_tail(
824 &mdb, &call->status_link,
825 grpc_mdelem_from_metadata_strings(
826 call->metadata_context,
827 grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)),
828 grpc_mdstr_from_string(call->metadata_context, status_str)));
829 if (data.send_status.details) {
830 grpc_metadata_batch_add_tail(
831 &mdb, &call->details_link,
832 grpc_mdelem_from_metadata_strings(
833 call->metadata_context,
Craig Tiller629b0ed2015-04-22 11:14:26 -0700834 grpc_mdstr_ref(
835 grpc_channel_get_message_string(call->channel)),
Craig Tiller58ce3f02015-04-22 07:54:24 -0700836 grpc_mdstr_from_string(call->metadata_context,
837 data.send_status.details)));
838 }
Craig Tiller7e8489a2015-04-23 12:41:16 -0700839 grpc_sopb_add_metadata(&call->send_ops, mdb);
Craig Tillerde648622015-02-05 09:32:10 -0800840 }
Craig Tillerc12fee62015-02-03 11:55:50 -0800841 }
Craig Tiller58ce3f02015-04-22 07:54:24 -0700842 break;
Craig Tillerc12fee62015-02-03 11:55:50 -0800843 case WRITE_STATE_WRITE_CLOSED:
Craig Tiller8eb9d472015-01-27 17:00:03 -0800844 break;
Craig Tiller62ac1552015-01-27 15:41:44 -0800845 }
Craig Tiller58ce3f02015-04-22 07:54:24 -0700846 if (op->send_ops) {
847 op->on_done_send = call_on_done_send;
848 op->send_user_data = call;
849 }
850 return op->send_ops != NULL;
Craig Tillercce17ac2015-01-20 09:29:28 -0800851}
852
853static grpc_call_error start_ioreq_error(grpc_call *call,
854 gpr_uint32 mutated_ops,
855 grpc_call_error ret) {
856 size_t i;
857 for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
Craig Tillerd642dcf2015-02-03 20:39:09 -0800858 if (mutated_ops & (1u << i)) {
Craig Tillerc12fee62015-02-03 11:55:50 -0800859 call->request_set[i] = REQSET_EMPTY;
Craig Tillercce17ac2015-01-20 09:29:28 -0800860 }
861 }
Craig Tillercce17ac2015-01-20 09:29:28 -0800862 return ret;
863}
864
Craig Tillerc12fee62015-02-03 11:55:50 -0800865static void finish_read_ops(grpc_call *call) {
866 int empty;
867
868 if (is_op_live(call, GRPC_IOREQ_RECV_MESSAGE)) {
869 empty =
870 (NULL == (*call->request_data[GRPC_IOREQ_RECV_MESSAGE].recv_message =
871 grpc_bbq_pop(&call->incoming_queue)));
872 if (!empty) {
873 finish_live_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_OK);
874 empty = grpc_bbq_empty(&call->incoming_queue);
875 }
876 } else {
877 empty = grpc_bbq_empty(&call->incoming_queue);
878 }
879
880 switch (call->read_state) {
881 case READ_STATE_STREAM_CLOSED:
882 if (empty) {
883 finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, GRPC_OP_OK);
884 }
885 /* fallthrough */
886 case READ_STATE_READ_CLOSED:
887 if (empty) {
888 finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_OK);
889 }
890 finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, GRPC_OP_OK);
Craig Tillerfb189f82015-02-03 12:07:07 -0800891 finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, GRPC_OP_OK);
Craig Tillerc12fee62015-02-03 11:55:50 -0800892 finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, GRPC_OP_OK);
893 /* fallthrough */
894 case READ_STATE_GOT_INITIAL_METADATA:
895 finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_OK);
896 /* fallthrough */
897 case READ_STATE_INITIAL:
898 /* do nothing */
899 break;
900 }
901}
902
903static void early_out_write_ops(grpc_call *call) {
904 switch (call->write_state) {
905 case WRITE_STATE_WRITE_CLOSED:
906 finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, GRPC_OP_ERROR);
907 finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, GRPC_OP_ERROR);
908 finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, GRPC_OP_ERROR);
909 finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, GRPC_OP_OK);
910 /* fallthrough */
911 case WRITE_STATE_STARTED:
912 finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, GRPC_OP_ERROR);
913 /* fallthrough */
914 case WRITE_STATE_INITIAL:
915 /* do nothing */
916 break;
917 }
918}
919
Craig Tiller8eb9d472015-01-27 17:00:03 -0800920static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
921 size_t nreqs,
922 grpc_ioreq_completion_func completion,
Craig Tiller9cc61412015-02-02 14:02:52 -0800923 void *user_data) {
Craig Tillercce17ac2015-01-20 09:29:28 -0800924 size_t i;
925 gpr_uint32 have_ops = 0;
Craig Tillercce17ac2015-01-20 09:29:28 -0800926 grpc_ioreq_op op;
Craig Tillerc18c56e2015-02-02 15:59:13 -0800927 reqinfo_master *master;
Craig Tillercce17ac2015-01-20 09:29:28 -0800928 grpc_ioreq_data data;
Craig Tiller1e0d4c42015-01-30 16:17:29 -0800929 gpr_uint8 set;
930
931 if (nreqs == 0) {
932 return GRPC_CALL_OK;
933 }
934
935 set = reqs[0].op;
Craig Tillercce17ac2015-01-20 09:29:28 -0800936
937 for (i = 0; i < nreqs; i++) {
938 op = reqs[i].op;
Craig Tillerc12fee62015-02-03 11:55:50 -0800939 if (call->request_set[op] < GRPC_IOREQ_OP_COUNT) {
Craig Tillercce17ac2015-01-20 09:29:28 -0800940 return start_ioreq_error(call, have_ops,
941 GRPC_CALL_ERROR_TOO_MANY_OPERATIONS);
Craig Tillerc12fee62015-02-03 11:55:50 -0800942 } else if (call->request_set[op] == REQSET_DONE) {
Craig Tiller1c141902015-01-31 08:51:54 -0800943 return start_ioreq_error(call, have_ops, GRPC_CALL_ERROR_ALREADY_INVOKED);
Craig Tillercce17ac2015-01-20 09:29:28 -0800944 }
Craig Tillerd642dcf2015-02-03 20:39:09 -0800945 have_ops |= 1u << op;
Craig Tillercce17ac2015-01-20 09:29:28 -0800946 data = reqs[i].data;
947
Craig Tillerc12fee62015-02-03 11:55:50 -0800948 call->request_data[op] = data;
949 call->request_set[op] = set;
Craig Tillercce17ac2015-01-20 09:29:28 -0800950 }
951
Craig Tillerc18c56e2015-02-02 15:59:13 -0800952 master = &call->masters[set];
953 master->status = GRPC_OP_OK;
Craig Tillercce17ac2015-01-20 09:29:28 -0800954 master->need_mask = have_ops;
Craig Tiller1b409442015-01-29 14:36:17 -0800955 master->complete_mask = 0;
Craig Tillercce17ac2015-01-20 09:29:28 -0800956 master->on_complete = completion;
957 master->user_data = user_data;
958
Craig Tillerc12fee62015-02-03 11:55:50 -0800959 finish_read_ops(call);
960 early_out_write_ops(call);
961
Craig Tillercce17ac2015-01-20 09:29:28 -0800962 return GRPC_CALL_OK;
963}
964
Craig Tillercce17ac2015-01-20 09:29:28 -0800965grpc_call_error grpc_call_start_ioreq_and_call_back(
966 grpc_call *call, const grpc_ioreq *reqs, size_t nreqs,
967 grpc_ioreq_completion_func on_complete, void *user_data) {
Craig Tiller8eb9d472015-01-27 17:00:03 -0800968 grpc_call_error err;
969 lock(call);
Craig Tiller9cc61412015-02-02 14:02:52 -0800970 err = start_ioreq(call, reqs, nreqs, on_complete, user_data);
Craig Tiller8eb9d472015-01-27 17:00:03 -0800971 unlock(call);
972 return err;
Craig Tillercce17ac2015-01-20 09:29:28 -0800973}
974
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800975void grpc_call_destroy(grpc_call *c) {
ctillerc6d61c42014-12-15 14:52:08 -0800976 int cancel;
Craig Tiller9724de82015-01-28 17:06:29 -0800977 lock(c);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800978 if (c->have_alarm) {
ctiller18b49ab2014-12-09 14:39:16 -0800979 grpc_alarm_cancel(&c->alarm);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800980 c->have_alarm = 0;
981 }
Craig Tillerdaceea82015-02-02 16:15:53 -0800982 cancel = c->read_state != READ_STATE_STREAM_CLOSED;
Craig Tiller9724de82015-01-28 17:06:29 -0800983 unlock(c);
ctillerc6d61c42014-12-15 14:52:08 -0800984 if (cancel) grpc_call_cancel(c);
Craig Tiller64bc3fd2015-04-24 17:07:12 -0700985 grpc_call_internal_unref(c, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800986}
987
Craig Tiller58ce3f02015-04-22 07:54:24 -0700988grpc_call_error grpc_call_cancel(grpc_call *call) {
Craig Tiller48b9fde2015-04-24 08:04:59 -0700989 return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800990}
991
Craig Tiller6046dc32015-01-14 12:55:45 -0800992grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
993 grpc_status_code status,
994 const char *description) {
Craig Tiller48b9fde2015-04-24 08:04:59 -0700995 grpc_transport_op op;
Craig Tiller6046dc32015-01-14 12:55:45 -0800996 grpc_mdstr *details =
997 description ? grpc_mdstr_from_string(c->metadata_context, description)
998 : NULL;
Craig Tiller48b9fde2015-04-24 08:04:59 -0700999 memset(&op, 0, sizeof(op));
1000 op.cancel_with_status = status;
1001
Craig Tiller9724de82015-01-28 17:06:29 -08001002 lock(c);
Craig Tiller68752722015-01-29 14:59:54 -08001003 set_status_code(c, STATUS_FROM_API_OVERRIDE, status);
1004 set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
Craig Tiller9724de82015-01-28 17:06:29 -08001005 unlock(c);
Craig Tiller48b9fde2015-04-24 08:04:59 -07001006
1007 execute_op(c, &op);
1008
1009 return GRPC_CALL_OK;
Craig Tillerd248c242015-01-14 11:49:12 -08001010}
1011
Craig Tiller58ce3f02015-04-22 07:54:24 -07001012static void execute_op(grpc_call *call, grpc_transport_op *op) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001013 grpc_call_element *elem;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001014 elem = CALL_ELEM_FROM_CALL(call, 0);
Craig Tiller58ce3f02015-04-22 07:54:24 -07001015 elem->filter->start_transport_op(elem, op);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001016}
1017
Craig Tiller566316f2015-02-02 15:25:32 -08001018grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
1019 return CALL_FROM_TOP_ELEM(elem);
1020}
1021
1022static void call_alarm(void *arg, int success) {
1023 grpc_call *call = arg;
1024 if (success) {
1025 if (call->is_client) {
1026 grpc_call_cancel_with_status(call, GRPC_STATUS_DEADLINE_EXCEEDED,
1027 "Deadline Exceeded");
1028 } else {
1029 grpc_call_cancel(call);
1030 }
1031 }
Craig Tiller64bc3fd2015-04-24 17:07:12 -07001032 grpc_call_internal_unref(call, 1);
Craig Tiller566316f2015-02-02 15:25:32 -08001033}
1034
Craig Tiller6902ad22015-04-16 08:01:49 -07001035static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) {
Craig Tiller566316f2015-02-02 15:25:32 -08001036 if (call->have_alarm) {
1037 gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice");
Craig Tillerfa4f9942015-04-23 15:22:09 -07001038 assert(0);
Craig Tiller7e8489a2015-04-23 12:41:16 -07001039 return;
Craig Tiller566316f2015-02-02 15:25:32 -08001040 }
Craig Tiller64bc3fd2015-04-24 17:07:12 -07001041 grpc_call_internal_ref(call);
Craig Tiller566316f2015-02-02 15:25:32 -08001042 call->have_alarm = 1;
1043 grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now());
1044}
1045
Craig Tiller566316f2015-02-02 15:25:32 -08001046/* we offset status by a small amount when storing it into transport metadata
1047 as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
1048 */
1049#define STATUS_OFFSET 1
1050static void destroy_status(void *ignored) {}
1051
1052static gpr_uint32 decode_status(grpc_mdelem *md) {
1053 gpr_uint32 status;
1054 void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
1055 if (user_data) {
Craig Tiller87d5b192015-04-16 14:37:57 -07001056 status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET;
Craig Tiller566316f2015-02-02 15:25:32 -08001057 } else {
1058 if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
1059 GPR_SLICE_LENGTH(md->value->slice),
1060 &status)) {
1061 status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
1062 }
1063 grpc_mdelem_set_user_data(md, destroy_status,
1064 (void *)(gpr_intptr)(status + STATUS_OFFSET));
1065 }
1066 return status;
1067}
1068
Craig Tiller629b0ed2015-04-22 11:14:26 -07001069static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
Craig Tiller6902ad22015-04-16 08:01:49 -07001070 grpc_linked_mdelem *l;
Craig Tiller566316f2015-02-02 15:25:32 -08001071 grpc_metadata_array *dest;
1072 grpc_metadata *mdusr;
Craig Tiller6902ad22015-04-16 08:01:49 -07001073 int is_trailing;
Craig Tiller8b282cb2015-04-17 14:57:44 -07001074 grpc_mdctx *mdctx = call->metadata_context;
Craig Tiller566316f2015-02-02 15:25:32 -08001075
Craig Tiller6902ad22015-04-16 08:01:49 -07001076 is_trailing = call->read_state >= READ_STATE_GOT_INITIAL_METADATA;
Craig Tiller48b02ec2015-04-21 13:58:36 -07001077 for (l = md->list.head; l != NULL; l = l->next) {
Craig Tiller6902ad22015-04-16 08:01:49 -07001078 grpc_mdelem *md = l->md;
1079 grpc_mdstr *key = md->key;
1080 if (key == grpc_channel_get_status_string(call->channel)) {
1081 set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
Craig Tiller6902ad22015-04-16 08:01:49 -07001082 } else if (key == grpc_channel_get_message_string(call->channel)) {
1083 set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
Craig Tiller6902ad22015-04-16 08:01:49 -07001084 } else {
1085 dest = &call->buffered_metadata[is_trailing];
1086 if (dest->count == dest->capacity) {
1087 dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
1088 dest->metadata =
1089 gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
1090 }
1091 mdusr = &dest->metadata[dest->count++];
1092 mdusr->key = grpc_mdstr_as_c_string(md->key);
1093 mdusr->value = grpc_mdstr_as_c_string(md->value);
1094 mdusr->value_length = GPR_SLICE_LENGTH(md->value->slice);
1095 if (call->owned_metadata_count == call->owned_metadata_capacity) {
Craig Tiller87d5b192015-04-16 14:37:57 -07001096 call->owned_metadata_capacity =
1097 GPR_MAX(call->owned_metadata_capacity + 8,
1098 call->owned_metadata_capacity * 2);
Craig Tiller6902ad22015-04-16 08:01:49 -07001099 call->owned_metadata =
1100 gpr_realloc(call->owned_metadata,
1101 sizeof(grpc_mdelem *) * call->owned_metadata_capacity);
1102 }
1103 call->owned_metadata[call->owned_metadata_count++] = md;
Craig Tiller8b282cb2015-04-17 14:57:44 -07001104 l->md = 0;
Craig Tiller566316f2015-02-02 15:25:32 -08001105 }
Craig Tiller6902ad22015-04-16 08:01:49 -07001106 }
1107 if (gpr_time_cmp(md->deadline, gpr_inf_future) != 0) {
1108 set_deadline_alarm(call, md->deadline);
1109 }
1110 if (!is_trailing) {
Craig Tiller629b0ed2015-04-22 11:14:26 -07001111 call->read_state = READ_STATE_GOT_INITIAL_METADATA;
Craig Tiller566316f2015-02-02 15:25:32 -08001112 }
Craig Tiller6902ad22015-04-16 08:01:49 -07001113
Craig Tiller8b282cb2015-04-17 14:57:44 -07001114 grpc_mdctx_lock(mdctx);
1115 for (l = md->list.head; l; l = l->next) {
1116 if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
1117 }
1118 for (l = md->garbage.head; l; l = l->next) {
1119 grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
1120 }
1121 grpc_mdctx_unlock(mdctx);
Craig Tiller629b0ed2015-04-22 11:14:26 -07001122}
Craig Tiller8b282cb2015-04-17 14:57:44 -07001123
Craig Tiller566316f2015-02-02 15:25:32 -08001124grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
1125 return CALL_STACK_FROM_CALL(call);
1126}
1127
1128/*
Craig Tillerfb189f82015-02-03 12:07:07 -08001129 * BATCH API IMPLEMENTATION
1130 */
1131
1132static void set_status_value_directly(grpc_status_code status, void *dest) {
1133 *(grpc_status_code *)dest = status;
1134}
1135
1136static void set_cancelled_value(grpc_status_code status, void *dest) {
1137 *(grpc_status_code *)dest = (status != GRPC_STATUS_OK);
1138}
1139
Craig Tiller166e2502015-02-03 20:14:41 -08001140static void finish_batch(grpc_call *call, grpc_op_error result, void *tag) {
1141 grpc_cq_end_op_complete(call->cq, tag, call, do_nothing, NULL, GRPC_OP_OK);
1142}
Craig Tillerfb189f82015-02-03 12:07:07 -08001143
1144grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
1145 size_t nops, void *tag) {
1146 grpc_ioreq reqs[GRPC_IOREQ_OP_COUNT];
1147 size_t in;
1148 size_t out;
1149 const grpc_op *op;
1150 grpc_ioreq *req;
1151
murgatroid99d47946b2015-03-09 14:27:07 -07001152 GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
1153
murgatroid99a8c21e82015-02-12 13:55:53 -08001154 if (nops == 0) {
1155 grpc_cq_begin_op(call->cq, call, GRPC_OP_COMPLETE);
1156 grpc_cq_end_op_complete(call->cq, tag, call, do_nothing, NULL, GRPC_OP_OK);
1157 return GRPC_CALL_OK;
1158 }
1159
Craig Tillerfb189f82015-02-03 12:07:07 -08001160 /* rewrite batch ops into ioreq ops */
1161 for (in = 0, out = 0; in < nops; in++) {
1162 op = &ops[in];
1163 switch (op->op) {
1164 case GRPC_OP_SEND_INITIAL_METADATA:
1165 req = &reqs[out++];
1166 req->op = GRPC_IOREQ_SEND_INITIAL_METADATA;
1167 req->data.send_metadata.count = op->data.send_initial_metadata.count;
1168 req->data.send_metadata.metadata =
1169 op->data.send_initial_metadata.metadata;
1170 break;
1171 case GRPC_OP_SEND_MESSAGE:
1172 req = &reqs[out++];
1173 req->op = GRPC_IOREQ_SEND_MESSAGE;
1174 req->data.send_message = op->data.send_message;
1175 break;
1176 case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
1177 if (!call->is_client) {
1178 return GRPC_CALL_ERROR_NOT_ON_SERVER;
1179 }
1180 req = &reqs[out++];
1181 req->op = GRPC_IOREQ_SEND_CLOSE;
1182 break;
1183 case GRPC_OP_SEND_STATUS_FROM_SERVER:
1184 if (call->is_client) {
1185 return GRPC_CALL_ERROR_NOT_ON_CLIENT;
1186 }
1187 req = &reqs[out++];
1188 req->op = GRPC_IOREQ_SEND_TRAILING_METADATA;
1189 req->data.send_metadata.count =
1190 op->data.send_status_from_server.trailing_metadata_count;
1191 req->data.send_metadata.metadata =
1192 op->data.send_status_from_server.trailing_metadata;
1193 req = &reqs[out++];
1194 req->op = GRPC_IOREQ_SEND_STATUS;
1195 req->data.send_status.code = op->data.send_status_from_server.status;
1196 req->data.send_status.details =
1197 op->data.send_status_from_server.status_details;
1198 req = &reqs[out++];
1199 req->op = GRPC_IOREQ_SEND_CLOSE;
1200 break;
1201 case GRPC_OP_RECV_INITIAL_METADATA:
1202 if (!call->is_client) {
1203 return GRPC_CALL_ERROR_NOT_ON_SERVER;
1204 }
1205 req = &reqs[out++];
1206 req->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
1207 req->data.recv_metadata = op->data.recv_initial_metadata;
1208 break;
1209 case GRPC_OP_RECV_MESSAGE:
1210 req = &reqs[out++];
1211 req->op = GRPC_IOREQ_RECV_MESSAGE;
1212 req->data.recv_message = op->data.recv_message;
1213 break;
1214 case GRPC_OP_RECV_STATUS_ON_CLIENT:
1215 if (!call->is_client) {
1216 return GRPC_CALL_ERROR_NOT_ON_SERVER;
1217 }
1218 req = &reqs[out++];
1219 req->op = GRPC_IOREQ_RECV_STATUS;
1220 req->data.recv_status.set_value = set_status_value_directly;
1221 req->data.recv_status.user_data = op->data.recv_status_on_client.status;
1222 req = &reqs[out++];
1223 req->op = GRPC_IOREQ_RECV_STATUS_DETAILS;
1224 req->data.recv_status_details.details =
1225 op->data.recv_status_on_client.status_details;
1226 req->data.recv_status_details.details_capacity =
1227 op->data.recv_status_on_client.status_details_capacity;
1228 req = &reqs[out++];
1229 req->op = GRPC_IOREQ_RECV_TRAILING_METADATA;
1230 req->data.recv_metadata =
1231 op->data.recv_status_on_client.trailing_metadata;
1232 req = &reqs[out++];
1233 req->op = GRPC_IOREQ_RECV_CLOSE;
1234 break;
1235 case GRPC_OP_RECV_CLOSE_ON_SERVER:
1236 req = &reqs[out++];
1237 req->op = GRPC_IOREQ_RECV_STATUS;
1238 req->data.recv_status.set_value = set_cancelled_value;
1239 req->data.recv_status.user_data =
1240 op->data.recv_close_on_server.cancelled;
1241 req = &reqs[out++];
1242 req->op = GRPC_IOREQ_RECV_CLOSE;
1243 break;
1244 }
1245 }
1246
1247 grpc_cq_begin_op(call->cq, call, GRPC_OP_COMPLETE);
1248
1249 return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_batch,
1250 tag);
1251}
1252
1253/*
Craig Tiller566316f2015-02-02 15:25:32 -08001254 * LEGACY API IMPLEMENTATION
1255 * All this code will disappear as soon as wrappings are updated
1256 */
1257
1258struct legacy_state {
1259 gpr_uint8 md_out_buffer;
1260 size_t md_out_count[2];
1261 size_t md_out_capacity[2];
1262 grpc_metadata *md_out[2];
1263 grpc_byte_buffer *msg_out;
1264
1265 /* input buffers */
1266 grpc_metadata_array initial_md_in;
1267 grpc_metadata_array trailing_md_in;
1268
1269 size_t details_capacity;
1270 char *details;
1271 grpc_status_code status;
1272
Craig Tiller37bbead2015-02-05 08:43:49 -08001273 char *send_details;
1274
Craig Tiller566316f2015-02-02 15:25:32 -08001275 size_t msg_in_read_idx;
1276 grpc_byte_buffer *msg_in;
1277
1278 void *finished_tag;
1279};
1280
1281static legacy_state *get_legacy_state(grpc_call *call) {
1282 if (call->legacy_state == NULL) {
1283 call->legacy_state = gpr_malloc(sizeof(legacy_state));
1284 memset(call->legacy_state, 0, sizeof(legacy_state));
1285 }
1286 return call->legacy_state;
1287}
1288
1289static void destroy_legacy_state(legacy_state *ls) {
1290 size_t i, j;
1291 for (i = 0; i < 2; i++) {
1292 for (j = 0; j < ls->md_out_count[i]; j++) {
Craig Tiller4f972732015-02-05 12:40:20 -08001293 gpr_free((char *)ls->md_out[i][j].key);
1294 gpr_free((char *)ls->md_out[i][j].value);
Craig Tiller566316f2015-02-02 15:25:32 -08001295 }
1296 gpr_free(ls->md_out[i]);
1297 }
1298 gpr_free(ls->initial_md_in.metadata);
1299 gpr_free(ls->trailing_md_in.metadata);
Craig Tillerea3697b2015-02-05 08:40:18 -08001300 gpr_free(ls->details);
Craig Tiller37bbead2015-02-05 08:43:49 -08001301 gpr_free(ls->send_details);
Craig Tiller566316f2015-02-02 15:25:32 -08001302 gpr_free(ls);
1303}
1304
Craig Tiller40d2a432015-02-02 15:29:14 -08001305grpc_call_error grpc_call_add_metadata_old(grpc_call *call,
1306 grpc_metadata *metadata,
1307 gpr_uint32 flags) {
Craig Tiller62ac1552015-01-27 15:41:44 -08001308 legacy_state *ls;
1309 grpc_metadata *mdout;
1310
Craig Tiller8eb9d472015-01-27 17:00:03 -08001311 lock(call);
Craig Tiller62ac1552015-01-27 15:41:44 -08001312 ls = get_legacy_state(call);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001313
Craig Tiller1c141902015-01-31 08:51:54 -08001314 if (ls->md_out_count[ls->md_out_buffer] ==
1315 ls->md_out_capacity[ls->md_out_buffer]) {
Craig Tillerc689ca32015-01-30 10:59:52 -08001316 ls->md_out_capacity[ls->md_out_buffer] =
Craig Tiller1c141902015-01-31 08:51:54 -08001317 GPR_MAX(ls->md_out_capacity[ls->md_out_buffer] * 3 / 2,
1318 ls->md_out_capacity[ls->md_out_buffer] + 8);
1319 ls->md_out[ls->md_out_buffer] = gpr_realloc(
1320 ls->md_out[ls->md_out_buffer],
1321 sizeof(grpc_metadata) * ls->md_out_capacity[ls->md_out_buffer]);
Craig Tillercce17ac2015-01-20 09:29:28 -08001322 }
Craig Tillerc689ca32015-01-30 10:59:52 -08001323 mdout = &ls->md_out[ls->md_out_buffer][ls->md_out_count[ls->md_out_buffer]++];
Craig Tiller62ac1552015-01-27 15:41:44 -08001324 mdout->key = gpr_strdup(metadata->key);
1325 mdout->value = gpr_malloc(metadata->value_length);
1326 mdout->value_length = metadata->value_length;
Craig Tiller4f972732015-02-05 12:40:20 -08001327 memcpy((char *)mdout->value, metadata->value, metadata->value_length);
klempnerc463f742014-12-19 13:03:35 -08001328
Craig Tiller8eb9d472015-01-27 17:00:03 -08001329 unlock(call);
Craig Tiller62ac1552015-01-27 15:41:44 -08001330
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001331 return GRPC_CALL_OK;
1332}
1333
Craig Tiller50524cc2015-01-29 23:00:00 -08001334static void finish_status(grpc_call *call, grpc_op_error status,
1335 void *ignored) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001336 legacy_state *ls;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001337
Craig Tiller8eb9d472015-01-27 17:00:03 -08001338 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001339 ls = get_legacy_state(call);
Craig Tiller7a9d7922015-01-31 09:35:20 -08001340 grpc_cq_end_finished(call->cq, ls->finished_tag, call, do_nothing, NULL,
1341 ls->status, ls->details, ls->trailing_md_in.metadata,
1342 ls->trailing_md_in.count);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001343 unlock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001344}
Craig Tiller80fa15c2015-01-13 16:10:49 -08001345
Craig Tillercce17ac2015-01-20 09:29:28 -08001346static void finish_recv_metadata(grpc_call *call, grpc_op_error status,
1347 void *tag) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001348 legacy_state *ls;
1349
Craig Tiller8eb9d472015-01-27 17:00:03 -08001350 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001351 ls = get_legacy_state(call);
1352 if (status == GRPC_OP_OK) {
1353 grpc_cq_end_client_metadata_read(call->cq, tag, call, do_nothing, NULL,
Craig Tiller1c141902015-01-31 08:51:54 -08001354 ls->initial_md_in.count,
1355 ls->initial_md_in.metadata);
Craig Tillercce17ac2015-01-20 09:29:28 -08001356
Craig Tiller62ac1552015-01-27 15:41:44 -08001357 } else {
1358 grpc_cq_end_client_metadata_read(call->cq, tag, call, do_nothing, NULL, 0,
1359 NULL);
1360 }
Craig Tiller8eb9d472015-01-27 17:00:03 -08001361 unlock(call);
Craig Tiller62ac1552015-01-27 15:41:44 -08001362}
1363
Craig Tiller50524cc2015-01-29 23:00:00 -08001364static void finish_send_metadata(grpc_call *call, grpc_op_error status,
1365 void *tag) {}
Craig Tiller80fa15c2015-01-13 16:10:49 -08001366
Craig Tiller40d2a432015-02-02 15:29:14 -08001367grpc_call_error grpc_call_invoke_old(grpc_call *call, grpc_completion_queue *cq,
1368 void *metadata_read_tag,
1369 void *finished_tag, gpr_uint32 flags) {
Craig Tillerfb189f82015-02-03 12:07:07 -08001370 grpc_ioreq reqs[4];
Craig Tillerfa8f4012015-01-29 16:16:58 -08001371 legacy_state *ls;
Craig Tillercce17ac2015-01-20 09:29:28 -08001372 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001373
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001374 grpc_cq_begin_op(cq, call, GRPC_CLIENT_METADATA_READ);
Craig Tillercce17ac2015-01-20 09:29:28 -08001375 grpc_cq_begin_op(cq, call, GRPC_FINISHED);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001376
Craig Tiller8eb9d472015-01-27 17:00:03 -08001377 lock(call);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001378 ls = get_legacy_state(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001379 err = bind_cq(call, cq);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001380 if (err != GRPC_CALL_OK) goto done;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001381
Craig Tiller50524cc2015-01-29 23:00:00 -08001382 ls->finished_tag = finished_tag;
1383
Craig Tillerfa8f4012015-01-29 16:16:58 -08001384 reqs[0].op = GRPC_IOREQ_SEND_INITIAL_METADATA;
Craig Tillerc689ca32015-01-30 10:59:52 -08001385 reqs[0].data.send_metadata.count = ls->md_out_count[ls->md_out_buffer];
1386 reqs[0].data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
1387 ls->md_out_buffer++;
Craig Tiller9cc61412015-02-02 14:02:52 -08001388 err = start_ioreq(call, reqs, 1, finish_send_metadata, NULL);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001389 if (err != GRPC_CALL_OK) goto done;
Craig Tiller9724de82015-01-28 17:06:29 -08001390
Craig Tillerfa8f4012015-01-29 16:16:58 -08001391 reqs[0].op = GRPC_IOREQ_RECV_INITIAL_METADATA;
Craig Tiller03d5bf72015-01-30 12:01:30 -08001392 reqs[0].data.recv_metadata = &ls->initial_md_in;
Craig Tiller9cc61412015-02-02 14:02:52 -08001393 err = start_ioreq(call, reqs, 1, finish_recv_metadata, metadata_read_tag);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001394 if (err != GRPC_CALL_OK) goto done;
1395
1396 reqs[0].op = GRPC_IOREQ_RECV_TRAILING_METADATA;
Craig Tiller03d5bf72015-01-30 12:01:30 -08001397 reqs[0].data.recv_metadata = &ls->trailing_md_in;
Craig Tillerfa8f4012015-01-29 16:16:58 -08001398 reqs[1].op = GRPC_IOREQ_RECV_STATUS;
Craig Tillerfb189f82015-02-03 12:07:07 -08001399 reqs[1].data.recv_status.user_data = &ls->status;
1400 reqs[1].data.recv_status.set_value = set_status_value_directly;
1401 reqs[2].op = GRPC_IOREQ_RECV_STATUS_DETAILS;
1402 reqs[2].data.recv_status_details.details = &ls->details;
1403 reqs[2].data.recv_status_details.details_capacity = &ls->details_capacity;
1404 reqs[3].op = GRPC_IOREQ_RECV_CLOSE;
1405 err = start_ioreq(call, reqs, 4, finish_status, NULL);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001406 if (err != GRPC_CALL_OK) goto done;
1407
1408done:
Craig Tiller8eb9d472015-01-27 17:00:03 -08001409 unlock(call);
1410 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001411}
1412
Craig Tiller40d2a432015-02-02 15:29:14 -08001413grpc_call_error grpc_call_server_accept_old(grpc_call *call,
1414 grpc_completion_queue *cq,
1415 void *finished_tag) {
Craig Tiller05140d02015-01-30 16:43:40 -08001416 grpc_ioreq reqs[2];
Craig Tiller8eb9d472015-01-27 17:00:03 -08001417 grpc_call_error err;
Craig Tiller05140d02015-01-30 16:43:40 -08001418 legacy_state *ls;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001419
1420 /* inform the completion queue of an incoming operation (corresponding to
1421 finished_tag) */
1422 grpc_cq_begin_op(cq, call, GRPC_FINISHED);
1423
Craig Tiller8884d7f2015-01-29 10:46:45 -08001424 lock(call);
Craig Tiller05140d02015-01-30 16:43:40 -08001425 ls = get_legacy_state(call);
1426
Craig Tiller8eb9d472015-01-27 17:00:03 -08001427 err = bind_cq(call, cq);
Craig Tiller970781b2015-02-08 14:38:31 -08001428 if (err != GRPC_CALL_OK) {
1429 unlock(call);
1430 return err;
1431 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001432
Craig Tiller05140d02015-01-30 16:43:40 -08001433 ls->finished_tag = finished_tag;
Craig Tiller50524cc2015-01-29 23:00:00 -08001434
Craig Tiller05140d02015-01-30 16:43:40 -08001435 reqs[0].op = GRPC_IOREQ_RECV_STATUS;
Craig Tillerfb189f82015-02-03 12:07:07 -08001436 reqs[0].data.recv_status.user_data = &ls->status;
1437 reqs[0].data.recv_status.set_value = set_status_value_directly;
Craig Tiller05140d02015-01-30 16:43:40 -08001438 reqs[1].op = GRPC_IOREQ_RECV_CLOSE;
Craig Tiller9cc61412015-02-02 14:02:52 -08001439 err = start_ioreq(call, reqs, 2, finish_status, NULL);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001440 unlock(call);
1441 return err;
nnoble0c475f02014-12-05 15:37:39 -08001442}
1443
Craig Tillerabcf6522015-01-28 15:44:24 -08001444static void finish_send_initial_metadata(grpc_call *call, grpc_op_error status,
1445 void *tag) {}
Craig Tiller39fd4282015-01-28 09:12:31 -08001446
Craig Tiller40d2a432015-02-02 15:29:14 -08001447grpc_call_error grpc_call_server_end_initial_metadata_old(grpc_call *call,
1448 gpr_uint32 flags) {
Craig Tiller39fd4282015-01-28 09:12:31 -08001449 grpc_ioreq req;
1450 grpc_call_error err;
1451 legacy_state *ls;
1452
1453 lock(call);
1454 ls = get_legacy_state(call);
1455 req.op = GRPC_IOREQ_SEND_INITIAL_METADATA;
Craig Tillerc689ca32015-01-30 10:59:52 -08001456 req.data.send_metadata.count = ls->md_out_count[ls->md_out_buffer];
1457 req.data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
Craig Tiller9cc61412015-02-02 14:02:52 -08001458 err = start_ioreq(call, &req, 1, finish_send_initial_metadata, NULL);
Craig Tiller39fd4282015-01-28 09:12:31 -08001459 unlock(call);
Craig Tillerabcf6522015-01-28 15:44:24 -08001460
Craig Tiller39fd4282015-01-28 09:12:31 -08001461 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001462}
1463
Craig Tiller68f55a02015-01-30 07:54:48 -08001464static void finish_read_event(void *p, grpc_op_error error) {
Craig Tiller8f4f6e22015-01-31 20:01:37 -08001465 if (p) grpc_byte_buffer_destroy(p);
Craig Tiller68f55a02015-01-30 07:54:48 -08001466}
1467
Craig Tillercce17ac2015-01-20 09:29:28 -08001468static void finish_read(grpc_call *call, grpc_op_error error, void *tag) {
1469 legacy_state *ls;
Craig Tiller05140d02015-01-30 16:43:40 -08001470 grpc_byte_buffer *msg;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001471 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001472 ls = get_legacy_state(call);
Craig Tiller05140d02015-01-30 16:43:40 -08001473 msg = ls->msg_in;
1474 grpc_cq_end_read(call->cq, tag, call, finish_read_event, msg, msg);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001475 unlock(call);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001476}
1477
Craig Tiller40d2a432015-02-02 15:29:14 -08001478grpc_call_error grpc_call_start_read_old(grpc_call *call, void *tag) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001479 legacy_state *ls;
1480 grpc_ioreq req;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001481 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001482
1483 grpc_cq_begin_op(call->cq, call, GRPC_READ);
1484
Craig Tiller8eb9d472015-01-27 17:00:03 -08001485 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001486 ls = get_legacy_state(call);
Craig Tiller05140d02015-01-30 16:43:40 -08001487 req.op = GRPC_IOREQ_RECV_MESSAGE;
1488 req.data.recv_message = &ls->msg_in;
Craig Tiller9cc61412015-02-02 14:02:52 -08001489 err = start_ioreq(call, &req, 1, finish_read, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001490 unlock(call);
1491 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001492}
1493
Craig Tillercce17ac2015-01-20 09:29:28 -08001494static void finish_write(grpc_call *call, grpc_op_error status, void *tag) {
Craig Tillera4541102015-01-29 11:46:11 -08001495 lock(call);
1496 grpc_byte_buffer_destroy(get_legacy_state(call)->msg_out);
1497 unlock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001498 grpc_cq_end_write_accepted(call->cq, tag, call, do_nothing, NULL, status);
1499}
1500
Craig Tiller40d2a432015-02-02 15:29:14 -08001501grpc_call_error grpc_call_start_write_old(grpc_call *call,
1502 grpc_byte_buffer *byte_buffer,
1503 void *tag, gpr_uint32 flags) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001504 grpc_ioreq req;
1505 legacy_state *ls;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001506 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001507
1508 grpc_cq_begin_op(call->cq, call, GRPC_WRITE_ACCEPTED);
1509
Craig Tiller8eb9d472015-01-27 17:00:03 -08001510 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001511 ls = get_legacy_state(call);
Craig Tillera4541102015-01-29 11:46:11 -08001512 ls->msg_out = grpc_byte_buffer_copy(byte_buffer);
Craig Tiller05140d02015-01-30 16:43:40 -08001513 req.op = GRPC_IOREQ_SEND_MESSAGE;
1514 req.data.send_message = ls->msg_out;
Craig Tiller9cc61412015-02-02 14:02:52 -08001515 err = start_ioreq(call, &req, 1, finish_write, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001516 unlock(call);
1517
1518 return err;
Craig Tillercce17ac2015-01-20 09:29:28 -08001519}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001520
Craig Tillercce17ac2015-01-20 09:29:28 -08001521static void finish_finish(grpc_call *call, grpc_op_error status, void *tag) {
1522 grpc_cq_end_finish_accepted(call->cq, tag, call, do_nothing, NULL, status);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001523}
1524
Craig Tiller40d2a432015-02-02 15:29:14 -08001525grpc_call_error grpc_call_writes_done_old(grpc_call *call, void *tag) {
Craig Tillercce17ac2015-01-20 09:29:28 -08001526 grpc_ioreq req;
Craig Tiller8eb9d472015-01-27 17:00:03 -08001527 grpc_call_error err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001528 grpc_cq_begin_op(call->cq, call, GRPC_FINISH_ACCEPTED);
1529
Craig Tiller8eb9d472015-01-27 17:00:03 -08001530 lock(call);
Craig Tillercce17ac2015-01-20 09:29:28 -08001531 req.op = GRPC_IOREQ_SEND_CLOSE;
Craig Tiller9cc61412015-02-02 14:02:52 -08001532 err = start_ioreq(call, &req, 1, finish_finish, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001533 unlock(call);
1534
1535 return err;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001536}
1537
Craig Tiller40d2a432015-02-02 15:29:14 -08001538grpc_call_error grpc_call_start_write_status_old(grpc_call *call,
1539 grpc_status_code status,
1540 const char *details,
1541 void *tag) {
Craig Tiller05140d02015-01-30 16:43:40 -08001542 grpc_ioreq reqs[3];
Craig Tiller8eb9d472015-01-27 17:00:03 -08001543 grpc_call_error err;
Craig Tillerfa8f4012015-01-29 16:16:58 -08001544 legacy_state *ls;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001545 grpc_cq_begin_op(call->cq, call, GRPC_FINISH_ACCEPTED);
1546
Craig Tiller8eb9d472015-01-27 17:00:03 -08001547 lock(call);
Craig Tillerfa8f4012015-01-29 16:16:58 -08001548 ls = get_legacy_state(call);
Craig Tillerf31d14c2015-01-28 09:26:42 -08001549 reqs[0].op = GRPC_IOREQ_SEND_TRAILING_METADATA;
Craig Tillerc689ca32015-01-30 10:59:52 -08001550 reqs[0].data.send_metadata.count = ls->md_out_count[ls->md_out_buffer];
1551 reqs[0].data.send_metadata.metadata = ls->md_out[ls->md_out_buffer];
Craig Tiller1c141902015-01-31 08:51:54 -08001552 reqs[1].op = GRPC_IOREQ_SEND_STATUS;
Craig Tiller05140d02015-01-30 16:43:40 -08001553 reqs[1].data.send_status.code = status;
Craig Tiller37bbead2015-02-05 08:43:49 -08001554 reqs[1].data.send_status.details = ls->send_details = gpr_strdup(details);
Craig Tiller1c141902015-01-31 08:51:54 -08001555 reqs[2].op = GRPC_IOREQ_SEND_CLOSE;
Craig Tiller9cc61412015-02-02 14:02:52 -08001556 err = start_ioreq(call, reqs, 3, finish_finish, tag);
Craig Tiller8eb9d472015-01-27 17:00:03 -08001557 unlock(call);
1558
1559 return err;
Craig Tiller190d3602015-02-18 09:23:38 -08001560}