call_op_set.h 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. /*
  2. *
  3. * Copyright 2018 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #ifndef GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H
  19. #define GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H
  20. // IWYU pragma: private
  21. #include <cstring>
  22. #include <map>
  23. #include <memory>
  24. #include <grpc/impl/codegen/compression_types.h>
  25. #include <grpc/impl/codegen/grpc_types.h>
  26. #include <grpcpp/impl/codegen/byte_buffer.h>
  27. #include <grpcpp/impl/codegen/call.h>
  28. #include <grpcpp/impl/codegen/call_hook.h>
  29. #include <grpcpp/impl/codegen/call_op_set_interface.h>
  30. #include <grpcpp/impl/codegen/client_context.h>
  31. #include <grpcpp/impl/codegen/completion_queue.h>
  32. #include <grpcpp/impl/codegen/completion_queue_tag.h>
  33. #include <grpcpp/impl/codegen/config.h>
  34. #include <grpcpp/impl/codegen/core_codegen_interface.h>
  35. #include <grpcpp/impl/codegen/intercepted_channel.h>
  36. #include <grpcpp/impl/codegen/interceptor_common.h>
  37. #include <grpcpp/impl/codegen/serialization_traits.h>
  38. #include <grpcpp/impl/codegen/slice.h>
  39. #include <grpcpp/impl/codegen/string_ref.h>
  40. namespace grpc {
  41. extern CoreCodegenInterface* g_core_codegen_interface;
  42. namespace internal {
  43. class Call;
  44. class CallHook;
  45. // TODO(yangg) if the map is changed before we send, the pointers will be a
  46. // mess. Make sure it does not happen.
  47. inline grpc_metadata* FillMetadataArray(
  48. const std::multimap<std::string, std::string>& metadata,
  49. size_t* metadata_count, const std::string& optional_error_details) {
  50. *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
  51. if (*metadata_count == 0) {
  52. return nullptr;
  53. }
  54. grpc_metadata* metadata_array =
  55. static_cast<grpc_metadata*>(g_core_codegen_interface->gpr_malloc(
  56. (*metadata_count) * sizeof(grpc_metadata)));
  57. size_t i = 0;
  58. for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
  59. metadata_array[i].key = SliceReferencingString(iter->first);
  60. metadata_array[i].value = SliceReferencingString(iter->second);
  61. }
  62. if (!optional_error_details.empty()) {
  63. metadata_array[i].key =
  64. g_core_codegen_interface->grpc_slice_from_static_buffer(
  65. kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
  66. metadata_array[i].value = SliceReferencingString(optional_error_details);
  67. }
  68. return metadata_array;
  69. }
  70. } // namespace internal
  71. /// Per-message write options.
  72. class WriteOptions {
  73. public:
  74. WriteOptions() : flags_(0), last_message_(false) {}
  75. /// Clear all flags.
  76. inline void Clear() { flags_ = 0; }
  77. /// Returns raw flags bitset.
  78. inline uint32_t flags() const { return flags_; }
  79. /// Sets flag for the disabling of compression for the next message write.
  80. ///
  81. /// \sa GRPC_WRITE_NO_COMPRESS
  82. inline WriteOptions& set_no_compression() {
  83. SetBit(GRPC_WRITE_NO_COMPRESS);
  84. return *this;
  85. }
  86. /// Clears flag for the disabling of compression for the next message write.
  87. ///
  88. /// \sa GRPC_WRITE_NO_COMPRESS
  89. inline WriteOptions& clear_no_compression() {
  90. ClearBit(GRPC_WRITE_NO_COMPRESS);
  91. return *this;
  92. }
  93. /// Get value for the flag indicating whether compression for the next
  94. /// message write is forcefully disabled.
  95. ///
  96. /// \sa GRPC_WRITE_NO_COMPRESS
  97. inline bool get_no_compression() const {
  98. return GetBit(GRPC_WRITE_NO_COMPRESS);
  99. }
  100. /// Sets flag indicating that the write may be buffered and need not go out on
  101. /// the wire immediately.
  102. ///
  103. /// \sa GRPC_WRITE_BUFFER_HINT
  104. inline WriteOptions& set_buffer_hint() {
  105. SetBit(GRPC_WRITE_BUFFER_HINT);
  106. return *this;
  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. /// Get value for the flag indicating that the write may be buffered and need
  117. /// not go out on the wire immediately.
  118. ///
  119. /// \sa GRPC_WRITE_BUFFER_HINT
  120. inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
  121. /// corked bit: aliases set_buffer_hint currently, with the intent that
  122. /// set_buffer_hint will be removed in the future
  123. inline WriteOptions& set_corked() {
  124. SetBit(GRPC_WRITE_BUFFER_HINT);
  125. return *this;
  126. }
  127. inline WriteOptions& clear_corked() {
  128. ClearBit(GRPC_WRITE_BUFFER_HINT);
  129. return *this;
  130. }
  131. inline bool is_corked() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
  132. /// last-message bit: indicates this is the last message in a stream
  133. /// client-side: makes Write the equivalent of performing Write, WritesDone
  134. /// in a single step
  135. /// server-side: hold the Write until the service handler returns (sync api)
  136. /// or until Finish is called (async api)
  137. inline WriteOptions& set_last_message() {
  138. last_message_ = true;
  139. return *this;
  140. }
  141. /// Clears flag indicating that this is the last message in a stream,
  142. /// disabling coalescing.
  143. inline WriteOptions& clear_last_message() {
  144. last_message_ = false;
  145. return *this;
  146. }
  147. /// Get value for the flag indicating that this is the last message, and
  148. /// should be coalesced with trailing metadata.
  149. ///
  150. /// \sa GRPC_WRITE_LAST_MESSAGE
  151. bool is_last_message() const { return last_message_; }
  152. /// Guarantee that all bytes have been written to the socket before completing
  153. /// this write (usually writes are completed when they pass flow control).
  154. inline WriteOptions& set_write_through() {
  155. SetBit(GRPC_WRITE_THROUGH);
  156. return *this;
  157. }
  158. inline WriteOptions& clear_write_through() {
  159. ClearBit(GRPC_WRITE_THROUGH);
  160. return *this;
  161. }
  162. inline bool is_write_through() const { return GetBit(GRPC_WRITE_THROUGH); }
  163. private:
  164. void SetBit(const uint32_t mask) { flags_ |= mask; }
  165. void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
  166. bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
  167. uint32_t flags_;
  168. bool last_message_;
  169. };
  170. namespace internal {
  171. /// Default argument for CallOpSet. The Unused parameter is unused by
  172. /// the class, but can be used for generating multiple names for the
  173. /// same thing.
  174. template <int Unused>
  175. class CallNoOp {
  176. protected:
  177. void AddOp(grpc_op* /*ops*/, size_t* /*nops*/) {}
  178. void FinishOp(bool* /*status*/) {}
  179. void SetInterceptionHookPoint(
  180. InterceptorBatchMethodsImpl* /*interceptor_methods*/) {}
  181. void SetFinishInterceptionHookPoint(
  182. InterceptorBatchMethodsImpl* /*interceptor_methods*/) {}
  183. void SetHijackingState(InterceptorBatchMethodsImpl* /*interceptor_methods*/) {
  184. }
  185. };
  186. class CallOpSendInitialMetadata {
  187. public:
  188. CallOpSendInitialMetadata() : send_(false) {
  189. maybe_compression_level_.is_set = false;
  190. }
  191. void SendInitialMetadata(std::multimap<std::string, std::string>* metadata,
  192. uint32_t flags) {
  193. maybe_compression_level_.is_set = false;
  194. send_ = true;
  195. flags_ = flags;
  196. metadata_map_ = metadata;
  197. }
  198. void set_compression_level(grpc_compression_level level) {
  199. maybe_compression_level_.is_set = true;
  200. maybe_compression_level_.level = level;
  201. }
  202. protected:
  203. void AddOp(grpc_op* ops, size_t* nops) {
  204. if (!send_ || hijacked_) return;
  205. grpc_op* op = &ops[(*nops)++];
  206. op->op = GRPC_OP_SEND_INITIAL_METADATA;
  207. op->flags = flags_;
  208. op->reserved = nullptr;
  209. initial_metadata_ =
  210. FillMetadataArray(*metadata_map_, &initial_metadata_count_, "");
  211. op->data.send_initial_metadata.count = initial_metadata_count_;
  212. op->data.send_initial_metadata.metadata = initial_metadata_;
  213. op->data.send_initial_metadata.maybe_compression_level.is_set =
  214. maybe_compression_level_.is_set;
  215. if (maybe_compression_level_.is_set) {
  216. op->data.send_initial_metadata.maybe_compression_level.level =
  217. maybe_compression_level_.level;
  218. }
  219. }
  220. void FinishOp(bool* /*status*/) {
  221. if (!send_ || hijacked_) return;
  222. g_core_codegen_interface->gpr_free(initial_metadata_);
  223. send_ = false;
  224. }
  225. void SetInterceptionHookPoint(
  226. InterceptorBatchMethodsImpl* interceptor_methods) {
  227. if (!send_) return;
  228. interceptor_methods->AddInterceptionHookPoint(
  229. experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA);
  230. interceptor_methods->SetSendInitialMetadata(metadata_map_);
  231. }
  232. void SetFinishInterceptionHookPoint(
  233. InterceptorBatchMethodsImpl* /*interceptor_methods*/) {}
  234. void SetHijackingState(InterceptorBatchMethodsImpl* /*interceptor_methods*/) {
  235. hijacked_ = true;
  236. }
  237. bool hijacked_ = false;
  238. bool send_;
  239. uint32_t flags_;
  240. size_t initial_metadata_count_;
  241. std::multimap<std::string, std::string>* metadata_map_;
  242. grpc_metadata* initial_metadata_;
  243. struct {
  244. bool is_set;
  245. grpc_compression_level level;
  246. } maybe_compression_level_;
  247. };
  248. class CallOpSendMessage {
  249. public:
  250. CallOpSendMessage() : send_buf_() {}
  251. /// Send \a message using \a options for the write. The \a options are cleared
  252. /// after use.
  253. template <class M>
  254. Status SendMessage(const M& message,
  255. WriteOptions options) GRPC_MUST_USE_RESULT;
  256. template <class M>
  257. Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
  258. /// Send \a message using \a options for the write. The \a options are cleared
  259. /// after use. This form of SendMessage allows gRPC to reference \a message
  260. /// beyond the lifetime of SendMessage.
  261. template <class M>
  262. Status SendMessagePtr(const M* message,
  263. WriteOptions options) GRPC_MUST_USE_RESULT;
  264. /// This form of SendMessage allows gRPC to reference \a message beyond the
  265. /// lifetime of SendMessage.
  266. template <class M>
  267. Status SendMessagePtr(const M* message) GRPC_MUST_USE_RESULT;
  268. protected:
  269. void AddOp(grpc_op* ops, size_t* nops) {
  270. if (msg_ == nullptr && !send_buf_.Valid()) return;
  271. if (hijacked_) {
  272. serializer_ = nullptr;
  273. return;
  274. }
  275. if (msg_ != nullptr) {
  276. GPR_CODEGEN_ASSERT(serializer_(msg_).ok());
  277. }
  278. serializer_ = nullptr;
  279. grpc_op* op = &ops[(*nops)++];
  280. op->op = GRPC_OP_SEND_MESSAGE;
  281. op->flags = write_options_.flags();
  282. op->reserved = nullptr;
  283. op->data.send_message.send_message = send_buf_.c_buffer();
  284. // Flags are per-message: clear them after use.
  285. write_options_.Clear();
  286. }
  287. void FinishOp(bool* status) {
  288. if (msg_ == nullptr && !send_buf_.Valid()) return;
  289. send_buf_.Clear();
  290. if (hijacked_ && failed_send_) {
  291. // Hijacking interceptor failed this Op
  292. *status = false;
  293. } else if (!*status) {
  294. // This Op was passed down to core and the Op failed
  295. failed_send_ = true;
  296. }
  297. }
  298. void SetInterceptionHookPoint(
  299. InterceptorBatchMethodsImpl* interceptor_methods) {
  300. if (msg_ == nullptr && !send_buf_.Valid()) return;
  301. interceptor_methods->AddInterceptionHookPoint(
  302. experimental::InterceptionHookPoints::PRE_SEND_MESSAGE);
  303. interceptor_methods->SetSendMessage(&send_buf_, &msg_, &failed_send_,
  304. serializer_);
  305. }
  306. void SetFinishInterceptionHookPoint(
  307. InterceptorBatchMethodsImpl* interceptor_methods) {
  308. if (msg_ != nullptr || send_buf_.Valid()) {
  309. interceptor_methods->AddInterceptionHookPoint(
  310. experimental::InterceptionHookPoints::POST_SEND_MESSAGE);
  311. }
  312. send_buf_.Clear();
  313. msg_ = nullptr;
  314. // The contents of the SendMessage value that was previously set
  315. // has had its references stolen by core's operations
  316. interceptor_methods->SetSendMessage(nullptr, nullptr, &failed_send_,
  317. nullptr);
  318. }
  319. void SetHijackingState(InterceptorBatchMethodsImpl* /*interceptor_methods*/) {
  320. hijacked_ = true;
  321. }
  322. private:
  323. const void* msg_ = nullptr; // The original non-serialized message
  324. bool hijacked_ = false;
  325. bool failed_send_ = false;
  326. ByteBuffer send_buf_;
  327. WriteOptions write_options_;
  328. std::function<Status(const void*)> serializer_;
  329. };
  330. template <class M>
  331. Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
  332. write_options_ = options;
  333. // Serialize immediately since we do not have access to the message pointer
  334. bool own_buf;
  335. // TODO(vjpai): Remove the void below when possible
  336. // The void in the template parameter below should not be needed
  337. // (since it should be implicit) but is needed due to an observed
  338. // difference in behavior between clang and gcc for certain internal users
  339. Status result = SerializationTraits<M, void>::Serialize(
  340. message, send_buf_.bbuf_ptr(), &own_buf);
  341. if (!own_buf) {
  342. send_buf_.Duplicate();
  343. }
  344. return result;
  345. }
  346. template <class M>
  347. Status CallOpSendMessage::SendMessage(const M& message) {
  348. return SendMessage(message, WriteOptions());
  349. }
  350. template <class M>
  351. Status CallOpSendMessage::SendMessagePtr(const M* message,
  352. WriteOptions options) {
  353. msg_ = message;
  354. write_options_ = options;
  355. // Store the serializer for later since we have access to the message
  356. serializer_ = [this](const void* message) {
  357. bool own_buf;
  358. // TODO(vjpai): Remove the void below when possible
  359. // The void in the template parameter below should not be needed
  360. // (since it should be implicit) but is needed due to an observed
  361. // difference in behavior between clang and gcc for certain internal users
  362. Status result = SerializationTraits<M, void>::Serialize(
  363. *static_cast<const M*>(message), send_buf_.bbuf_ptr(), &own_buf);
  364. if (!own_buf) {
  365. send_buf_.Duplicate();
  366. }
  367. return result;
  368. };
  369. return Status();
  370. }
  371. template <class M>
  372. Status CallOpSendMessage::SendMessagePtr(const M* message) {
  373. return SendMessagePtr(message, WriteOptions());
  374. }
  375. template <class R>
  376. class CallOpRecvMessage {
  377. public:
  378. void RecvMessage(R* message) { message_ = message; }
  379. // Do not change status if no message is received.
  380. void AllowNoMessage() { allow_not_getting_message_ = true; }
  381. bool got_message = false;
  382. protected:
  383. void AddOp(grpc_op* ops, size_t* nops) {
  384. if (message_ == nullptr || hijacked_) return;
  385. grpc_op* op = &ops[(*nops)++];
  386. op->op = GRPC_OP_RECV_MESSAGE;
  387. op->flags = 0;
  388. op->reserved = nullptr;
  389. op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
  390. }
  391. void FinishOp(bool* status) {
  392. if (message_ == nullptr) return;
  393. if (recv_buf_.Valid()) {
  394. if (*status) {
  395. got_message = *status =
  396. SerializationTraits<R>::Deserialize(recv_buf_.bbuf_ptr(), message_)
  397. .ok();
  398. recv_buf_.Release();
  399. } else {
  400. got_message = false;
  401. recv_buf_.Clear();
  402. }
  403. } else if (hijacked_) {
  404. if (hijacked_recv_message_failed_) {
  405. FinishOpRecvMessageFailureHandler(status);
  406. } else {
  407. // The op was hijacked and it was successful. There is no further action
  408. // to be performed since the message is already in its non-serialized
  409. // form.
  410. }
  411. } else {
  412. FinishOpRecvMessageFailureHandler(status);
  413. }
  414. }
  415. void SetInterceptionHookPoint(
  416. InterceptorBatchMethodsImpl* interceptor_methods) {
  417. if (message_ == nullptr) return;
  418. interceptor_methods->SetRecvMessage(message_,
  419. &hijacked_recv_message_failed_);
  420. }
  421. void SetFinishInterceptionHookPoint(
  422. InterceptorBatchMethodsImpl* interceptor_methods) {
  423. if (message_ == nullptr) return;
  424. interceptor_methods->AddInterceptionHookPoint(
  425. experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
  426. if (!got_message) interceptor_methods->SetRecvMessage(nullptr, nullptr);
  427. }
  428. void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
  429. hijacked_ = true;
  430. if (message_ == nullptr) return;
  431. interceptor_methods->AddInterceptionHookPoint(
  432. experimental::InterceptionHookPoints::PRE_RECV_MESSAGE);
  433. got_message = true;
  434. }
  435. private:
  436. // Sets got_message and \a status for a failed recv message op
  437. void FinishOpRecvMessageFailureHandler(bool* status) {
  438. got_message = false;
  439. if (!allow_not_getting_message_) {
  440. *status = false;
  441. }
  442. }
  443. R* message_ = nullptr;
  444. ByteBuffer recv_buf_;
  445. bool allow_not_getting_message_ = false;
  446. bool hijacked_ = false;
  447. bool hijacked_recv_message_failed_ = false;
  448. };
  449. class DeserializeFunc {
  450. public:
  451. virtual Status Deserialize(ByteBuffer* buf) = 0;
  452. virtual ~DeserializeFunc() {}
  453. };
  454. template <class R>
  455. class DeserializeFuncType final : public DeserializeFunc {
  456. public:
  457. explicit DeserializeFuncType(R* message) : message_(message) {}
  458. Status Deserialize(ByteBuffer* buf) override {
  459. return SerializationTraits<R>::Deserialize(buf->bbuf_ptr(), message_);
  460. }
  461. ~DeserializeFuncType() override {}
  462. private:
  463. R* message_; // Not a managed pointer because management is external to this
  464. };
  465. class CallOpGenericRecvMessage {
  466. public:
  467. template <class R>
  468. void RecvMessage(R* message) {
  469. // Use an explicit base class pointer to avoid resolution error in the
  470. // following unique_ptr::reset for some old implementations.
  471. DeserializeFunc* func = new DeserializeFuncType<R>(message);
  472. deserialize_.reset(func);
  473. message_ = message;
  474. }
  475. // Do not change status if no message is received.
  476. void AllowNoMessage() { allow_not_getting_message_ = true; }
  477. bool got_message = false;
  478. protected:
  479. void AddOp(grpc_op* ops, size_t* nops) {
  480. if (!deserialize_ || hijacked_) return;
  481. grpc_op* op = &ops[(*nops)++];
  482. op->op = GRPC_OP_RECV_MESSAGE;
  483. op->flags = 0;
  484. op->reserved = nullptr;
  485. op->data.recv_message.recv_message = recv_buf_.c_buffer_ptr();
  486. }
  487. void FinishOp(bool* status) {
  488. if (!deserialize_) return;
  489. if (recv_buf_.Valid()) {
  490. if (*status) {
  491. got_message = true;
  492. *status = deserialize_->Deserialize(&recv_buf_).ok();
  493. recv_buf_.Release();
  494. } else {
  495. got_message = false;
  496. recv_buf_.Clear();
  497. }
  498. } else if (hijacked_) {
  499. if (hijacked_recv_message_failed_) {
  500. FinishOpRecvMessageFailureHandler(status);
  501. } else {
  502. // The op was hijacked and it was successful. There is no further action
  503. // to be performed since the message is already in its non-serialized
  504. // form.
  505. }
  506. } else {
  507. got_message = false;
  508. if (!allow_not_getting_message_) {
  509. *status = false;
  510. }
  511. }
  512. }
  513. void SetInterceptionHookPoint(
  514. InterceptorBatchMethodsImpl* interceptor_methods) {
  515. if (!deserialize_) return;
  516. interceptor_methods->SetRecvMessage(message_,
  517. &hijacked_recv_message_failed_);
  518. }
  519. void SetFinishInterceptionHookPoint(
  520. InterceptorBatchMethodsImpl* interceptor_methods) {
  521. if (!deserialize_) return;
  522. interceptor_methods->AddInterceptionHookPoint(
  523. experimental::InterceptionHookPoints::POST_RECV_MESSAGE);
  524. if (!got_message) interceptor_methods->SetRecvMessage(nullptr, nullptr);
  525. deserialize_.reset();
  526. }
  527. void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
  528. hijacked_ = true;
  529. if (!deserialize_) return;
  530. interceptor_methods->AddInterceptionHookPoint(
  531. experimental::InterceptionHookPoints::PRE_RECV_MESSAGE);
  532. got_message = true;
  533. }
  534. private:
  535. // Sets got_message and \a status for a failed recv message op
  536. void FinishOpRecvMessageFailureHandler(bool* status) {
  537. got_message = false;
  538. if (!allow_not_getting_message_) {
  539. *status = false;
  540. }
  541. }
  542. void* message_ = nullptr;
  543. std::unique_ptr<DeserializeFunc> deserialize_;
  544. ByteBuffer recv_buf_;
  545. bool allow_not_getting_message_ = false;
  546. bool hijacked_ = false;
  547. bool hijacked_recv_message_failed_ = false;
  548. };
  549. class CallOpClientSendClose {
  550. public:
  551. CallOpClientSendClose() : send_(false) {}
  552. void ClientSendClose() { send_ = true; }
  553. protected:
  554. void AddOp(grpc_op* ops, size_t* nops) {
  555. if (!send_ || hijacked_) return;
  556. grpc_op* op = &ops[(*nops)++];
  557. op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  558. op->flags = 0;
  559. op->reserved = nullptr;
  560. }
  561. void FinishOp(bool* /*status*/) { send_ = false; }
  562. void SetInterceptionHookPoint(
  563. InterceptorBatchMethodsImpl* interceptor_methods) {
  564. if (!send_) return;
  565. interceptor_methods->AddInterceptionHookPoint(
  566. experimental::InterceptionHookPoints::PRE_SEND_CLOSE);
  567. }
  568. void SetFinishInterceptionHookPoint(
  569. InterceptorBatchMethodsImpl* /*interceptor_methods*/) {}
  570. void SetHijackingState(InterceptorBatchMethodsImpl* /*interceptor_methods*/) {
  571. hijacked_ = true;
  572. }
  573. private:
  574. bool hijacked_ = false;
  575. bool send_;
  576. };
  577. class CallOpServerSendStatus {
  578. public:
  579. CallOpServerSendStatus() : send_status_available_(false) {}
  580. void ServerSendStatus(
  581. std::multimap<std::string, std::string>* trailing_metadata,
  582. const Status& status) {
  583. send_error_details_ = status.error_details();
  584. metadata_map_ = trailing_metadata;
  585. send_status_available_ = true;
  586. send_status_code_ = static_cast<grpc_status_code>(status.error_code());
  587. send_error_message_ = status.error_message();
  588. }
  589. protected:
  590. void AddOp(grpc_op* ops, size_t* nops) {
  591. if (!send_status_available_ || hijacked_) return;
  592. trailing_metadata_ = FillMetadataArray(
  593. *metadata_map_, &trailing_metadata_count_, send_error_details_);
  594. grpc_op* op = &ops[(*nops)++];
  595. op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
  596. op->data.send_status_from_server.trailing_metadata_count =
  597. trailing_metadata_count_;
  598. op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
  599. op->data.send_status_from_server.status = send_status_code_;
  600. error_message_slice_ = SliceReferencingString(send_error_message_);
  601. op->data.send_status_from_server.status_details =
  602. send_error_message_.empty() ? nullptr : &error_message_slice_;
  603. op->flags = 0;
  604. op->reserved = nullptr;
  605. }
  606. void FinishOp(bool* /*status*/) {
  607. if (!send_status_available_ || hijacked_) return;
  608. g_core_codegen_interface->gpr_free(trailing_metadata_);
  609. send_status_available_ = false;
  610. }
  611. void SetInterceptionHookPoint(
  612. InterceptorBatchMethodsImpl* interceptor_methods) {
  613. if (!send_status_available_) return;
  614. interceptor_methods->AddInterceptionHookPoint(
  615. experimental::InterceptionHookPoints::PRE_SEND_STATUS);
  616. interceptor_methods->SetSendTrailingMetadata(metadata_map_);
  617. interceptor_methods->SetSendStatus(&send_status_code_, &send_error_details_,
  618. &send_error_message_);
  619. }
  620. void SetFinishInterceptionHookPoint(
  621. InterceptorBatchMethodsImpl* /*interceptor_methods*/) {}
  622. void SetHijackingState(InterceptorBatchMethodsImpl* /*interceptor_methods*/) {
  623. hijacked_ = true;
  624. }
  625. private:
  626. bool hijacked_ = false;
  627. bool send_status_available_;
  628. grpc_status_code send_status_code_;
  629. std::string send_error_details_;
  630. std::string send_error_message_;
  631. size_t trailing_metadata_count_;
  632. std::multimap<std::string, std::string>* metadata_map_;
  633. grpc_metadata* trailing_metadata_;
  634. grpc_slice error_message_slice_;
  635. };
  636. class CallOpRecvInitialMetadata {
  637. public:
  638. CallOpRecvInitialMetadata() : metadata_map_(nullptr) {}
  639. void RecvInitialMetadata(grpc::ClientContext* context) {
  640. context->initial_metadata_received_ = true;
  641. metadata_map_ = &context->recv_initial_metadata_;
  642. }
  643. protected:
  644. void AddOp(grpc_op* ops, size_t* nops) {
  645. if (metadata_map_ == nullptr || hijacked_) return;
  646. grpc_op* op = &ops[(*nops)++];
  647. op->op = GRPC_OP_RECV_INITIAL_METADATA;
  648. op->data.recv_initial_metadata.recv_initial_metadata = metadata_map_->arr();
  649. op->flags = 0;
  650. op->reserved = nullptr;
  651. }
  652. void FinishOp(bool* /*status*/) {
  653. if (metadata_map_ == nullptr || hijacked_) return;
  654. }
  655. void SetInterceptionHookPoint(
  656. InterceptorBatchMethodsImpl* interceptor_methods) {
  657. interceptor_methods->SetRecvInitialMetadata(metadata_map_);
  658. }
  659. void SetFinishInterceptionHookPoint(
  660. InterceptorBatchMethodsImpl* interceptor_methods) {
  661. if (metadata_map_ == nullptr) return;
  662. interceptor_methods->AddInterceptionHookPoint(
  663. experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA);
  664. metadata_map_ = nullptr;
  665. }
  666. void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
  667. hijacked_ = true;
  668. if (metadata_map_ == nullptr) return;
  669. interceptor_methods->AddInterceptionHookPoint(
  670. experimental::InterceptionHookPoints::PRE_RECV_INITIAL_METADATA);
  671. }
  672. private:
  673. bool hijacked_ = false;
  674. MetadataMap* metadata_map_;
  675. };
  676. class CallOpClientRecvStatus {
  677. public:
  678. CallOpClientRecvStatus()
  679. : recv_status_(nullptr), debug_error_string_(nullptr) {}
  680. void ClientRecvStatus(grpc::ClientContext* context, Status* status) {
  681. client_context_ = context;
  682. metadata_map_ = &client_context_->trailing_metadata_;
  683. recv_status_ = status;
  684. error_message_ = g_core_codegen_interface->grpc_empty_slice();
  685. }
  686. protected:
  687. void AddOp(grpc_op* ops, size_t* nops) {
  688. if (recv_status_ == nullptr || hijacked_) return;
  689. grpc_op* op = &ops[(*nops)++];
  690. op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  691. op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
  692. op->data.recv_status_on_client.status = &status_code_;
  693. op->data.recv_status_on_client.status_details = &error_message_;
  694. op->data.recv_status_on_client.error_string = &debug_error_string_;
  695. op->flags = 0;
  696. op->reserved = nullptr;
  697. }
  698. void FinishOp(bool* /*status*/) {
  699. if (recv_status_ == nullptr || hijacked_) return;
  700. if (static_cast<StatusCode>(status_code_) == StatusCode::OK) {
  701. *recv_status_ = Status();
  702. GPR_CODEGEN_DEBUG_ASSERT(debug_error_string_ == nullptr);
  703. } else {
  704. *recv_status_ =
  705. Status(static_cast<StatusCode>(status_code_),
  706. GRPC_SLICE_IS_EMPTY(error_message_)
  707. ? std::string()
  708. : std::string(GRPC_SLICE_START_PTR(error_message_),
  709. GRPC_SLICE_END_PTR(error_message_)),
  710. metadata_map_->GetBinaryErrorDetails());
  711. if (debug_error_string_ != nullptr) {
  712. client_context_->set_debug_error_string(debug_error_string_);
  713. g_core_codegen_interface->gpr_free(
  714. const_cast<char*>(debug_error_string_));
  715. }
  716. }
  717. // TODO(soheil): Find callers that set debug string even for status OK,
  718. // and fix them.
  719. g_core_codegen_interface->grpc_slice_unref(error_message_);
  720. }
  721. void SetInterceptionHookPoint(
  722. InterceptorBatchMethodsImpl* interceptor_methods) {
  723. interceptor_methods->SetRecvStatus(recv_status_);
  724. interceptor_methods->SetRecvTrailingMetadata(metadata_map_);
  725. }
  726. void SetFinishInterceptionHookPoint(
  727. InterceptorBatchMethodsImpl* interceptor_methods) {
  728. if (recv_status_ == nullptr) return;
  729. interceptor_methods->AddInterceptionHookPoint(
  730. experimental::InterceptionHookPoints::POST_RECV_STATUS);
  731. recv_status_ = nullptr;
  732. }
  733. void SetHijackingState(InterceptorBatchMethodsImpl* interceptor_methods) {
  734. hijacked_ = true;
  735. if (recv_status_ == nullptr) return;
  736. interceptor_methods->AddInterceptionHookPoint(
  737. experimental::InterceptionHookPoints::PRE_RECV_STATUS);
  738. }
  739. private:
  740. bool hijacked_ = false;
  741. grpc::ClientContext* client_context_;
  742. MetadataMap* metadata_map_;
  743. Status* recv_status_;
  744. const char* debug_error_string_;
  745. grpc_status_code status_code_;
  746. grpc_slice error_message_;
  747. };
  748. template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
  749. class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
  750. class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
  751. class CallOpSet;
  752. /// Primary implementation of CallOpSetInterface.
  753. /// Since we cannot use variadic templates, we declare slots up to
  754. /// the maximum count of ops we'll need in a set. We leverage the
  755. /// empty base class optimization to slim this class (especially
  756. /// when there are many unused slots used). To avoid duplicate base classes,
  757. /// the template parameter for CallNoOp is varied by argument position.
  758. template <class Op1, class Op2, class Op3, class Op4, class Op5, class Op6>
  759. class CallOpSet : public CallOpSetInterface,
  760. public Op1,
  761. public Op2,
  762. public Op3,
  763. public Op4,
  764. public Op5,
  765. public Op6 {
  766. public:
  767. CallOpSet() : core_cq_tag_(this), return_tag_(this) {}
  768. // The copy constructor and assignment operator reset the value of
  769. // core_cq_tag_, return_tag_, done_intercepting_ and interceptor_methods_
  770. // since those are only meaningful on a specific object, not across objects.
  771. CallOpSet(const CallOpSet& other)
  772. : core_cq_tag_(this),
  773. return_tag_(this),
  774. call_(other.call_),
  775. done_intercepting_(false),
  776. interceptor_methods_(InterceptorBatchMethodsImpl()) {}
  777. CallOpSet& operator=(const CallOpSet& other) {
  778. if (&other == this) {
  779. return *this;
  780. }
  781. core_cq_tag_ = this;
  782. return_tag_ = this;
  783. call_ = other.call_;
  784. done_intercepting_ = false;
  785. interceptor_methods_ = InterceptorBatchMethodsImpl();
  786. return *this;
  787. }
  788. void FillOps(Call* call) override {
  789. done_intercepting_ = false;
  790. g_core_codegen_interface->grpc_call_ref(call->call());
  791. call_ =
  792. *call; // It's fine to create a copy of call since it's just pointers
  793. if (RunInterceptors()) {
  794. ContinueFillOpsAfterInterception();
  795. } else {
  796. // After the interceptors are run, ContinueFillOpsAfterInterception will
  797. // be run
  798. }
  799. }
  800. bool FinalizeResult(void** tag, bool* status) override {
  801. if (done_intercepting_) {
  802. // Complete the avalanching since we are done with this batch of ops
  803. call_.cq()->CompleteAvalanching();
  804. // We have already finished intercepting and filling in the results. This
  805. // round trip from the core needed to be made because interceptors were
  806. // run
  807. *tag = return_tag_;
  808. *status = saved_status_;
  809. g_core_codegen_interface->grpc_call_unref(call_.call());
  810. return true;
  811. }
  812. this->Op1::FinishOp(status);
  813. this->Op2::FinishOp(status);
  814. this->Op3::FinishOp(status);
  815. this->Op4::FinishOp(status);
  816. this->Op5::FinishOp(status);
  817. this->Op6::FinishOp(status);
  818. saved_status_ = *status;
  819. if (RunInterceptorsPostRecv()) {
  820. *tag = return_tag_;
  821. g_core_codegen_interface->grpc_call_unref(call_.call());
  822. return true;
  823. }
  824. // Interceptors are going to be run, so we can't return the tag just yet.
  825. // After the interceptors are run, ContinueFinalizeResultAfterInterception
  826. return false;
  827. }
  828. void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
  829. void* core_cq_tag() override { return core_cq_tag_; }
  830. /// set_core_cq_tag is used to provide a different core CQ tag than "this".
  831. /// This is used for callback-based tags, where the core tag is the core
  832. /// callback function. It does not change the use or behavior of any other
  833. /// function (such as FinalizeResult)
  834. void set_core_cq_tag(void* core_cq_tag) { core_cq_tag_ = core_cq_tag; }
  835. // This will be called while interceptors are run if the RPC is a hijacked
  836. // RPC. This should set hijacking state for each of the ops.
  837. void SetHijackingState() override {
  838. this->Op1::SetHijackingState(&interceptor_methods_);
  839. this->Op2::SetHijackingState(&interceptor_methods_);
  840. this->Op3::SetHijackingState(&interceptor_methods_);
  841. this->Op4::SetHijackingState(&interceptor_methods_);
  842. this->Op5::SetHijackingState(&interceptor_methods_);
  843. this->Op6::SetHijackingState(&interceptor_methods_);
  844. }
  845. // Should be called after interceptors are done running
  846. void ContinueFillOpsAfterInterception() override {
  847. static const size_t MAX_OPS = 6;
  848. grpc_op ops[MAX_OPS];
  849. size_t nops = 0;
  850. this->Op1::AddOp(ops, &nops);
  851. this->Op2::AddOp(ops, &nops);
  852. this->Op3::AddOp(ops, &nops);
  853. this->Op4::AddOp(ops, &nops);
  854. this->Op5::AddOp(ops, &nops);
  855. this->Op6::AddOp(ops, &nops);
  856. grpc_call_error err = g_core_codegen_interface->grpc_call_start_batch(
  857. call_.call(), ops, nops, core_cq_tag(), nullptr);
  858. if (err != GRPC_CALL_OK) {
  859. // A failure here indicates an API misuse; for example, doing a Write
  860. // while another Write is already pending on the same RPC or invoking
  861. // WritesDone multiple times
  862. // gpr_log(GPR_ERROR, "API misuse of type %s observed",
  863. // g_core_codegen_interface->grpc_call_error_to_string(err));
  864. GPR_CODEGEN_ASSERT(false);
  865. }
  866. }
  867. // Should be called after interceptors are done running on the finalize result
  868. // path
  869. void ContinueFinalizeResultAfterInterception() override {
  870. done_intercepting_ = true;
  871. // The following call_start_batch is internally-generated so no need for an
  872. // explanatory log on failure.
  873. GPR_CODEGEN_ASSERT(g_core_codegen_interface->grpc_call_start_batch(
  874. call_.call(), nullptr, 0, core_cq_tag(), nullptr) ==
  875. GRPC_CALL_OK);
  876. }
  877. private:
  878. // Returns true if no interceptors need to be run
  879. bool RunInterceptors() {
  880. interceptor_methods_.ClearState();
  881. interceptor_methods_.SetCallOpSetInterface(this);
  882. interceptor_methods_.SetCall(&call_);
  883. this->Op1::SetInterceptionHookPoint(&interceptor_methods_);
  884. this->Op2::SetInterceptionHookPoint(&interceptor_methods_);
  885. this->Op3::SetInterceptionHookPoint(&interceptor_methods_);
  886. this->Op4::SetInterceptionHookPoint(&interceptor_methods_);
  887. this->Op5::SetInterceptionHookPoint(&interceptor_methods_);
  888. this->Op6::SetInterceptionHookPoint(&interceptor_methods_);
  889. if (interceptor_methods_.InterceptorsListEmpty()) {
  890. return true;
  891. }
  892. // This call will go through interceptors and would need to
  893. // schedule new batches, so delay completion queue shutdown
  894. call_.cq()->RegisterAvalanching();
  895. return interceptor_methods_.RunInterceptors();
  896. }
  897. // Returns true if no interceptors need to be run
  898. bool RunInterceptorsPostRecv() {
  899. // Call and OpSet had already been set on the set state.
  900. // SetReverse also clears previously set hook points
  901. interceptor_methods_.SetReverse();
  902. this->Op1::SetFinishInterceptionHookPoint(&interceptor_methods_);
  903. this->Op2::SetFinishInterceptionHookPoint(&interceptor_methods_);
  904. this->Op3::SetFinishInterceptionHookPoint(&interceptor_methods_);
  905. this->Op4::SetFinishInterceptionHookPoint(&interceptor_methods_);
  906. this->Op5::SetFinishInterceptionHookPoint(&interceptor_methods_);
  907. this->Op6::SetFinishInterceptionHookPoint(&interceptor_methods_);
  908. return interceptor_methods_.RunInterceptors();
  909. }
  910. void* core_cq_tag_;
  911. void* return_tag_;
  912. Call call_;
  913. bool done_intercepting_ = false;
  914. InterceptorBatchMethodsImpl interceptor_methods_;
  915. bool saved_status_;
  916. };
  917. } // namespace internal
  918. } // namespace grpc
  919. #endif // GRPCPP_IMPL_CODEGEN_CALL_OP_SET_H