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 7316545 : WriteOptions() : flags_(0) {}
67 : WriteOptions(const WriteOptions& other) : flags_(other.flags_) {}
68 :
69 : /// Clear all flags.
70 3756022 : inline void Clear() { flags_ = 0; }
71 :
72 : /// Returns raw flags bitset.
73 3755132 : 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 5198878 : WriteOptions& operator=(const WriteOptions& rhs) {
124 5198878 : flags_ = rhs.flags_;
125 5198878 : 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 30761224 : class CallNoOp {
142 : protected:
143 17701747 : void AddOp(grpc_op* ops, size_t* nops) {}
144 17713344 : void FinishOp(bool* status, int max_message_size) {}
145 : };
146 :
147 : class CallOpSendInitialMetadata {
148 : public:
149 5023731 : CallOpSendInitialMetadata() : send_(false) {}
150 :
151 3288553 : void SendInitialMetadata(
152 : const std::multimap<grpc::string, grpc::string>& metadata) {
153 3288553 : send_ = true;
154 3288553 : initial_metadata_count_ = metadata.size();
155 3290846 : initial_metadata_ = FillMetadataArray(metadata);
156 3291206 : }
157 :
158 : protected:
159 3529383 : void AddOp(grpc_op* ops, size_t* nops) {
160 7058766 : if (!send_) return;
161 3288229 : grpc_op* op = &ops[(*nops)++];
162 3288229 : op->op = GRPC_OP_SEND_INITIAL_METADATA;
163 3288229 : op->flags = 0;
164 3288229 : op->reserved = NULL;
165 3288229 : op->data.send_initial_metadata.count = initial_metadata_count_;
166 3288229 : op->data.send_initial_metadata.metadata = initial_metadata_;
167 : }
168 3534079 : void FinishOp(bool* status, int max_message_size) {
169 7067890 : if (!send_) return;
170 3292925 : gpr_free(initial_metadata_);
171 3292657 : send_ = false;
172 : }
173 :
174 : bool send_;
175 : size_t initial_metadata_count_;
176 : grpc_metadata* initial_metadata_;
177 : };
178 :
179 1447811 : class CallOpSendMessage {
180 : public:
181 3574362 : 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 3753850 : void AddOp(grpc_op* ops, size_t* nops) {
194 7509708 : if (send_buf_ == nullptr) return;
195 3753831 : grpc_op* op = &ops[(*nops)++];
196 3753831 : op->op = GRPC_OP_SEND_MESSAGE;
197 3753831 : op->flags = write_options_.flags();
198 3755870 : op->reserved = NULL;
199 3755870 : op->data.send_message = send_buf_;
200 : // Flags are per-message: clear them after use.
201 3755870 : write_options_.Clear();
202 : }
203 3757026 : void FinishOp(bool* status, int max_message_size) {
204 3757026 : if (own_buf_) grpc_byte_buffer_destroy(send_buf_);
205 3756950 : send_buf_ = nullptr;
206 3756950 : }
207 :
208 : private:
209 : grpc_byte_buffer* send_buf_;
210 : WriteOptions write_options_;
211 : bool own_buf_;
212 : };
213 :
214 : template <class M>
215 3756967 : Status CallOpSendMessage::SendMessage(const M& message,
216 : const WriteOptions& options) {
217 3756967 : write_options_ = options;
218 3757241 : return SerializationTraits<M>::Serialize(message, &send_buf_, &own_buf_);
219 : }
220 :
221 : template <class M>
222 3543033 : Status CallOpSendMessage::SendMessage(const M& message) {
223 3543033 : return SendMessage(message, WriteOptions());
224 : }
225 :
226 : template <class R>
227 : class CallOpRecvMessage {
228 : public:
229 1901472 : CallOpRecvMessage() : got_message(false), message_(nullptr) {}
230 :
231 2110100 : void RecvMessage(R* message) { message_ = message; }
232 :
233 : bool got_message;
234 :
235 : protected:
236 2108877 : void AddOp(grpc_op* ops, size_t* nops) {
237 4217754 : if (message_ == nullptr) return;
238 2108877 : grpc_op* op = &ops[(*nops)++];
239 2108877 : op->op = GRPC_OP_RECV_MESSAGE;
240 2108877 : op->flags = 0;
241 2108877 : op->reserved = NULL;
242 2108877 : op->data.recv_message = &recv_buf_;
243 : }
244 :
245 2110674 : void FinishOp(bool* status, int max_message_size) {
246 4221616 : if (message_ == nullptr) return;
247 2110674 : if (recv_buf_) {
248 2110585 : if (*status) {
249 2110585 : got_message = true;
250 2110585 : *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 2110942 : 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 1646630 : CallOpClientSendClose() : send_(false) {}
335 :
336 1646600 : void ClientSendClose() { send_ = true; }
337 :
338 : protected:
339 1646748 : void AddOp(grpc_op* ops, size_t* nops) {
340 3293496 : if (!send_) return;
341 1646748 : grpc_op* op = &ops[(*nops)++];
342 1646748 : op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
343 1646748 : op->flags = 0;
344 1646748 : op->reserved = NULL;
345 : }
346 1646720 : void FinishOp(bool* status, int max_message_size) { send_ = false; }
347 :
348 : private:
349 : bool send_;
350 : };
351 :
352 3165765 : class CallOpServerSendStatus {
353 : public:
354 1717779 : CallOpServerSendStatus() : send_status_available_(false) {}
355 :
356 1645502 : void ServerSendStatus(
357 : const std::multimap<grpc::string, grpc::string>& trailing_metadata,
358 : const Status& status) {
359 1645502 : trailing_metadata_count_ = trailing_metadata.size();
360 1646576 : trailing_metadata_ = FillMetadataArray(trailing_metadata);
361 1646575 : send_status_available_ = true;
362 1646575 : send_status_code_ = static_cast<grpc_status_code>(status.error_code());
363 1646568 : send_status_details_ = status.error_message();
364 1646659 : }
365 :
366 : protected:
367 1646349 : void AddOp(grpc_op* ops, size_t* nops) {
368 3292955 : if (!send_status_available_) return;
369 1646349 : grpc_op* op = &ops[(*nops)++];
370 1646349 : op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
371 : op->data.send_status_from_server.trailing_metadata_count =
372 1646349 : trailing_metadata_count_;
373 1646349 : op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
374 1646349 : op->data.send_status_from_server.status = send_status_code_;
375 : op->data.send_status_from_server.status_details =
376 1646349 : send_status_details_.empty() ? nullptr : send_status_details_.c_str();
377 1646606 : op->flags = 0;
378 1646606 : op->reserved = NULL;
379 : }
380 :
381 1646629 : void FinishOp(bool* status, int max_message_size) {
382 3293263 : if (!send_status_available_) return;
383 1646629 : gpr_free(trailing_metadata_);
384 1646634 : 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 3197699 : CallOpRecvInitialMetadata() : recv_initial_metadata_(nullptr) {}
398 :
399 1646672 : void RecvInitialMetadata(ClientContext* context) {
400 1646672 : context->initial_metadata_received_ = true;
401 1646672 : recv_initial_metadata_ = &context->recv_initial_metadata_;
402 1646672 : }
403 :
404 : protected:
405 1887753 : void AddOp(grpc_op* ops, size_t* nops) {
406 3775506 : if (!recv_initial_metadata_) return;
407 1646620 : memset(&recv_initial_metadata_arr_, 0, sizeof(recv_initial_metadata_arr_));
408 1646620 : grpc_op* op = &ops[(*nops)++];
409 1646620 : op->op = GRPC_OP_RECV_INITIAL_METADATA;
410 1646620 : op->data.recv_initial_metadata = &recv_initial_metadata_arr_;
411 1646620 : op->flags = 0;
412 1646620 : op->reserved = NULL;
413 : }
414 1887254 : void FinishOp(bool* status, int max_message_size) {
415 3775068 : if (recv_initial_metadata_ == nullptr) return;
416 1646121 : FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
417 1646681 : 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 1646623 : CallOpClientRecvStatus() : recv_status_(nullptr) {}
428 :
429 1646165 : void ClientRecvStatus(ClientContext* context, Status* status) {
430 1646165 : recv_trailing_metadata_ = &context->trailing_metadata_;
431 1646165 : recv_status_ = status;
432 1646165 : }
433 :
434 : protected:
435 1646734 : void AddOp(grpc_op* ops, size_t* nops) {
436 3293468 : if (recv_status_ == nullptr) return;
437 : memset(&recv_trailing_metadata_arr_, 0,
438 1646734 : sizeof(recv_trailing_metadata_arr_));
439 1646734 : status_details_ = nullptr;
440 1646734 : status_details_capacity_ = 0;
441 1646734 : grpc_op* op = &ops[(*nops)++];
442 1646734 : op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
443 : op->data.recv_status_on_client.trailing_metadata =
444 1646734 : &recv_trailing_metadata_arr_;
445 1646734 : op->data.recv_status_on_client.status = &status_code_;
446 1646734 : op->data.recv_status_on_client.status_details = &status_details_;
447 : op->data.recv_status_on_client.status_details_capacity =
448 1646734 : &status_details_capacity_;
449 1646734 : op->flags = 0;
450 1646734 : op->reserved = NULL;
451 : }
452 :
453 1646778 : void FinishOp(bool* status, int max_message_size) {
454 3293478 : if (recv_status_ == nullptr) return;
455 1646778 : FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_);
456 4939598 : *recv_status_ = Status(
457 : static_cast<StatusCode>(status_code_),
458 1646262 : status_details_ ? grpc::string(status_details_) : grpc::string());
459 1646557 : gpr_free(status_details_);
460 1646700 : 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 12775020 : class CallOpSetInterface : public CompletionQueueTag {
478 : public:
479 9868704 : 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 200997 : void set_max_message_size(int max_message_size) {
485 200997 : max_message_size_ = max_message_size;
486 200997 : }
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 11175492 : 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 8257388 : CallOpSet() : return_tag_(this) {}
510 5658292 : void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE {
511 5658292 : this->Op1::AddOp(ops, nops);
512 5659240 : this->Op2::AddOp(ops, nops);
513 5659268 : this->Op3::AddOp(ops, nops);
514 5659086 : this->Op4::AddOp(ops, nops);
515 5658774 : this->Op5::AddOp(ops, nops);
516 5659251 : this->Op6::AddOp(ops, nops);
517 5659234 : }
518 :
519 5658290 : bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
520 5658290 : this->Op1::FinishOp(status, max_message_size_);
521 5659128 : this->Op2::FinishOp(status, max_message_size_);
522 5659221 : this->Op3::FinishOp(status, max_message_size_);
523 5658740 : this->Op4::FinishOp(status, max_message_size_);
524 5659130 : this->Op5::FinishOp(status, max_message_size_);
525 5659214 : this->Op6::FinishOp(status, max_message_size_);
526 5659137 : *tag = return_tag_;
527 5659137 : return true;
528 : }
529 :
530 3373885 : 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 2874307 : class SneakyCallOpSet : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
544 : public:
545 1437222 : bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
546 : typedef CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> Base;
547 1437222 : return Base::FinalizeResult(tag, status) && false;
548 : }
549 : };
550 :
551 : // Channel and Server implement this to allow them to hook performing ops
552 335 : class CallHook {
553 : public:
554 335 : 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 7283291 : grpc_call* call() { return call_; }
569 423647 : CompletionQueue* cq() { return cq_; }
570 :
571 209488 : 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
|