grpc 1.15.0 → 1.16.0.pre1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +158 -80
  3. data/etc/roots.pem +23 -0
  4. data/include/grpc/grpc.h +13 -1
  5. data/include/grpc/grpc_security.h +2 -2
  6. data/include/grpc/grpc_security_constants.h +24 -19
  7. data/include/grpc/impl/codegen/grpc_types.h +23 -5
  8. data/include/grpc/impl/codegen/port_platform.h +1 -0
  9. data/src/core/ext/filters/client_channel/client_channel.cc +95 -10
  10. data/src/core/ext/filters/client_channel/client_channel_channelz.cc +71 -0
  11. data/src/core/ext/filters/client_channel/client_channel_channelz.h +45 -11
  12. data/src/core/ext/filters/client_channel/connector.h +3 -0
  13. data/src/core/ext/filters/client_channel/http_connect_handshaker.cc +1 -1
  14. data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +5 -3
  15. data/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +12 -32
  16. data/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +6 -5
  17. data/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +20 -15
  18. data/src/core/ext/filters/client_channel/lb_policy_factory.h +2 -4
  19. data/src/core/ext/filters/client_channel/parse_address.cc +27 -4
  20. data/src/core/ext/filters/client_channel/parse_address.h +3 -0
  21. data/src/core/ext/filters/client_channel/resolver.h +1 -12
  22. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +1 -11
  23. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +80 -19
  24. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +9 -3
  25. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc +5 -0
  26. data/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc +70 -0
  27. data/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +1 -11
  28. data/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +2 -16
  29. data/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h +2 -1
  30. data/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc +0 -7
  31. data/src/core/ext/filters/client_channel/subchannel.cc +45 -7
  32. data/src/core/ext/filters/client_channel/subchannel.h +16 -1
  33. data/src/core/ext/filters/client_channel/subchannel_index.cc +2 -1
  34. data/src/core/ext/filters/client_channel/subchannel_index.h +1 -4
  35. data/src/core/ext/filters/http/client/http_client_filter.cc +32 -3
  36. data/src/core/ext/filters/http/server/http_server_filter.cc +59 -1
  37. data/src/core/ext/filters/max_age/max_age_filter.cc +1 -2
  38. data/src/core/ext/filters/message_size/message_size_filter.cc +59 -3
  39. data/src/core/ext/transport/chttp2/client/chttp2_connector.cc +2 -0
  40. data/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc +1 -1
  41. data/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc +1 -1
  42. data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +286 -228
  43. data/src/core/ext/transport/chttp2/transport/chttp2_transport.h +2 -0
  44. data/src/core/ext/transport/chttp2/transport/frame_data.cc +4 -0
  45. data/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +14 -3
  46. data/src/core/ext/transport/chttp2/transport/hpack_table.cc +29 -0
  47. data/src/core/ext/transport/chttp2/transport/hpack_table.h +9 -0
  48. data/src/core/ext/transport/chttp2/transport/internal.h +10 -0
  49. data/src/core/ext/transport/chttp2/transport/parsing.cc +85 -54
  50. data/src/core/ext/transport/chttp2/transport/writing.cc +6 -0
  51. data/src/core/lib/channel/channel_trace.cc +51 -56
  52. data/src/core/lib/channel/channel_trace.h +30 -25
  53. data/src/core/lib/channel/channelz.cc +235 -61
  54. data/src/core/lib/channel/channelz.h +179 -48
  55. data/src/core/lib/channel/channelz_registry.cc +95 -23
  56. data/src/core/lib/channel/channelz_registry.h +15 -42
  57. data/src/core/lib/gpr/sync_posix.cc +42 -0
  58. data/src/core/lib/http/httpcli.cc +1 -1
  59. data/src/core/lib/iomgr/buffer_list.cc +134 -0
  60. data/src/core/lib/iomgr/buffer_list.h +96 -0
  61. data/src/core/lib/iomgr/endpoint.cc +2 -2
  62. data/src/core/lib/iomgr/endpoint.h +6 -2
  63. data/src/core/lib/iomgr/endpoint_pair_posix.cc +2 -2
  64. data/src/core/lib/iomgr/error.cc +29 -18
  65. data/src/core/lib/iomgr/error.h +8 -0
  66. data/src/core/lib/iomgr/ev_epoll1_linux.cc +4 -0
  67. data/src/core/lib/iomgr/ev_epollex_linux.cc +4 -0
  68. data/src/core/lib/iomgr/ev_posix.cc +16 -10
  69. data/src/core/lib/iomgr/exec_ctx.h +0 -7
  70. data/src/core/lib/iomgr/{ev_epollsig_linux.h → internal_errqueue.cc} +13 -12
  71. data/src/core/lib/iomgr/internal_errqueue.h +83 -0
  72. data/src/core/lib/iomgr/port.h +11 -2
  73. data/src/core/lib/iomgr/socket_utils_common_posix.cc +90 -0
  74. data/src/core/lib/iomgr/socket_utils_posix.h +7 -0
  75. data/src/core/lib/iomgr/tcp_client_posix.cc +4 -1
  76. data/src/core/lib/iomgr/tcp_custom.cc +1 -1
  77. data/src/core/lib/iomgr/tcp_posix.cc +306 -13
  78. data/src/core/lib/iomgr/tcp_posix.h +3 -0
  79. data/src/core/lib/iomgr/tcp_server_posix.cc +2 -2
  80. data/src/core/lib/iomgr/tcp_server_utils_posix_common.cc +4 -1
  81. data/src/core/lib/iomgr/tcp_windows.cc +1 -1
  82. data/src/core/lib/iomgr/timer_generic.cc +13 -12
  83. data/src/core/lib/iomgr/timer_heap.cc +2 -2
  84. data/src/core/lib/iomgr/timer_heap.h +3 -3
  85. data/src/core/lib/iomgr/timer_manager.cc +28 -3
  86. data/src/core/lib/iomgr/timer_manager.h +2 -2
  87. data/src/core/lib/iomgr/udp_server.cc +1 -1
  88. data/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc +2 -1
  89. data/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc +2 -1
  90. data/src/core/lib/security/security_connector/security_connector.cc +7 -7
  91. data/src/core/lib/security/transport/secure_endpoint.cc +2 -2
  92. data/src/core/lib/security/transport/security_handshaker.cc +1 -1
  93. data/src/core/lib/security/transport/server_auth_filter.cc +53 -4
  94. data/src/core/lib/slice/slice.cc +8 -0
  95. data/src/core/lib/slice/slice_internal.h +5 -0
  96. data/src/core/lib/surface/call.cc +149 -253
  97. data/src/core/lib/surface/call.h +1 -0
  98. data/src/core/lib/surface/channel.cc +17 -13
  99. data/src/core/lib/surface/completion_queue.cc +21 -17
  100. data/src/core/lib/surface/completion_queue.h +1 -18
  101. data/src/core/lib/surface/completion_queue_factory.cc +3 -3
  102. data/src/core/lib/surface/init_secure.cc +1 -1
  103. data/src/core/lib/surface/server.cc +77 -4
  104. data/src/core/lib/surface/server.h +4 -0
  105. data/src/core/lib/surface/version.cc +2 -2
  106. data/src/core/lib/transport/metadata.cc +0 -18
  107. data/src/core/lib/transport/metadata.h +0 -3
  108. data/src/core/lib/transport/metadata_batch.cc +2 -2
  109. data/src/core/lib/transport/metadata_batch.h +2 -0
  110. data/src/core/lib/transport/static_metadata.cc +220 -249
  111. data/src/core/lib/transport/static_metadata.h +189 -191
  112. data/src/core/tsi/alts/handshaker/alts_handshaker_client.cc +5 -4
  113. data/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc +3 -1
  114. data/src/core/tsi/alts/handshaker/alts_tsi_event.cc +4 -2
  115. data/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc +6 -5
  116. data/src/core/tsi/alts/handshaker/alts_tsi_utils.cc +3 -1
  117. data/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc +2 -2
  118. data/src/core/tsi/alts_transport_security.cc +3 -1
  119. data/src/core/tsi/ssl/session_cache/ssl_session_cache.cc +2 -1
  120. data/src/ruby/ext/grpc/rb_call.c +1 -0
  121. data/src/ruby/ext/grpc/rb_channel.c +3 -0
  122. data/src/ruby/ext/grpc/rb_grpc.c +31 -1
  123. data/src/ruby/ext/grpc/rb_grpc.h +2 -0
  124. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +6 -0
  125. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +12 -3
  126. data/src/ruby/ext/grpc/rb_server.c +2 -0
  127. data/src/ruby/lib/grpc/errors.rb +0 -1
  128. data/src/ruby/lib/grpc/generic/rpc_desc.rb +3 -3
  129. data/src/ruby/lib/grpc/generic/rpc_server.rb +1 -1
  130. data/src/ruby/lib/grpc/version.rb +1 -1
  131. data/src/ruby/spec/channel_spec.rb +44 -0
  132. data/src/ruby/spec/client_auth_spec.rb +5 -5
  133. data/src/ruby/spec/generic/client_stub_spec.rb +13 -9
  134. data/src/ruby/spec/generic/rpc_server_spec.rb +3 -3
  135. data/src/ruby/spec/pb/codegen/package_option_spec.rb +53 -0
  136. data/src/ruby/spec/support/services.rb +28 -22
  137. metadata +35 -31
  138. data/src/core/lib/iomgr/ev_epollsig_linux.cc +0 -1743
@@ -88,6 +88,14 @@ static const grpc_slice_refcount_vtable noop_refcount_vtable = {
88
88
  static grpc_slice_refcount noop_refcount = {&noop_refcount_vtable,
89
89
  &noop_refcount};
90
90
 
91
+ size_t grpc_slice_memory_usage(grpc_slice s) {
92
+ if (s.refcount == nullptr || s.refcount == &noop_refcount) {
93
+ return 0;
94
+ } else {
95
+ return s.data.refcounted.length;
96
+ }
97
+ }
98
+
91
99
  grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
92
100
  grpc_slice slice;
93
101
  slice.refcount = &noop_refcount;
@@ -46,4 +46,9 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
46
46
  uint32_t grpc_static_slice_hash(grpc_slice s);
47
47
  int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
48
48
 
49
+ // Returns the memory used by this slice, not counting the slice structure
50
+ // itself. This means that inlined and slices from static strings will return
51
+ // 0. All other slices will return the size of the allocated chars.
52
+ size_t grpc_slice_memory_usage(grpc_slice s);
53
+
49
54
  #endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */
@@ -48,6 +48,7 @@
48
48
  #include "src/core/lib/surface/call_test_only.h"
49
49
  #include "src/core/lib/surface/channel.h"
50
50
  #include "src/core/lib/surface/completion_queue.h"
51
+ #include "src/core/lib/surface/server.h"
51
52
  #include "src/core/lib/surface/validate_metadata.h"
52
53
  #include "src/core/lib/transport/error_utils.h"
53
54
  #include "src/core/lib/transport/metadata.h"
@@ -71,46 +72,6 @@
71
72
  // Used to create arena for the first call.
72
73
  #define ESTIMATED_MDELEM_COUNT 16
73
74
 
74
- /* Status data for a request can come from several sources; this
75
- enumerates them all, and acts as a priority sorting for which
76
- status to return to the application - earlier entries override
77
- later ones */
78
- typedef enum {
79
- /* Status came from the application layer overriding whatever
80
- the wire says */
81
- STATUS_FROM_API_OVERRIDE = 0,
82
- /* Status came from 'the wire' - or somewhere below the surface
83
- layer */
84
- STATUS_FROM_WIRE,
85
- /* Status was created by some internal channel stack operation: must come via
86
- add_batch_error */
87
- STATUS_FROM_CORE,
88
- /* Status was created by some surface error */
89
- STATUS_FROM_SURFACE,
90
- /* Status came from the server sending status */
91
- STATUS_FROM_SERVER_STATUS,
92
- STATUS_SOURCE_COUNT
93
- } status_source;
94
-
95
- typedef struct {
96
- bool is_set;
97
- grpc_error* error;
98
- } received_status;
99
-
100
- static gpr_atm pack_received_status(received_status r) {
101
- return r.is_set ? (1 | (gpr_atm)r.error) : 0;
102
- }
103
-
104
- static received_status unpack_received_status(gpr_atm atm) {
105
- if ((atm & 1) == 0) {
106
- return {false, GRPC_ERROR_NONE};
107
- } else {
108
- return {true, (grpc_error*)(atm & ~static_cast<gpr_atm>(1))};
109
- }
110
- }
111
-
112
- #define MAX_ERRORS_PER_BATCH 4
113
-
114
75
  typedef struct batch_control {
115
76
  grpc_call* call;
116
77
  /* Share memory for cq_completion and notify_tag as they are never needed
@@ -135,10 +96,7 @@ typedef struct batch_control {
135
96
  grpc_closure start_batch;
136
97
  grpc_closure finish_batch;
137
98
  gpr_refcount steps_to_complete;
138
-
139
- grpc_error* errors[MAX_ERRORS_PER_BATCH];
140
- gpr_atm num_errors;
141
-
99
+ gpr_atm batch_error;
142
100
  grpc_transport_stream_op_batch op;
143
101
  } batch_control;
144
102
 
@@ -201,9 +159,6 @@ struct grpc_call {
201
159
  // A char* indicating the peer name.
202
160
  gpr_atm peer_string;
203
161
 
204
- /* Packed received call statuses from various sources */
205
- gpr_atm status[STATUS_SOURCE_COUNT];
206
-
207
162
  /* Call data useful used for reporting. Only valid after the call has
208
163
  * completed */
209
164
  grpc_call_final_info final_info;
@@ -236,6 +191,7 @@ struct grpc_call {
236
191
  grpc_closure receiving_initial_metadata_ready;
237
192
  grpc_closure receiving_trailing_metadata_ready;
238
193
  uint32_t test_only_last_message_flags;
194
+ gpr_atm cancelled;
239
195
 
240
196
  grpc_closure release_call;
241
197
 
@@ -247,8 +203,11 @@ struct grpc_call {
247
203
  } client;
248
204
  struct {
249
205
  int* cancelled;
206
+ // backpointer to owning server if this is a server side call.
207
+ grpc_server* server;
250
208
  } server;
251
209
  } final_op;
210
+ gpr_atm status_error;
252
211
 
253
212
  /* recv_state can contain one of the following values:
254
213
  RECV_NONE : : no initial metadata and messages received
@@ -286,23 +245,15 @@ grpc_core::TraceFlag grpc_compression_trace(false, "compression");
286
245
 
287
246
  static void execute_batch(grpc_call* call, grpc_transport_stream_op_batch* op,
288
247
  grpc_closure* start_batch_closure);
289
- static void cancel_with_status(grpc_call* c, status_source source,
290
- grpc_status_code status,
248
+
249
+ static void cancel_with_status(grpc_call* c, grpc_status_code status,
291
250
  const char* description);
292
- static void cancel_with_error(grpc_call* c, status_source source,
293
- grpc_error* error);
251
+ static void cancel_with_error(grpc_call* c, grpc_error* error);
294
252
  static void destroy_call(void* call_stack, grpc_error* error);
295
253
  static void receiving_slice_ready(void* bctlp, grpc_error* error);
296
- static void get_final_status(
297
- grpc_call* call, void (*set_value)(grpc_status_code code, void* user_data),
298
- void* set_value_user_data, grpc_slice* details, const char** error_string);
299
- static void set_status_value_directly(grpc_status_code status, void* dest);
300
- static void set_status_from_error(grpc_call* call, status_source source,
301
- grpc_error* error);
254
+ static void set_final_status(grpc_call* call, grpc_error* error);
302
255
  static void process_data_after_md(batch_control* bctl);
303
256
  static void post_batch_completion(batch_control* bctl);
304
- static void add_batch_error(batch_control* bctl, grpc_error* error,
305
- bool has_cancelled);
306
257
 
307
258
  static void add_init_error(grpc_error** composite, grpc_error* new_err) {
308
259
  if (new_err == GRPC_ERROR_NONE) return;
@@ -353,6 +304,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
353
304
  gpr_arena_alloc(arena, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) +
354
305
  channel_stack->call_stack_size));
355
306
  gpr_ref_init(&call->ext_ref, 1);
307
+ gpr_atm_no_barrier_store(&call->cancelled, 0);
356
308
  call->arena = arena;
357
309
  grpc_call_combiner_init(&call->call_combiner);
358
310
  *out_call = call;
@@ -362,14 +314,10 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
362
314
  /* Always support no compression */
363
315
  GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_MESSAGE_COMPRESS_NONE);
364
316
  call->is_client = args->server_transport_data == nullptr;
365
- if (call->is_client) {
366
- GRPC_STATS_INC_CLIENT_CALLS_CREATED();
367
- } else {
368
- GRPC_STATS_INC_SERVER_CALLS_CREATED();
369
- }
370
317
  call->stream_op_payload.context = call->context;
371
318
  grpc_slice path = grpc_empty_slice();
372
319
  if (call->is_client) {
320
+ GRPC_STATS_INC_CLIENT_CALLS_CREATED();
373
321
  GPR_ASSERT(args->add_initial_metadata_count <
374
322
  MAX_SEND_EXTRA_METADATA_COUNT);
375
323
  for (i = 0; i < args->add_initial_metadata_count; i++) {
@@ -383,6 +331,8 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
383
331
  call->send_extra_metadata_count =
384
332
  static_cast<int>(args->add_initial_metadata_count);
385
333
  } else {
334
+ GRPC_STATS_INC_SERVER_CALLS_CREATED();
335
+ call->final_op.server.server = args->server;
386
336
  GPR_ASSERT(args->add_initial_metadata_count == 0);
387
337
  call->send_extra_metadata_count = 0;
388
338
  }
@@ -464,10 +414,10 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
464
414
  gpr_mu_unlock(&pc->child_list_mu);
465
415
  }
466
416
  if (error != GRPC_ERROR_NONE) {
467
- cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
417
+ cancel_with_error(call, GRPC_ERROR_REF(error));
468
418
  }
469
419
  if (immediately_cancel) {
470
- cancel_with_error(call, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED);
420
+ cancel_with_error(call, GRPC_ERROR_CANCELLED);
471
421
  }
472
422
  if (args->cq != nullptr) {
473
423
  GPR_ASSERT(args->pollset_set_alternative == nullptr &&
@@ -486,10 +436,18 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
486
436
  &call->pollent);
487
437
  }
488
438
 
489
- grpc_core::channelz::ChannelNode* channelz_channel =
490
- grpc_channel_get_channelz_node(call->channel);
491
- if (channelz_channel != nullptr) {
492
- channelz_channel->RecordCallStarted();
439
+ if (call->is_client) {
440
+ grpc_core::channelz::ChannelNode* channelz_channel =
441
+ grpc_channel_get_channelz_node(call->channel);
442
+ if (channelz_channel != nullptr) {
443
+ channelz_channel->RecordCallStarted();
444
+ }
445
+ } else {
446
+ grpc_core::channelz::ServerNode* channelz_server =
447
+ grpc_server_get_channelz_node(call->final_op.server.server);
448
+ if (channelz_server != nullptr) {
449
+ channelz_server->RecordCallStarted();
450
+ }
493
451
  }
494
452
 
495
453
  grpc_slice_unref_internal(path);
@@ -561,16 +519,15 @@ static void destroy_call(void* call, grpc_error* error) {
561
519
  GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
562
520
  }
563
521
 
564
- get_final_status(c, set_status_value_directly, &c->final_info.final_status,
565
- nullptr, &(c->final_info.error_string));
522
+ grpc_error* status_error =
523
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&c->status_error));
524
+ grpc_error_get_status(status_error, c->send_deadline,
525
+ &c->final_info.final_status, nullptr, nullptr,
526
+ &(c->final_info.error_string));
527
+ GRPC_ERROR_UNREF(status_error);
566
528
  c->final_info.stats.latency =
567
529
  gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
568
530
 
569
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
570
- GRPC_ERROR_UNREF(
571
- unpack_received_status(gpr_atm_acq_load(&c->status[i])).error);
572
- }
573
-
574
531
  grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c), &c->final_info,
575
532
  GRPC_CLOSURE_INIT(&c->release_call, release_call, c,
576
533
  grpc_schedule_on_exec_ctx));
@@ -608,7 +565,7 @@ void grpc_call_unref(grpc_call* c) {
608
565
  bool cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) != 0 &&
609
566
  gpr_atm_acq_load(&c->received_final_op_atm) == 0;
610
567
  if (cancel) {
611
- cancel_with_error(c, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED);
568
+ cancel_with_error(c, GRPC_ERROR_CANCELLED);
612
569
  } else {
613
570
  // Unset the call combiner cancellation closure. This has the
614
571
  // effect of scheduling the previously set cancellation closure, if
@@ -626,8 +583,7 @@ grpc_call_error grpc_call_cancel(grpc_call* call, void* reserved) {
626
583
  GRPC_API_TRACE("grpc_call_cancel(call=%p, reserved=%p)", 2, (call, reserved));
627
584
  GPR_ASSERT(!reserved);
628
585
  grpc_core::ExecCtx exec_ctx;
629
- cancel_with_error(call, STATUS_FROM_API_OVERRIDE, GRPC_ERROR_CANCELLED);
630
-
586
+ cancel_with_error(call, GRPC_ERROR_CANCELLED);
631
587
  return GRPC_CALL_OK;
632
588
  }
633
589
 
@@ -681,8 +637,7 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call* c,
681
637
  "c=%p, status=%d, description=%s, reserved=%p)",
682
638
  4, (c, (int)status, description, reserved));
683
639
  GPR_ASSERT(reserved == nullptr);
684
- cancel_with_status(c, STATUS_FROM_API_OVERRIDE, status, description);
685
-
640
+ cancel_with_status(c, status, description);
686
641
  return GRPC_CALL_OK;
687
642
  }
688
643
 
@@ -702,15 +657,17 @@ static void done_termination(void* arg, grpc_error* error) {
702
657
  gpr_free(state);
703
658
  }
704
659
 
705
- static void cancel_with_error(grpc_call* c, status_source source,
706
- grpc_error* error) {
660
+ static void cancel_with_error(grpc_call* c, grpc_error* error) {
661
+ if (!gpr_atm_rel_cas(&c->cancelled, 0, 1)) {
662
+ GRPC_ERROR_UNREF(error);
663
+ return;
664
+ }
707
665
  GRPC_CALL_INTERNAL_REF(c, "termination");
708
666
  // Inform the call combiner of the cancellation, so that it can cancel
709
667
  // any in-flight asynchronous actions that may be holding the call
710
668
  // combiner. This ensures that the cancel_stream batch can be sent
711
669
  // down the filter stack in a timely manner.
712
670
  grpc_call_combiner_cancel(&c->call_combiner, GRPC_ERROR_REF(error));
713
- set_status_from_error(c, source, GRPC_ERROR_REF(error));
714
671
  cancel_state* state = static_cast<cancel_state*>(gpr_malloc(sizeof(*state)));
715
672
  state->call = c;
716
673
  GRPC_CLOSURE_INIT(&state->finish_batch, done_termination, state,
@@ -733,90 +690,47 @@ static grpc_error* error_from_status(grpc_status_code status,
733
690
  GRPC_ERROR_INT_GRPC_STATUS, status);
734
691
  }
735
692
 
736
- static void cancel_with_status(grpc_call* c, status_source source,
737
- grpc_status_code status,
693
+ static void cancel_with_status(grpc_call* c, grpc_status_code status,
738
694
  const char* description) {
739
- cancel_with_error(c, source, error_from_status(status, description));
740
- }
741
-
742
- /*******************************************************************************
743
- * FINAL STATUS CODE MANIPULATION
744
- */
745
-
746
- static bool get_final_status_from(
747
- grpc_call* call, grpc_error* error, bool allow_ok_status,
748
- void (*set_value)(grpc_status_code code, void* user_data),
749
- void* set_value_user_data, grpc_slice* details, const char** error_string) {
750
- grpc_status_code code;
751
- grpc_slice slice = grpc_empty_slice();
752
- grpc_error_get_status(error, call->send_deadline, &code, &slice, nullptr,
753
- error_string);
754
- if (code == GRPC_STATUS_OK && !allow_ok_status) {
755
- return false;
756
- }
757
-
758
- set_value(code, set_value_user_data);
759
- if (details != nullptr) {
760
- *details = grpc_slice_ref_internal(slice);
761
- }
762
- return true;
695
+ cancel_with_error(c, error_from_status(status, description));
763
696
  }
764
697
 
765
- static void get_final_status(
766
- grpc_call* call, void (*set_value)(grpc_status_code code, void* user_data),
767
- void* set_value_user_data, grpc_slice* details, const char** error_string) {
768
- int i;
769
- received_status status[STATUS_SOURCE_COUNT];
770
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
771
- status[i] = unpack_received_status(gpr_atm_acq_load(&call->status[i]));
772
- }
698
+ static void set_final_status(grpc_call* call, grpc_error* error) {
773
699
  if (grpc_call_error_trace.enabled()) {
774
- gpr_log(GPR_INFO, "get_final_status %s", call->is_client ? "CLI" : "SVR");
775
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
776
- if (status[i].is_set) {
777
- gpr_log(GPR_INFO, " %d: %s", i, grpc_error_string(status[i].error));
778
- }
779
- }
700
+ gpr_log(GPR_DEBUG, "set_final_status %s", call->is_client ? "CLI" : "SVR");
701
+ gpr_log(GPR_DEBUG, "%s", grpc_error_string(error));
780
702
  }
781
- /* first search through ignoring "OK" statuses: if something went wrong,
782
- * ensure we report it */
783
- for (int allow_ok_status = 0; allow_ok_status < 2; allow_ok_status++) {
784
- /* search for the best status we can present: ideally the error we use has a
785
- clearly defined grpc-status, and we'll prefer that. */
786
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
787
- if (status[i].is_set &&
788
- grpc_error_has_clear_grpc_status(status[i].error)) {
789
- if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
790
- set_value, set_value_user_data, details,
791
- error_string)) {
792
- return;
793
- }
703
+ if (call->is_client) {
704
+ grpc_error_get_status(error, call->send_deadline,
705
+ call->final_op.client.status,
706
+ call->final_op.client.status_details, nullptr,
707
+ call->final_op.client.error_string);
708
+ // explicitly take a ref
709
+ grpc_slice_ref_internal(*call->final_op.client.status_details);
710
+ gpr_atm_rel_store(&call->status_error, reinterpret_cast<gpr_atm>(error));
711
+ grpc_core::channelz::ChannelNode* channelz_channel =
712
+ grpc_channel_get_channelz_node(call->channel);
713
+ if (channelz_channel != nullptr) {
714
+ if (*call->final_op.client.status != GRPC_STATUS_OK) {
715
+ channelz_channel->RecordCallFailed();
716
+ } else {
717
+ channelz_channel->RecordCallSucceeded();
794
718
  }
795
719
  }
796
- /* If no clearly defined status exists, search for 'anything' */
797
- for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
798
- if (status[i].is_set) {
799
- if (get_final_status_from(call, status[i].error, allow_ok_status != 0,
800
- set_value, set_value_user_data, details,
801
- error_string)) {
802
- return;
803
- }
720
+ } else {
721
+ *call->final_op.server.cancelled =
722
+ error != GRPC_ERROR_NONE ||
723
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&call->status_error)) !=
724
+ GRPC_ERROR_NONE;
725
+ grpc_core::channelz::ServerNode* channelz_server =
726
+ grpc_server_get_channelz_node(call->final_op.server.server);
727
+ if (channelz_server != nullptr) {
728
+ if (*call->final_op.server.cancelled) {
729
+ channelz_server->RecordCallFailed();
730
+ } else {
731
+ channelz_server->RecordCallSucceeded();
804
732
  }
805
733
  }
806
- }
807
- /* If nothing exists, set some default */
808
- if (call->is_client) {
809
- set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
810
- } else {
811
- set_value(GRPC_STATUS_OK, set_value_user_data);
812
- }
813
- }
814
-
815
- static void set_status_from_error(grpc_call* call, status_source source,
816
- grpc_error* error) {
817
- if (!gpr_atm_rel_cas(&call->status[source],
818
- pack_received_status({false, GRPC_ERROR_NONE}),
819
- pack_received_status({true, error}))) {
820
734
  GRPC_ERROR_UNREF(error);
821
735
  }
822
736
  }
@@ -1035,6 +949,7 @@ static grpc_stream_compression_algorithm decode_stream_compression(
1035
949
  static void publish_app_metadata(grpc_call* call, grpc_metadata_batch* b,
1036
950
  int is_trailing) {
1037
951
  if (b->list.count == 0) return;
952
+ if (!call->is_client && is_trailing) return;
1038
953
  if (is_trailing && call->buffered_metadata[1] == nullptr) return;
1039
954
  GPR_TIMER_SCOPE("publish_app_metadata", 0);
1040
955
  grpc_metadata_array* dest;
@@ -1088,9 +1003,12 @@ static void recv_initial_filter(grpc_call* call, grpc_metadata_batch* b) {
1088
1003
  publish_app_metadata(call, b, false);
1089
1004
  }
1090
1005
 
1091
- static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
1006
+ static void recv_trailing_filter(void* args, grpc_metadata_batch* b,
1007
+ grpc_error* batch_error) {
1092
1008
  grpc_call* call = static_cast<grpc_call*>(args);
1093
- if (b->idx.named.grpc_status != nullptr) {
1009
+ if (batch_error != GRPC_ERROR_NONE) {
1010
+ set_final_status(call, batch_error);
1011
+ } else if (b->idx.named.grpc_status != nullptr) {
1094
1012
  grpc_status_code status_code =
1095
1013
  grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
1096
1014
  grpc_error* error = GRPC_ERROR_NONE;
@@ -1108,8 +1026,18 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
1108
1026
  error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
1109
1027
  grpc_empty_slice());
1110
1028
  }
1111
- set_status_from_error(call, STATUS_FROM_WIRE, error);
1029
+ set_final_status(call, GRPC_ERROR_REF(error));
1112
1030
  grpc_metadata_batch_remove(b, b->idx.named.grpc_status);
1031
+ GRPC_ERROR_UNREF(error);
1032
+ } else if (!call->is_client) {
1033
+ set_final_status(call, GRPC_ERROR_NONE);
1034
+ } else {
1035
+ gpr_log(GPR_DEBUG,
1036
+ "Received trailing metadata with no error and no status");
1037
+ set_final_status(
1038
+ call, grpc_error_set_int(
1039
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("No status received"),
1040
+ GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNKNOWN));
1113
1041
  }
1114
1042
  publish_app_metadata(call, b, true);
1115
1043
  }
@@ -1124,14 +1052,6 @@ grpc_call_stack* grpc_call_get_call_stack(grpc_call* call) {
1124
1052
  * BATCH API IMPLEMENTATION
1125
1053
  */
1126
1054
 
1127
- static void set_status_value_directly(grpc_status_code status, void* dest) {
1128
- *static_cast<grpc_status_code*>(dest) = status;
1129
- }
1130
-
1131
- static void set_cancelled_value(grpc_status_code status, void* dest) {
1132
- *static_cast<int*>(dest) = (status != GRPC_STATUS_OK);
1133
- }
1134
-
1135
1055
  static bool are_write_flags_valid(uint32_t flags) {
1136
1056
  /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */
1137
1057
  const uint32_t allowed_write_positions =
@@ -1199,31 +1119,18 @@ static void finish_batch_completion(void* user_data,
1199
1119
  GRPC_CALL_INTERNAL_UNREF(call, "completion");
1200
1120
  }
1201
1121
 
1202
- static grpc_error* consolidate_batch_errors(batch_control* bctl) {
1203
- size_t n = static_cast<size_t>(gpr_atm_acq_load(&bctl->num_errors));
1204
- if (n == 0) {
1205
- return GRPC_ERROR_NONE;
1206
- } else if (n == 1) {
1207
- /* Skip creating a composite error in the case that only one error was
1208
- logged */
1209
- grpc_error* e = bctl->errors[0];
1210
- bctl->errors[0] = nullptr;
1211
- return e;
1212
- } else {
1213
- grpc_error* error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
1214
- "Call batch failed", bctl->errors, n);
1215
- for (size_t i = 0; i < n; i++) {
1216
- GRPC_ERROR_UNREF(bctl->errors[i]);
1217
- bctl->errors[i] = nullptr;
1218
- }
1219
- return error;
1220
- }
1122
+ static void reset_batch_errors(batch_control* bctl) {
1123
+ GRPC_ERROR_UNREF(
1124
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
1125
+ gpr_atm_rel_store(&bctl->batch_error,
1126
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_NONE));
1221
1127
  }
1222
1128
 
1223
1129
  static void post_batch_completion(batch_control* bctl) {
1224
1130
  grpc_call* next_child_call;
1225
1131
  grpc_call* call = bctl->call;
1226
- grpc_error* error = consolidate_batch_errors(bctl);
1132
+ grpc_error* error = GRPC_ERROR_REF(
1133
+ reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)));
1227
1134
 
1228
1135
  if (bctl->op.send_initial_metadata) {
1229
1136
  grpc_metadata_batch_destroy(
@@ -1249,8 +1156,7 @@ static void post_batch_completion(batch_control* bctl) {
1249
1156
  next_child_call = child->child->sibling_next;
1250
1157
  if (child->cancellation_is_inherited) {
1251
1158
  GRPC_CALL_INTERNAL_REF(child, "propagate_cancel");
1252
- cancel_with_error(child, STATUS_FROM_API_OVERRIDE,
1253
- GRPC_ERROR_CANCELLED);
1159
+ cancel_with_error(child, GRPC_ERROR_CANCELLED);
1254
1160
  GRPC_CALL_INTERNAL_UNREF(child, "propagate_cancel");
1255
1161
  }
1256
1162
  child = next_child_call;
@@ -1258,24 +1164,6 @@ static void post_batch_completion(batch_control* bctl) {
1258
1164
  }
1259
1165
  gpr_mu_unlock(&pc->child_list_mu);
1260
1166
  }
1261
- if (call->is_client) {
1262
- get_final_status(call, set_status_value_directly,
1263
- call->final_op.client.status,
1264
- call->final_op.client.status_details,
1265
- call->final_op.client.error_string);
1266
- } else {
1267
- get_final_status(call, set_cancelled_value,
1268
- call->final_op.server.cancelled, nullptr, nullptr);
1269
- }
1270
- grpc_core::channelz::ChannelNode* channelz_channel =
1271
- grpc_channel_get_channelz_node(call->channel);
1272
- if (channelz_channel != nullptr) {
1273
- if (*call->final_op.client.status != GRPC_STATUS_OK) {
1274
- channelz_channel->RecordCallFailed();
1275
- } else {
1276
- channelz_channel->RecordCallSucceeded();
1277
- }
1278
- }
1279
1167
  GRPC_ERROR_UNREF(error);
1280
1168
  error = GRPC_ERROR_NONE;
1281
1169
  }
@@ -1284,9 +1172,10 @@ static void post_batch_completion(batch_control* bctl) {
1284
1172
  grpc_byte_buffer_destroy(*call->receiving_buffer);
1285
1173
  *call->receiving_buffer = nullptr;
1286
1174
  }
1175
+ reset_batch_errors(bctl);
1287
1176
 
1288
1177
  if (bctl->completion_data.notify_tag.is_closure) {
1289
- /* unrefs bctl->error */
1178
+ /* unrefs error */
1290
1179
  bctl->call = nullptr;
1291
1180
  /* This closure may be meant to be run within some combiner. Since we aren't
1292
1181
  * running in any combiner here, we need to use GRPC_CLOSURE_SCHED instead
@@ -1296,7 +1185,7 @@ static void post_batch_completion(batch_control* bctl) {
1296
1185
  error);
1297
1186
  GRPC_CALL_INTERNAL_UNREF(call, "completion");
1298
1187
  } else {
1299
- /* unrefs bctl->error */
1188
+ /* unrefs error */
1300
1189
  grpc_cq_end_op(bctl->call->cq, bctl->completion_data.notify_tag.tag, error,
1301
1190
  finish_batch_completion, bctl,
1302
1191
  &bctl->completion_data.cq_completion);
@@ -1405,8 +1294,12 @@ static void receiving_stream_ready(void* bctlp, grpc_error* error) {
1405
1294
  grpc_call* call = bctl->call;
1406
1295
  if (error != GRPC_ERROR_NONE) {
1407
1296
  call->receiving_stream.reset();
1408
- add_batch_error(bctl, GRPC_ERROR_REF(error), true);
1409
- cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
1297
+ if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
1298
+ GRPC_ERROR_NONE) {
1299
+ gpr_atm_rel_store(&bctl->batch_error,
1300
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
1301
+ }
1302
+ cancel_with_error(call, GRPC_ERROR_REF(error));
1410
1303
  }
1411
1304
  /* If recv_state is RECV_NONE, we will save the batch_control
1412
1305
  * object with rel_cas, and will not use it after the cas. Its corresponding
@@ -1442,8 +1335,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
1442
1335
  call->incoming_stream_compression_algorithm,
1443
1336
  call->incoming_message_compression_algorithm);
1444
1337
  gpr_log(GPR_ERROR, "%s", error_msg);
1445
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_INTERNAL,
1446
- error_msg);
1338
+ cancel_with_status(call, GRPC_STATUS_INTERNAL, error_msg);
1447
1339
  gpr_free(error_msg);
1448
1340
  } else if (
1449
1341
  grpc_compression_algorithm_from_message_stream_compression_algorithm(
@@ -1455,8 +1347,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
1455
1347
  "compression (%d).",
1456
1348
  call->incoming_stream_compression_algorithm,
1457
1349
  call->incoming_message_compression_algorithm);
1458
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_INTERNAL,
1459
- error_msg);
1350
+ cancel_with_status(call, GRPC_STATUS_INTERNAL, error_msg);
1460
1351
  gpr_free(error_msg);
1461
1352
  } else {
1462
1353
  char* error_msg = nullptr;
@@ -1466,8 +1357,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
1466
1357
  gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
1467
1358
  compression_algorithm);
1468
1359
  gpr_log(GPR_ERROR, "%s", error_msg);
1469
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_UNIMPLEMENTED,
1470
- error_msg);
1360
+ cancel_with_status(call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
1471
1361
  } else if (grpc_compression_options_is_algorithm_enabled(
1472
1362
  &compression_options, compression_algorithm) == 0) {
1473
1363
  /* check if algorithm is supported by current channel config */
@@ -1476,8 +1366,7 @@ static void validate_filtered_metadata(batch_control* bctl) {
1476
1366
  gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
1477
1367
  algo_name);
1478
1368
  gpr_log(GPR_ERROR, "%s", error_msg);
1479
- cancel_with_status(call, STATUS_FROM_SURFACE, GRPC_STATUS_UNIMPLEMENTED,
1480
- error_msg);
1369
+ cancel_with_status(call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
1481
1370
  }
1482
1371
  gpr_free(error_msg);
1483
1372
 
@@ -1495,23 +1384,12 @@ static void validate_filtered_metadata(batch_control* bctl) {
1495
1384
  }
1496
1385
  }
1497
1386
 
1498
- static void add_batch_error(batch_control* bctl, grpc_error* error,
1499
- bool has_cancelled) {
1500
- if (error == GRPC_ERROR_NONE) return;
1501
- int idx = static_cast<int>(gpr_atm_full_fetch_add(&bctl->num_errors, 1));
1502
- if (idx == 0 && !has_cancelled) {
1503
- cancel_with_error(bctl->call, STATUS_FROM_CORE, GRPC_ERROR_REF(error));
1504
- }
1505
- bctl->errors[idx] = error;
1506
- }
1507
-
1508
1387
  static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
1509
1388
  batch_control* bctl = static_cast<batch_control*>(bctlp);
1510
1389
  grpc_call* call = bctl->call;
1511
1390
 
1512
1391
  GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_initial_metadata_ready");
1513
1392
 
1514
- add_batch_error(bctl, GRPC_ERROR_REF(error), false);
1515
1393
  if (error == GRPC_ERROR_NONE) {
1516
1394
  grpc_metadata_batch* md =
1517
1395
  &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
@@ -1524,6 +1402,13 @@ static void receiving_initial_metadata_ready(void* bctlp, grpc_error* error) {
1524
1402
  if (md->deadline != GRPC_MILLIS_INF_FUTURE && !call->is_client) {
1525
1403
  call->send_deadline = md->deadline;
1526
1404
  }
1405
+ } else {
1406
+ if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
1407
+ GRPC_ERROR_NONE) {
1408
+ gpr_atm_rel_store(&bctl->batch_error,
1409
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
1410
+ }
1411
+ cancel_with_error(call, GRPC_ERROR_REF(error));
1527
1412
  }
1528
1413
 
1529
1414
  grpc_closure* saved_rsr_closure = nullptr;
@@ -1561,10 +1446,9 @@ static void receiving_trailing_metadata_ready(void* bctlp, grpc_error* error) {
1561
1446
  batch_control* bctl = static_cast<batch_control*>(bctlp);
1562
1447
  grpc_call* call = bctl->call;
1563
1448
  GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_trailing_metadata_ready");
1564
- add_batch_error(bctl, GRPC_ERROR_REF(error), false);
1565
1449
  grpc_metadata_batch* md =
1566
1450
  &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
1567
- recv_trailing_filter(call, md);
1451
+ recv_trailing_filter(call, md, GRPC_ERROR_REF(error));
1568
1452
  finish_batch_step(bctl);
1569
1453
  }
1570
1454
 
@@ -1572,7 +1456,14 @@ static void finish_batch(void* bctlp, grpc_error* error) {
1572
1456
  batch_control* bctl = static_cast<batch_control*>(bctlp);
1573
1457
  grpc_call* call = bctl->call;
1574
1458
  GRPC_CALL_COMBINER_STOP(&call->call_combiner, "on_complete");
1575
- add_batch_error(bctl, GRPC_ERROR_REF(error), false);
1459
+ if (reinterpret_cast<grpc_error*>(gpr_atm_acq_load(&bctl->batch_error)) ==
1460
+ GRPC_ERROR_NONE) {
1461
+ gpr_atm_rel_store(&bctl->batch_error,
1462
+ reinterpret_cast<gpr_atm>(GRPC_ERROR_REF(error)));
1463
+ }
1464
+ if (error != GRPC_ERROR_NONE) {
1465
+ cancel_with_error(call, GRPC_ERROR_REF(error));
1466
+ }
1576
1467
  finish_batch_step(bctl);
1577
1468
  }
1578
1469
 
@@ -1774,28 +1665,33 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
1774
1665
  call->send_extra_metadata_count = 1;
1775
1666
  call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
1776
1667
  call->channel, op->data.send_status_from_server.status);
1777
- {
1778
- grpc_error* override_error = GRPC_ERROR_NONE;
1779
- if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
1780
- override_error =
1781
- error_from_status(op->data.send_status_from_server.status,
1782
- "Returned non-ok status");
1783
- }
1784
- if (op->data.send_status_from_server.status_details != nullptr) {
1785
- call->send_extra_metadata[1].md = grpc_mdelem_from_slices(
1786
- GRPC_MDSTR_GRPC_MESSAGE,
1787
- grpc_slice_ref_internal(
1788
- *op->data.send_status_from_server.status_details));
1789
- call->send_extra_metadata_count++;
1668
+ grpc_error* status_error =
1669
+ op->data.send_status_from_server.status == GRPC_STATUS_OK
1670
+ ? GRPC_ERROR_NONE
1671
+ : grpc_error_set_int(
1672
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1673
+ "Server returned error"),
1674
+ GRPC_ERROR_INT_GRPC_STATUS,
1675
+ static_cast<intptr_t>(
1676
+ op->data.send_status_from_server.status));
1677
+ if (op->data.send_status_from_server.status_details != nullptr) {
1678
+ call->send_extra_metadata[1].md = grpc_mdelem_from_slices(
1679
+ GRPC_MDSTR_GRPC_MESSAGE,
1680
+ grpc_slice_ref_internal(
1681
+ *op->data.send_status_from_server.status_details));
1682
+ call->send_extra_metadata_count++;
1683
+ if (status_error != GRPC_ERROR_NONE) {
1790
1684
  char* msg = grpc_slice_to_c_string(
1791
1685
  GRPC_MDVALUE(call->send_extra_metadata[1].md));
1792
- override_error =
1793
- grpc_error_set_str(override_error, GRPC_ERROR_STR_GRPC_MESSAGE,
1686
+ status_error =
1687
+ grpc_error_set_str(status_error, GRPC_ERROR_STR_GRPC_MESSAGE,
1794
1688
  grpc_slice_from_copied_string(msg));
1795
1689
  gpr_free(msg);
1796
1690
  }
1797
- set_status_from_error(call, STATUS_FROM_API_OVERRIDE, override_error);
1798
1691
  }
1692
+
1693
+ gpr_atm_rel_store(&call->status_error,
1694
+ reinterpret_cast<gpr_atm>(status_error));
1799
1695
  if (!prepare_application_metadata(
1800
1696
  call,
1801
1697
  static_cast<int>(