Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * 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 : #ifndef GRPCXX_IMPL_CALL_H
35 : #define GRPCXX_IMPL_CALL_H
36 :
37 : #include <functional>
38 : #include <memory>
39 : #include <map>
40 : #include <cstring>
41 :
42 : #include <grpc/support/alloc.h>
43 : #include <grpc++/client_context.h>
44 : #include <grpc++/completion_queue.h>
45 : #include <grpc++/impl/serialization_traits.h>
46 : #include <grpc++/support/config.h>
47 : #include <grpc++/support/status.h>
48 :
49 : struct grpc_call;
50 : struct grpc_op;
51 :
52 : namespace grpc {
53 :
54 : class ByteBuffer;
55 : class Call;
56 :
57 : void FillMetadataMap(
58 : grpc_metadata_array* arr,
59 : std::multimap<grpc::string_ref, grpc::string_ref>* metadata);
60 : grpc_metadata* FillMetadataArray(
61 : const std::multimap<grpc::string, grpc::string>& metadata);
62 :
63 : /// Per-message write options.
64 : class WriteOptions {
65 : public:
66 5629273 : WriteOptions() : flags_(0) {}
67 : WriteOptions(const WriteOptions& other) : flags_(other.flags_) {}
68 :
69 : /// Clear all flags.
70 2794932 : inline void Clear() { flags_ = 0; }
71 :
72 : /// Returns raw flags bitset.
73 2794894 : inline gpr_uint32 flags() const { return flags_; }
74 :
75 : /// Sets flag for the disabling of compression for the next message write.
76 : ///
77 : /// \sa GRPC_WRITE_NO_COMPRESS
78 : inline WriteOptions& set_no_compression() {
79 : SetBit(GRPC_WRITE_NO_COMPRESS);
80 : return *this;
81 : }
82 :
83 : /// Clears flag for the disabling of compression for the next message write.
84 : ///
85 : /// \sa GRPC_WRITE_NO_COMPRESS
86 : inline WriteOptions& clear_no_compression() {
87 : ClearBit(GRPC_WRITE_NO_COMPRESS);
88 : return *this;
89 : }
90 :
91 : /// Get value for the flag indicating whether compression for the next
92 : /// message write is forcefully disabled.
93 : ///
94 : /// \sa GRPC_WRITE_NO_COMPRESS
95 : inline bool get_no_compression() const {
96 : return GetBit(GRPC_WRITE_NO_COMPRESS);
97 : }
98 :
99 : /// Sets flag indicating that the write may be buffered and need not go out on
100 : /// the wire immediately.
101 : ///
102 : /// \sa GRPC_WRITE_BUFFER_HINT
103 : inline WriteOptions& set_buffer_hint() {
104 : SetBit(GRPC_WRITE_BUFFER_HINT);
105 : return *this;
106 : }
107 :
108 : /// Clears flag indicating that the write may be buffered and need not go out
109 : /// on the wire immediately.
110 : ///
111 : /// \sa GRPC_WRITE_BUFFER_HINT
112 : inline WriteOptions& clear_buffer_hint() {
113 : ClearBit(GRPC_WRITE_BUFFER_HINT);
114 : return *this;
115 : }
116 :
117 : /// Get value for the flag indicating that the write may be buffered and need
118 : /// not go out on the wire immediately.
119 : ///
120 : /// \sa GRPC_WRITE_BUFFER_HINT
121 : inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
122 :
123 3956466 : WriteOptions& operator=(const WriteOptions& rhs) {
124 3956466 : flags_ = rhs.flags_;
125 3956466 : return *this;
126 : }
127 :
128 : private:
129 : void SetBit(const gpr_uint32 mask) { flags_ |= mask; }
130 :
131 : void ClearBit(const gpr_uint32 mask) { flags_ &= ~mask; }
132 :
133 : bool GetBit(const gpr_uint32 mask) const { return (flags_ & mask) != 0; }
134 :
135 : gpr_uint32 flags_;
136 : };
137 :
138 : /// Default argument for CallOpSet. I is unused by the class, but can be
139 : /// used for generating multiple names for the same thing.
140 : template <int I>
141 24861812 : class CallNoOp {
142 : protected:
143 12481570 : void AddOp(grpc_op* ops, size_t* nops) {}
144 12484672 : void FinishOp(bool* status, int max_message_size) {}
145 : };
146 :
147 : class CallOpSendInitialMetadata {
148 : public:
149 4091487 : CallOpSendInitialMetadata() : send_(false) {}
150 :
151 2596283 : void SendInitialMetadata(
152 : const std::multimap<grpc::string, grpc::string>& metadata) {
153 2596283 : send_ = true;
154 2596283 : initial_metadata_count_ = metadata.size();
155 2597168 : initial_metadata_ = FillMetadataArray(metadata);
156 2597125 : }
157 :
158 : protected:
159 2703125 : void AddOp(grpc_op* ops, size_t* nops) {
160 5406250 : if (!send_) return;
161 2595183 : grpc_op* op = &ops[(*nops)++];
162 2595183 : op->op = GRPC_OP_SEND_INITIAL_METADATA;
163 2595183 : op->flags = 0;
164 2595183 : op->reserved = NULL;
165 2595183 : op->data.send_initial_metadata.count = initial_metadata_count_;
166 2595183 : op->data.send_initial_metadata.metadata = initial_metadata_;
167 : }
168 2705803 : void FinishOp(bool* status, int max_message_size) {
169 5410504 : if (!send_) return;
170 2597861 : gpr_free(initial_metadata_);
171 2596759 : send_ = false;
172 : }
173 :
174 : bool send_;
175 : size_t initial_metadata_count_;
176 : grpc_metadata* initial_metadata_;
177 : };
178 :
179 1165431 : class CallOpSendMessage {
180 : public:
181 2846636 : CallOpSendMessage() : send_buf_(nullptr), own_buf_(false) {}
182 :
183 : /// Send \a message using \a options for the write. The \a options are cleared
184 : /// after use.
185 : template <class M>
186 : Status SendMessage(const M& message,
187 : const WriteOptions& options) GRPC_MUST_USE_RESULT;
188 :
189 : template <class M>
190 : Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
191 :
192 : protected:
193 2794196 : void AddOp(grpc_op* ops, size_t* nops) {
194 5588588 : if (send_buf_ == nullptr) return;
195 2794176 : grpc_op* op = &ops[(*nops)++];
196 2794176 : op->op = GRPC_OP_SEND_MESSAGE;
197 2794176 : op->flags = write_options_.flags();
198 2794917 : op->reserved = NULL;
199 2794917 : op->data.send_message = send_buf_;
200 : // Flags are per-message: clear them after use.
201 2794917 : write_options_.Clear();
202 : }
203 2795521 : void FinishOp(bool* status, int max_message_size) {
204 2795521 : if (own_buf_) grpc_byte_buffer_destroy(send_buf_);
205 2795497 : send_buf_ = nullptr;
206 2795497 : }
207 :
208 : private:
209 : grpc_byte_buffer* send_buf_;
210 : WriteOptions write_options_;
211 : bool own_buf_;
212 : };
213 :
214 : template <class M>
215 2795662 : Status CallOpSendMessage::SendMessage(const M& message,
216 : const WriteOptions& options) {
217 2795662 : write_options_ = options;
218 2795681 : return SerializationTraits<M>::Serialize(message, &send_buf_, &own_buf_);
219 : }
220 :
221 : template <class M>
222 2650498 : Status CallOpSendMessage::SendMessage(const M& message) {
223 2650498 : return SendMessage(message, WriteOptions());
224 : }
225 :
226 : template <class R>
227 : class CallOpRecvMessage {
228 : public:
229 1507580 : CallOpRecvMessage() : got_message(false), message_(nullptr) {}
230 :
231 1496715 : void RecvMessage(R* message) { message_ = message; }
232 :
233 : bool got_message;
234 :
235 : protected:
236 1496547 : void AddOp(grpc_op* ops, size_t* nops) {
237 2993094 : if (message_ == nullptr) return;
238 1496547 : grpc_op* op = &ops[(*nops)++];
239 1496547 : op->op = GRPC_OP_RECV_MESSAGE;
240 1496547 : op->flags = 0;
241 1496547 : op->reserved = NULL;
242 1496547 : op->data.recv_message = &recv_buf_;
243 : }
244 :
245 1496786 : void FinishOp(bool* status, int max_message_size) {
246 2993666 : if (message_ == nullptr) return;
247 1496786 : if (recv_buf_) {
248 1496697 : if (*status) {
249 1496697 : got_message = true;
250 1496697 : *status = SerializationTraits<R>::Deserialize(recv_buf_, message_,
251 : max_message_size).ok();
252 : } else {
253 0 : got_message = false;
254 0 : grpc_byte_buffer_destroy(recv_buf_);
255 : }
256 : } else {
257 89 : got_message = false;
258 89 : *status = false;
259 : }
260 1496880 : message_ = nullptr;
261 : }
262 :
263 : private:
264 : R* message_;
265 : grpc_byte_buffer* recv_buf_;
266 : };
267 :
268 : namespace CallOpGenericRecvMessageHelper {
269 10 : class DeserializeFunc {
270 : public:
271 : virtual Status Deserialize(grpc_byte_buffer* buf, int max_message_size) = 0;
272 : };
273 :
274 : template <class R>
275 : class DeserializeFuncType GRPC_FINAL : public DeserializeFunc {
276 : public:
277 10 : DeserializeFuncType(R* message) : message_(message) {}
278 6 : Status Deserialize(grpc_byte_buffer* buf,
279 : int max_message_size) GRPC_OVERRIDE {
280 6 : return SerializationTraits<R>::Deserialize(buf, message_, max_message_size);
281 : }
282 :
283 : private:
284 : R* message_; // Not a managed pointer because management is external to this
285 : };
286 : } // namespace CallOpGenericRecvMessageHelper
287 :
288 10 : class CallOpGenericRecvMessage {
289 : public:
290 10 : CallOpGenericRecvMessage() : got_message(false) {}
291 :
292 : template <class R>
293 10 : void RecvMessage(R* message) {
294 10 : deserialize_.reset(
295 : new CallOpGenericRecvMessageHelper::DeserializeFuncType<R>(message));
296 10 : }
297 :
298 : bool got_message;
299 :
300 : protected:
301 10 : void AddOp(grpc_op* ops, size_t* nops) {
302 20 : if (!deserialize_) return;
303 10 : grpc_op* op = &ops[(*nops)++];
304 10 : op->op = GRPC_OP_RECV_MESSAGE;
305 10 : op->flags = 0;
306 10 : op->reserved = NULL;
307 10 : op->data.recv_message = &recv_buf_;
308 : }
309 :
310 10 : void FinishOp(bool* status, int max_message_size) {
311 20 : if (!deserialize_) return;
312 10 : if (recv_buf_) {
313 6 : if (*status) {
314 6 : got_message = true;
315 6 : *status = deserialize_->Deserialize(recv_buf_, max_message_size).ok();
316 : } else {
317 0 : got_message = false;
318 0 : grpc_byte_buffer_destroy(recv_buf_);
319 : }
320 : } else {
321 4 : got_message = false;
322 4 : *status = false;
323 : }
324 10 : deserialize_.reset();
325 : }
326 :
327 : private:
328 : std::unique_ptr<CallOpGenericRecvMessageHelper::DeserializeFunc> deserialize_;
329 : grpc_byte_buffer* recv_buf_;
330 : };
331 :
332 : class CallOpClientSendClose {
333 : public:
334 1298453 : CallOpClientSendClose() : send_(false) {}
335 :
336 1299072 : void ClientSendClose() { send_ = true; }
337 :
338 : protected:
339 1299141 : void AddOp(grpc_op* ops, size_t* nops) {
340 2598282 : if (!send_) return;
341 1299141 : grpc_op* op = &ops[(*nops)++];
342 1299141 : op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
343 1299141 : op->flags = 0;
344 1299141 : op->reserved = NULL;
345 : }
346 1299119 : void FinishOp(bool* status, int max_message_size) { send_ = false; }
347 :
348 : private:
349 : bool send_;
350 : };
351 :
352 2570549 : class CallOpServerSendStatus {
353 : public:
354 1405298 : CallOpServerSendStatus() : send_status_available_(false) {}
355 :
356 1298970 : void ServerSendStatus(
357 : const std::multimap<grpc::string, grpc::string>& trailing_metadata,
358 : const Status& status) {
359 1298970 : trailing_metadata_count_ = trailing_metadata.size();
360 1299031 : trailing_metadata_ = FillMetadataArray(trailing_metadata);
361 1299032 : send_status_available_ = true;
362 1299032 : send_status_code_ = static_cast<grpc_status_code>(status.error_code());
363 1299027 : send_status_details_ = status.error_message();
364 1299089 : }
365 :
366 : protected:
367 1299036 : void AddOp(grpc_op* ops, size_t* nops) {
368 2598146 : if (!send_status_available_) return;
369 1299036 : grpc_op* op = &ops[(*nops)++];
370 1299036 : op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
371 : op->data.send_status_from_server.trailing_metadata_count =
372 1299036 : trailing_metadata_count_;
373 1299036 : op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
374 1299036 : op->data.send_status_from_server.status = send_status_code_;
375 : op->data.send_status_from_server.status_details =
376 1299036 : send_status_details_.empty() ? nullptr : send_status_details_.c_str();
377 1299110 : op->flags = 0;
378 1299110 : op->reserved = NULL;
379 : }
380 :
381 1299108 : void FinishOp(bool* status, int max_message_size) {
382 2598212 : if (!send_status_available_) return;
383 1299108 : gpr_free(trailing_metadata_);
384 1299104 : send_status_available_ = false;
385 : }
386 :
387 : private:
388 : bool send_status_available_;
389 : grpc_status_code send_status_code_;
390 : grpc::string send_status_details_;
391 : size_t trailing_metadata_count_;
392 : grpc_metadata* trailing_metadata_;
393 : };
394 :
395 : class CallOpRecvInitialMetadata {
396 : public:
397 2519138 : CallOpRecvInitialMetadata() : recv_initial_metadata_(nullptr) {}
398 :
399 1299097 : void RecvInitialMetadata(ClientContext* context) {
400 1299097 : context->initial_metadata_received_ = true;
401 1299097 : recv_initial_metadata_ = &context->recv_initial_metadata_;
402 1299097 : }
403 :
404 : protected:
405 1406852 : void AddOp(grpc_op* ops, size_t* nops) {
406 2813704 : if (!recv_initial_metadata_) return;
407 1298932 : memset(&recv_initial_metadata_arr_, 0, sizeof(recv_initial_metadata_arr_));
408 1298932 : grpc_op* op = &ops[(*nops)++];
409 1298932 : op->op = GRPC_OP_RECV_INITIAL_METADATA;
410 1298932 : op->data.recv_initial_metadata = &recv_initial_metadata_arr_;
411 1298932 : op->flags = 0;
412 1298932 : op->reserved = NULL;
413 : }
414 1406665 : void FinishOp(bool* status, int max_message_size) {
415 2813679 : if (recv_initial_metadata_ == nullptr) return;
416 1298745 : FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
417 1299094 : recv_initial_metadata_ = nullptr;
418 : }
419 :
420 : private:
421 : std::multimap<grpc::string_ref, grpc::string_ref>* recv_initial_metadata_;
422 : grpc_metadata_array recv_initial_metadata_arr_;
423 : };
424 :
425 : class CallOpClientRecvStatus {
426 : public:
427 1298935 : CallOpClientRecvStatus() : recv_status_(nullptr) {}
428 :
429 1297710 : void ClientRecvStatus(ClientContext* context, Status* status) {
430 1297710 : recv_trailing_metadata_ = &context->trailing_metadata_;
431 1297710 : recv_status_ = status;
432 1297710 : }
433 :
434 : protected:
435 1299138 : void AddOp(grpc_op* ops, size_t* nops) {
436 2598276 : if (recv_status_ == nullptr) return;
437 : memset(&recv_trailing_metadata_arr_, 0,
438 1299138 : sizeof(recv_trailing_metadata_arr_));
439 1299138 : status_details_ = nullptr;
440 1299138 : status_details_capacity_ = 0;
441 1299138 : grpc_op* op = &ops[(*nops)++];
442 1299138 : op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
443 : op->data.recv_status_on_client.trailing_metadata =
444 1299138 : &recv_trailing_metadata_arr_;
445 1299138 : op->data.recv_status_on_client.status = &status_code_;
446 1299138 : op->data.recv_status_on_client.status_details = &status_details_;
447 : op->data.recv_status_on_client.status_details_capacity =
448 1299138 : &status_details_capacity_;
449 1299138 : op->flags = 0;
450 1299138 : op->reserved = NULL;
451 : }
452 :
453 1298967 : void FinishOp(bool* status, int max_message_size) {
454 2598106 : if (recv_status_ == nullptr) return;
455 1298967 : FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_);
456 3897036 : *recv_status_ = Status(
457 : static_cast<StatusCode>(status_code_),
458 1298886 : status_details_ ? grpc::string(status_details_) : grpc::string());
459 1299123 : gpr_free(status_details_);
460 1299139 : recv_status_ = nullptr;
461 : }
462 :
463 : private:
464 : std::multimap<grpc::string_ref, grpc::string_ref>* recv_trailing_metadata_;
465 : Status* recv_status_;
466 : grpc_metadata_array recv_trailing_metadata_arr_;
467 : grpc_status_code status_code_;
468 : char* status_details_;
469 : size_t status_details_capacity_;
470 : };
471 :
472 : /// An abstract collection of call ops, used to generate the
473 : /// grpc_call_op structure to pass down to the lower layers,
474 : /// and as it is-a CompletionQueueTag, also massages the final
475 : /// completion into the correct form for consumption in the C++
476 : /// API.
477 10278235 : class CallOpSetInterface : public CompletionQueueTag {
478 : public:
479 7924932 : CallOpSetInterface() : max_message_size_(0) {}
480 : /// Fills in grpc_op, starting from ops[*nops] and moving
481 : /// upwards.
482 : virtual void FillOps(grpc_op* ops, size_t* nops) = 0;
483 :
484 200971 : void set_max_message_size(int max_message_size) {
485 200971 : max_message_size_ = max_message_size;
486 200971 : }
487 :
488 : protected:
489 : int max_message_size_;
490 : };
491 :
492 : /// Primary implementaiton of CallOpSetInterface.
493 : /// Since we cannot use variadic templates, we declare slots up to
494 : /// the maximum count of ops we'll need in a set. We leverage the
495 : /// empty base class optimization to slim this class (especially
496 : /// when there are many unused slots used). To avoid duplicate base classes,
497 : /// the template parmeter for CallNoOp is varied by argument position.
498 : template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
499 : class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
500 : class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
501 9027106 : class CallOpSet : public CallOpSetInterface,
502 : public Op1,
503 : public Op2,
504 : public Op3,
505 : public Op4,
506 : public Op5,
507 : public Op6 {
508 : public:
509 6648076 : CallOpSet() : return_tag_(this) {}
510 4133011 : void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE {
511 4133011 : this->Op1::AddOp(ops, nops);
512 4133402 : this->Op2::AddOp(ops, nops);
513 4133437 : this->Op3::AddOp(ops, nops);
514 4133364 : this->Op4::AddOp(ops, nops);
515 4132629 : this->Op5::AddOp(ops, nops);
516 4133352 : this->Op6::AddOp(ops, nops);
517 4133237 : }
518 :
519 4133334 : bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
520 4133334 : this->Op1::FinishOp(status, max_message_size_);
521 4133366 : this->Op2::FinishOp(status, max_message_size_);
522 4133298 : this->Op3::FinishOp(status, max_message_size_);
523 4133431 : this->Op4::FinishOp(status, max_message_size_);
524 4133450 : this->Op5::FinishOp(status, max_message_size_);
525 4133449 : this->Op6::FinishOp(status, max_message_size_);
526 4133414 : *tag = return_tag_;
527 4133414 : return true;
528 : }
529 :
530 2384023 : void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
531 :
532 : private:
533 : void* return_tag_;
534 : };
535 :
536 : /// A CallOpSet that does not post completions to the completion queue.
537 : ///
538 : /// Allows hiding some completions that the C core must generate from
539 : /// C++ users.
540 : template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
541 : class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
542 : class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
543 2278566 : class SneakyCallOpSet : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
544 : public:
545 1139602 : bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
546 : typedef CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> Base;
547 1139602 : return Base::FinalizeResult(tag, status) && false;
548 : }
549 : };
550 :
551 : // Channel and Server implement this to allow them to hook performing ops
552 341 : class CallHook {
553 : public:
554 341 : virtual ~CallHook() {}
555 : virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
556 : };
557 :
558 : // Straightforward wrapping of the C call object
559 : class Call GRPC_FINAL {
560 : public:
561 : /* call is owned by the caller */
562 : Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq);
563 : Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq,
564 : int max_message_size);
565 :
566 : void PerformOps(CallOpSetInterface* ops);
567 :
568 5414921 : grpc_call* call() { return call_; }
569 304160 : CompletionQueue* cq() { return cq_; }
570 :
571 159512 : int max_message_size() { return max_message_size_; }
572 :
573 : private:
574 : CallHook* call_hook_;
575 : CompletionQueue* cq_;
576 : grpc_call* call_;
577 : int max_message_size_;
578 : };
579 :
580 : } // namespace grpc
581 :
582 : #endif // GRPCXX_IMPL_CALL_H
|