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
@@ -273,6 +273,10 @@ static gpr_mu fork_fd_list_mu;
273
273
  static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
274
274
 
275
275
  static void fd_global_shutdown(void) {
276
+ // TODO(guantaol): We don't have a reasonable explanation about this
277
+ // lock()/unlock() pattern. It can be a valid barrier if there is at most one
278
+ // pending lock() at this point. Otherwise, there is still a possibility of
279
+ // use-after-free race. Need to reason about the code and/or clean it up.
276
280
  gpr_mu_lock(&fd_freelist_mu);
277
281
  gpr_mu_unlock(&fd_freelist_mu);
278
282
  while (fd_freelist != nullptr) {
@@ -403,6 +403,10 @@ static void unref_by(grpc_fd* fd, int n) {
403
403
  static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
404
404
 
405
405
  static void fd_global_shutdown(void) {
406
+ // TODO(guantaol): We don't have a reasonable explanation about this
407
+ // lock()/unlock() pattern. It can be a valid barrier if there is at most one
408
+ // pending lock() at this point. Otherwise, there is still a possibility of
409
+ // use-after-free race. Need to reason about the code and/or clean it up.
406
410
  gpr_mu_lock(&fd_freelist_mu);
407
411
  gpr_mu_unlock(&fd_freelist_mu);
408
412
  while (fd_freelist != nullptr) {
@@ -35,7 +35,6 @@
35
35
  #include "src/core/lib/gpr/useful.h"
36
36
  #include "src/core/lib/iomgr/ev_epoll1_linux.h"
37
37
  #include "src/core/lib/iomgr/ev_epollex_linux.h"
38
- #include "src/core/lib/iomgr/ev_epollsig_linux.h"
39
38
  #include "src/core/lib/iomgr/ev_poll_posix.h"
40
39
 
41
40
  grpc_core::TraceFlag grpc_polling_trace(false,
@@ -123,13 +122,13 @@ const grpc_event_engine_vtable* init_non_polling(bool explicit_request) {
123
122
  // environment variable if that variable is set (which should be a
124
123
  // comma-separated list of one or more event engine names)
125
124
  static event_engine_factory g_factories[] = {
126
- {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
127
- {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
128
- {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
129
- {"epollsig", grpc_init_epollsig_linux}, {"poll", grpc_init_poll_posix},
130
- {"poll-cv", grpc_init_poll_cv_posix}, {"none", init_non_polling},
131
- {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
132
- {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
125
+ {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
126
+ {ENGINE_HEAD_CUSTOM, nullptr}, {ENGINE_HEAD_CUSTOM, nullptr},
127
+ {"epollex", grpc_init_epollex_linux}, {"epoll1", grpc_init_epoll1_linux},
128
+ {"poll", grpc_init_poll_posix}, {"poll-cv", grpc_init_poll_cv_posix},
129
+ {"none", init_non_polling}, {ENGINE_TAIL_CUSTOM, nullptr},
130
+ {ENGINE_TAIL_CUSTOM, nullptr}, {ENGINE_TAIL_CUSTOM, nullptr},
131
+ {ENGINE_TAIL_CUSTOM, nullptr},
133
132
  };
134
133
 
135
134
  static void add(const char* beg, const char* end, char*** ss, size_t* ns) {
@@ -237,14 +236,19 @@ void grpc_event_engine_shutdown(void) {
237
236
  }
238
237
 
239
238
  bool grpc_event_engine_can_track_errors(void) {
239
+ /* Only track errors if platform supports errqueue. */
240
+ #ifdef GRPC_LINUX_ERRQUEUE
240
241
  return g_event_engine->can_track_err;
242
+ #else
243
+ return false;
244
+ #endif /* GRPC_LINUX_ERRQUEUE */
241
245
  }
242
246
 
243
247
  grpc_fd* grpc_fd_create(int fd, const char* name, bool track_err) {
244
248
  GRPC_POLLING_API_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
245
249
  GRPC_FD_TRACE("fd_create(%d, %s, %d)", fd, name, track_err);
246
- GPR_DEBUG_ASSERT(!track_err || g_event_engine->can_track_err);
247
- return g_event_engine->fd_create(fd, name, track_err);
250
+ return g_event_engine->fd_create(fd, name,
251
+ track_err && g_event_engine->can_track_err);
248
252
  }
249
253
 
250
254
  int grpc_fd_wrapped_fd(grpc_fd* fd) {
@@ -391,4 +395,6 @@ void grpc_pollset_set_del_fd(grpc_pollset_set* pollset_set, grpc_fd* fd) {
391
395
  g_event_engine->pollset_set_del_fd(pollset_set, fd);
392
396
  }
393
397
 
398
+ void grpc_use_signal(int signum) {}
399
+
394
400
  #endif // GRPC_POSIX_SOCKET_EV
@@ -116,12 +116,7 @@ class ExecCtx {
116
116
  ExecCtx(const ExecCtx&) = delete;
117
117
  ExecCtx& operator=(const ExecCtx&) = delete;
118
118
 
119
- /** Return starting_cpu. This is only required for stats collection and is
120
- * hence only defined if GRPC_COLLECT_STATS is enabled.
121
- */
122
- #if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)
123
119
  unsigned starting_cpu() const { return starting_cpu_; }
124
- #endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */
125
120
 
126
121
  struct CombinerData {
127
122
  /* currently active combiner: updated only via combiner.c */
@@ -223,9 +218,7 @@ class ExecCtx {
223
218
  CombinerData combiner_data_ = {nullptr, nullptr};
224
219
  uintptr_t flags_;
225
220
 
226
- #if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)
227
221
  unsigned starting_cpu_ = gpr_cpu_current_cpu();
228
- #endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */
229
222
 
230
223
  bool now_is_valid_ = false;
231
224
  grpc_millis now_ = 0;
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  *
3
- * Copyright 2015 gRPC authors.
3
+ * Copyright 2018 gRPC authors.
4
4
  *
5
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
6
  * you may not use this file except in compliance with the License.
@@ -16,20 +16,21 @@
16
16
  *
17
17
  */
18
18
 
19
- #ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
20
- #define GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H
21
-
22
19
  #include <grpc/support/port_platform.h>
23
20
 
24
- #include "src/core/lib/iomgr/ev_posix.h"
25
21
  #include "src/core/lib/iomgr/port.h"
26
22
 
27
- const grpc_event_engine_vtable* grpc_init_epollsig_linux(bool explicit_request);
23
+ #include "src/core/lib/iomgr/internal_errqueue.h"
24
+
25
+ #ifdef GRPC_POSIX_SOCKET_TCP
28
26
 
29
- #ifdef GRPC_LINUX_EPOLL_CREATE1
30
- void* grpc_fd_get_polling_island(grpc_fd* fd);
31
- void* grpc_pollset_get_polling_island(grpc_pollset* ps);
32
- bool grpc_are_polling_islands_equal(void* p, void* q);
33
- #endif /* defined(GRPC_LINUX_EPOLL_CREATE1) */
27
+ bool kernel_supports_errqueue() {
28
+ #ifdef LINUX_VERSION_CODE
29
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
30
+ return true;
31
+ #endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(4, 0, 0) */
32
+ #endif /* LINUX_VERSION_CODE */
33
+ return false;
34
+ }
34
35
 
35
- #endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */
36
+ #endif /* GRPC_POSIX_SOCKET_TCP */
@@ -0,0 +1,83 @@
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
+
19
+ /* This file contains constants defined in <linux/errqueue.h> and
20
+ * <linux/net_tstamp.h> so as to allow collecting network timestamps in the
21
+ * kernel. This file allows tcp_posix.cc to compile on platforms that do not
22
+ * have <linux/errqueue.h> and <linux/net_tstamp.h>.
23
+ */
24
+
25
+ #ifndef GRPC_CORE_LIB_IOMGR_INTERNAL_ERRQUEUE_H
26
+ #define GRPC_CORE_LIB_IOMGR_INTERNAL_ERRQUEUE_H
27
+
28
+ #include <grpc/support/port_platform.h>
29
+
30
+ #include "src/core/lib/iomgr/port.h"
31
+
32
+ #ifdef GRPC_POSIX_SOCKET_TCP
33
+
34
+ #include <sys/types.h>
35
+ #include <time.h>
36
+
37
+ #ifdef GRPC_LINUX_ERRQUEUE
38
+ #include <linux/errqueue.h>
39
+ #include <linux/net_tstamp.h>
40
+ #include <sys/socket.h>
41
+ #endif /* GRPC_LINUX_ERRQUEUE */
42
+
43
+ namespace grpc_core {
44
+
45
+ #ifdef GRPC_LINUX_ERRQUEUE
46
+
47
+ /* Redefining scm_timestamping in the same way that <linux/errqueue.h> defines
48
+ * it, so that code compiles on systems that don't have it. */
49
+ struct scm_timestamping {
50
+ struct timespec ts[3];
51
+ };
52
+ /* Also redefine timestamp types */
53
+ /* The timestamp type for when the driver passed skb to NIC, or HW. */
54
+ constexpr int SCM_TSTAMP_SND = 0;
55
+ /* The timestamp type for when data entered the packet scheduler. */
56
+ constexpr int SCM_TSTAMP_SCHED = 1;
57
+ /* The timestamp type for when data acknowledged by peer. */
58
+ constexpr int SCM_TSTAMP_ACK = 2;
59
+ /* Redefine required constants from <linux/net_tstamp.h> */
60
+ constexpr uint32_t SOF_TIMESTAMPING_TX_SOFTWARE = 1u << 1;
61
+ constexpr uint32_t SOF_TIMESTAMPING_SOFTWARE = 1u << 4;
62
+ constexpr uint32_t SOF_TIMESTAMPING_OPT_ID = 1u << 7;
63
+ constexpr uint32_t SOF_TIMESTAMPING_TX_SCHED = 1u << 8;
64
+ constexpr uint32_t SOF_TIMESTAMPING_TX_ACK = 1u << 9;
65
+ constexpr uint32_t SOF_TIMESTAMPING_OPT_TSONLY = 1u << 11;
66
+
67
+ constexpr uint32_t kTimestampingSocketOptions = SOF_TIMESTAMPING_SOFTWARE |
68
+ SOF_TIMESTAMPING_OPT_ID |
69
+ SOF_TIMESTAMPING_OPT_TSONLY;
70
+ constexpr uint32_t kTimestampingRecordingOptions =
71
+ SOF_TIMESTAMPING_TX_SCHED | SOF_TIMESTAMPING_TX_SOFTWARE |
72
+ SOF_TIMESTAMPING_TX_ACK;
73
+ #endif /* GRPC_LINUX_ERRQUEUE */
74
+
75
+ /* Returns true if kernel is capable of supporting errqueue and timestamping.
76
+ * Currently allowing only linux kernels above 4.0.0
77
+ */
78
+ bool kernel_supports_errqueue();
79
+ } // namespace grpc_core
80
+
81
+ #endif /* GRPC_POSIX_SOCKET_TCP */
82
+
83
+ #endif /* GRPC_CORE_LIB_IOMGR_INTERNAL_ERRQUEUE_H */
@@ -60,6 +60,12 @@
60
60
  #define GRPC_HAVE_IP_PKTINFO 1
61
61
  #define GRPC_HAVE_MSG_NOSIGNAL 1
62
62
  #define GRPC_HAVE_UNIX_SOCKET 1
63
+ #ifdef LINUX_VERSION_CODE
64
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
65
+ /* TODO(yashykt): Re-enable once Fathom changes are commited.
66
+ #define GRPC_LINUX_ERRQUEUE 1 */
67
+ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
68
+ #endif /* LINUX_VERSION_CODE */
63
69
  #define GRPC_LINUX_MULTIPOLL_WITH_EPOLL 1
64
70
  #define GRPC_POSIX_FORK 1
65
71
  #define GRPC_POSIX_HOST_NAME_MAX 1
@@ -77,6 +83,11 @@
77
83
  #define GRPC_LINUX_SOCKETUTILS 1
78
84
  #endif
79
85
  #endif
86
+ #ifdef LINUX_VERSION_CODE
87
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
88
+ #define GRPC_HAVE_TCP_USER_TIMEOUT
89
+ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) */
90
+ #endif /* LINUX_VERSION_CODE */
80
91
  #ifndef __GLIBC__
81
92
  #define GRPC_LINUX_EPOLL 1
82
93
  #define GRPC_LINUX_EPOLL_CREATE1 1
@@ -105,7 +116,6 @@
105
116
  #define GRPC_POSIX_SOCKET_EV 1
106
117
  #define GRPC_POSIX_SOCKET_EV_EPOLL1 1
107
118
  #define GRPC_POSIX_SOCKET_EV_EPOLLEX 1
108
- #define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1
109
119
  #define GRPC_POSIX_SOCKET_EV_POLL 1
110
120
  #define GRPC_POSIX_SOCKET_RESOLVE_ADDRESS 1
111
121
  #define GRPC_POSIX_SOCKET_SOCKADDR 1
@@ -173,7 +183,6 @@
173
183
  #define GRPC_POSIX_SOCKET_ARES_EV_DRIVER 1
174
184
  #define GRPC_POSIX_SOCKET_EV 1
175
185
  #define GRPC_POSIX_SOCKET_EV_EPOLLEX 1
176
- #define GRPC_POSIX_SOCKET_EV_EPOLLSIG 1
177
186
  #define GRPC_POSIX_SOCKET_EV_POLL 1
178
187
  #define GRPC_POSIX_SOCKET_EV_EPOLL1 1
179
188
  #define GRPC_POSIX_SOCKET_IOMGR 1
@@ -41,6 +41,7 @@
41
41
  #include <grpc/support/log.h>
42
42
  #include <grpc/support/sync.h>
43
43
 
44
+ #include "src/core/lib/channel/channel_args.h"
44
45
  #include "src/core/lib/gpr/host_port.h"
45
46
  #include "src/core/lib/gpr/string.h"
46
47
  #include "src/core/lib/iomgr/sockaddr.h"
@@ -222,6 +223,95 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency) {
222
223
  return GRPC_ERROR_NONE;
223
224
  }
224
225
 
226
+ /* The default values for TCP_USER_TIMEOUT are currently configured to be in
227
+ * line with the default values of KEEPALIVE_TIMEOUT as proposed in
228
+ * https://github.com/grpc/proposal/blob/master/A18-tcp-user-timeout.md */
229
+ #define DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
230
+ #define DEFAULT_SERVER_TCP_USER_TIMEOUT_MS 20000 /* 20 seconds */
231
+
232
+ static int g_default_client_tcp_user_timeout_ms =
233
+ DEFAULT_CLIENT_TCP_USER_TIMEOUT_MS;
234
+ static int g_default_server_tcp_user_timeout_ms =
235
+ DEFAULT_SERVER_TCP_USER_TIMEOUT_MS;
236
+ static bool g_default_client_tcp_user_timeout_enabled = false;
237
+ static bool g_default_server_tcp_user_timeout_enabled = true;
238
+
239
+ void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client) {
240
+ if (is_client) {
241
+ g_default_client_tcp_user_timeout_enabled = enable;
242
+ if (timeout > 0) {
243
+ g_default_client_tcp_user_timeout_ms = timeout;
244
+ }
245
+ } else {
246
+ g_default_server_tcp_user_timeout_enabled = enable;
247
+ if (timeout > 0) {
248
+ g_default_server_tcp_user_timeout_ms = timeout;
249
+ }
250
+ }
251
+ }
252
+
253
+ /* Set TCP_USER_TIMEOUT */
254
+ grpc_error* grpc_set_socket_tcp_user_timeout(
255
+ int fd, const grpc_channel_args* channel_args, bool is_client) {
256
+ #ifdef GRPC_HAVE_TCP_USER_TIMEOUT
257
+ bool enable;
258
+ int timeout;
259
+ if (is_client) {
260
+ enable = g_default_client_tcp_user_timeout_enabled;
261
+ timeout = g_default_client_tcp_user_timeout_ms;
262
+ } else {
263
+ enable = g_default_server_tcp_user_timeout_enabled;
264
+ timeout = g_default_server_tcp_user_timeout_ms;
265
+ }
266
+ if (channel_args) {
267
+ for (unsigned int i = 0; i < channel_args->num_args; i++) {
268
+ if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_MS)) {
269
+ const int value = grpc_channel_arg_get_integer(
270
+ &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
271
+ /* Continue using default if value is 0 */
272
+ if (value == 0) {
273
+ continue;
274
+ }
275
+ /* Disable if value is INT_MAX */
276
+ enable = value != INT_MAX;
277
+ } else if (0 == strcmp(channel_args->args[i].key,
278
+ GRPC_ARG_KEEPALIVE_TIMEOUT_MS)) {
279
+ const int value = grpc_channel_arg_get_integer(
280
+ &channel_args->args[i], grpc_integer_options{0, 1, INT_MAX});
281
+ /* Continue using default if value is 0 */
282
+ if (value == 0) {
283
+ continue;
284
+ }
285
+ timeout = value;
286
+ }
287
+ }
288
+ }
289
+ if (enable) {
290
+ extern grpc_core::TraceFlag grpc_tcp_trace;
291
+ if (grpc_tcp_trace.enabled()) {
292
+ gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms",
293
+ timeout);
294
+ }
295
+ int newval;
296
+ socklen_t len = sizeof(newval);
297
+ if (0 != setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout,
298
+ sizeof(timeout))) {
299
+ return GRPC_OS_ERROR(errno, "setsockopt(TCP_USER_TIMEOUT)");
300
+ }
301
+ if (0 != getsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &newval, &len)) {
302
+ return GRPC_OS_ERROR(errno, "getsockopt(TCP_USER_TIMEOUT)");
303
+ }
304
+ if (newval != timeout) {
305
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
306
+ "Failed to set TCP_USER_TIMEOUT");
307
+ }
308
+ }
309
+ #else
310
+ gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform");
311
+ #endif /* GRPC_HAVE_TCP_USER_TIMEOUT */
312
+ return GRPC_ERROR_NONE;
313
+ }
314
+
225
315
  /* set a socket using a grpc_socket_mutator */
226
316
  grpc_error* grpc_set_socket_with_mutator(int fd, grpc_socket_mutator* mutator) {
227
317
  GPR_ASSERT(mutator);
@@ -53,6 +53,13 @@ grpc_error* grpc_set_socket_low_latency(int fd, int low_latency);
53
53
  /* set SO_REUSEPORT */
54
54
  grpc_error* grpc_set_socket_reuse_port(int fd, int reuse);
55
55
 
56
+ /* Configure the default values for TCP_USER_TIMEOUT */
57
+ void config_default_tcp_user_timeout(bool enable, int timeout, bool is_client);
58
+
59
+ /* Set TCP_USER_TIMEOUT */
60
+ grpc_error* grpc_set_socket_tcp_user_timeout(
61
+ int fd, const grpc_channel_args* channel_args, bool is_client);
62
+
56
63
  /* Returns true if this system can create AF_INET6 sockets bound to ::1.
57
64
  The value is probed once, and cached for the life of the process.
58
65
 
@@ -76,6 +76,9 @@ static grpc_error* prepare_socket(const grpc_resolved_address* addr, int fd,
76
76
  if (!grpc_is_unix_socket(addr)) {
77
77
  err = grpc_set_socket_low_latency(fd, 1);
78
78
  if (err != GRPC_ERROR_NONE) goto error;
79
+ err = grpc_set_socket_tcp_user_timeout(fd, channel_args,
80
+ true /* is_client */);
81
+ if (err != GRPC_ERROR_NONE) goto error;
79
82
  }
80
83
  err = grpc_set_socket_no_sigpipe_if_possible(fd);
81
84
  if (err != GRPC_ERROR_NONE) goto error;
@@ -279,7 +282,7 @@ grpc_error* grpc_tcp_client_prepare_fd(const grpc_channel_args* channel_args,
279
282
  }
280
283
  addr_str = grpc_sockaddr_to_uri(mapped_addr);
281
284
  gpr_asprintf(&name, "tcp-client:%s", addr_str);
282
- *fdobj = grpc_fd_create(fd, name, false);
285
+ *fdobj = grpc_fd_create(fd, name, true);
283
286
  gpr_free(name);
284
287
  gpr_free(addr_str);
285
288
  return GRPC_ERROR_NONE;
@@ -221,7 +221,7 @@ static void custom_write_callback(grpc_custom_socket* socket,
221
221
  }
222
222
 
223
223
  static void endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* write_slices,
224
- grpc_closure* cb) {
224
+ grpc_closure* cb, void* arg) {
225
225
  custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
226
226
  GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
227
227
 
@@ -27,7 +27,9 @@
27
27
 
28
28
  #include <errno.h>
29
29
  #include <limits.h>
30
+ #include <netinet/in.h>
30
31
  #include <stdbool.h>
32
+ #include <stdio.h>
31
33
  #include <stdlib.h>
32
34
  #include <string.h>
33
35
  #include <sys/socket.h>
@@ -46,6 +48,7 @@
46
48
  #include "src/core/lib/debug/trace.h"
47
49
  #include "src/core/lib/gpr/string.h"
48
50
  #include "src/core/lib/gpr/useful.h"
51
+ #include "src/core/lib/iomgr/buffer_list.h"
49
52
  #include "src/core/lib/iomgr/ev_posix.h"
50
53
  #include "src/core/lib/iomgr/executor.h"
51
54
  #include "src/core/lib/profiling/timers.h"
@@ -97,17 +100,42 @@ struct grpc_tcp {
97
100
 
98
101
  grpc_closure read_done_closure;
99
102
  grpc_closure write_done_closure;
103
+ grpc_closure error_closure;
100
104
 
101
105
  char* peer_string;
102
106
 
103
107
  grpc_resource_user* resource_user;
104
108
  grpc_resource_user_slice_allocator slice_allocator;
109
+
110
+ grpc_core::TracedBuffer* tb_head; /* List of traced buffers */
111
+ gpr_mu tb_mu; /* Lock for access to list of traced buffers */
112
+
113
+ /* grpc_endpoint_write takes an argument which if non-null means that the
114
+ * transport layer wants the TCP layer to collect timestamps for this write.
115
+ * This arg is forwarded to the timestamps callback function when the ACK
116
+ * timestamp is received from the kernel. This arg is a (void *) which allows
117
+ * users of this API to pass in a pointer to any kind of structure. This
118
+ * structure could actually be a tag or any book-keeping object that the user
119
+ * can use to distinguish between different traced writes. The only
120
+ * requirement from the TCP endpoint layer is that this arg should be non-null
121
+ * if the user wants timestamps for the write. */
122
+ void* outgoing_buffer_arg;
123
+ /* A counter which starts at 0. It is initialized the first time the socket
124
+ * options for collecting timestamps are set, and is incremented with each
125
+ * byte sent. */
126
+ int bytes_counter;
127
+ bool socket_ts_enabled; /* True if timestamping options are set on the socket
128
+ */
129
+ gpr_atm
130
+ stop_error_notification; /* Set to 1 if we do not want to be notified on
131
+ errors anymore */
105
132
  };
106
133
 
107
134
  struct backup_poller {
108
135
  gpr_mu* pollset_mu;
109
136
  grpc_closure run_poller;
110
137
  };
138
+
111
139
  } // namespace
112
140
 
113
141
  #define BACKUP_POLLER_POLLSET(b) ((grpc_pollset*)((b) + 1))
@@ -176,6 +204,13 @@ static void drop_uncovered(grpc_tcp* tcp) {
176
204
  GPR_ASSERT(old_count != 1);
177
205
  }
178
206
 
207
+ // gRPC API considers a Write operation to be done the moment it clears ‘flow
208
+ // control’ i.e., not necessarily sent on the wire. This means that the
209
+ // application MIGHT not call `grpc_completion_queue_next/pluck` in a timely
210
+ // manner when its `Write()` API is acked.
211
+ //
212
+ // We need to ensure that the fd is 'covered' (i.e being monitored by some
213
+ // polling thread and progress is made) and hence add it to a backup poller here
179
214
  static void cover_self(grpc_tcp* tcp) {
180
215
  backup_poller* p;
181
216
  gpr_atm old_count =
@@ -302,6 +337,7 @@ static void tcp_free(grpc_tcp* tcp) {
302
337
  grpc_slice_buffer_destroy_internal(&tcp->last_read_buffer);
303
338
  grpc_resource_user_unref(tcp->resource_user);
304
339
  gpr_free(tcp->peer_string);
340
+ gpr_mu_destroy(&tcp->tb_mu);
305
341
  gpr_free(tcp);
306
342
  }
307
343
 
@@ -347,6 +383,10 @@ static void tcp_destroy(grpc_endpoint* ep) {
347
383
  grpc_network_status_unregister_endpoint(ep);
348
384
  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
349
385
  grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
386
+ if (grpc_event_engine_can_track_errors()) {
387
+ gpr_atm_no_barrier_store(&tcp->stop_error_notification, true);
388
+ grpc_fd_set_error(tcp->em_fd);
389
+ }
350
390
  TCP_UNREF(tcp, "destroy");
351
391
  }
352
392
 
@@ -513,6 +553,235 @@ static void tcp_read(grpc_endpoint* ep, grpc_slice_buffer* incoming_buffer,
513
553
  }
514
554
  }
515
555
 
556
+ /* A wrapper around sendmsg. It sends \a msg over \a fd and returns the number
557
+ * of bytes sent. */
558
+ ssize_t tcp_send(int fd, const struct msghdr* msg) {
559
+ GPR_TIMER_SCOPE("sendmsg", 1);
560
+ ssize_t sent_length;
561
+ do {
562
+ /* TODO(klempner): Cork if this is a partial write */
563
+ GRPC_STATS_INC_SYSCALL_WRITE();
564
+ sent_length = sendmsg(fd, msg, SENDMSG_FLAGS);
565
+ } while (sent_length < 0 && errno == EINTR);
566
+ return sent_length;
567
+ }
568
+
569
+ /** This is to be called if outgoing_buffer_arg is not null. On linux platforms,
570
+ * this will call sendmsg with socket options set to collect timestamps inside
571
+ * the kernel. On return, sent_length is set to the return value of the sendmsg
572
+ * call. Returns false if setting the socket options failed. This is not
573
+ * implemented for non-linux platforms currently, and crashes out.
574
+ */
575
+ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
576
+ size_t sending_length,
577
+ ssize_t* sent_length, grpc_error** error);
578
+
579
+ /** The callback function to be invoked when we get an error on the socket. */
580
+ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error);
581
+
582
+ #ifdef GRPC_LINUX_ERRQUEUE
583
+ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
584
+ size_t sending_length,
585
+ ssize_t* sent_length,
586
+ grpc_error** error) {
587
+ if (!tcp->socket_ts_enabled) {
588
+ uint32_t opt = grpc_core::kTimestampingSocketOptions;
589
+ if (setsockopt(tcp->fd, SOL_SOCKET, SO_TIMESTAMPING,
590
+ static_cast<void*>(&opt), sizeof(opt)) != 0) {
591
+ *error = tcp_annotate_error(GRPC_OS_ERROR(errno, "setsockopt"), tcp);
592
+ grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer);
593
+ if (grpc_tcp_trace.enabled()) {
594
+ gpr_log(GPR_ERROR, "Failed to set timestamping options on the socket.");
595
+ }
596
+ return false;
597
+ }
598
+ tcp->bytes_counter = -1;
599
+ tcp->socket_ts_enabled = true;
600
+ }
601
+ /* Set control message to indicate that you want timestamps. */
602
+ union {
603
+ char cmsg_buf[CMSG_SPACE(sizeof(uint32_t))];
604
+ struct cmsghdr align;
605
+ } u;
606
+ cmsghdr* cmsg = reinterpret_cast<cmsghdr*>(u.cmsg_buf);
607
+ cmsg->cmsg_level = SOL_SOCKET;
608
+ cmsg->cmsg_type = SO_TIMESTAMPING;
609
+ cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
610
+ *reinterpret_cast<int*>(CMSG_DATA(cmsg)) =
611
+ grpc_core::kTimestampingRecordingOptions;
612
+ msg->msg_control = u.cmsg_buf;
613
+ msg->msg_controllen = CMSG_SPACE(sizeof(uint32_t));
614
+
615
+ /* If there was an error on sendmsg the logic in tcp_flush will handle it. */
616
+ ssize_t length = tcp_send(tcp->fd, msg);
617
+ *sent_length = length;
618
+ /* Only save timestamps if all the bytes were taken by sendmsg. */
619
+ if (sending_length == static_cast<size_t>(length)) {
620
+ gpr_mu_lock(&tcp->tb_mu);
621
+ grpc_core::TracedBuffer::AddNewEntry(
622
+ &tcp->tb_head, static_cast<int>(tcp->bytes_counter + length),
623
+ tcp->outgoing_buffer_arg);
624
+ gpr_mu_unlock(&tcp->tb_mu);
625
+ tcp->outgoing_buffer_arg = nullptr;
626
+ }
627
+ return true;
628
+ }
629
+
630
+ /** Reads \a cmsg to derive timestamps from the control messages. If a valid
631
+ * timestamp is found, the traced buffer list is updated with this timestamp.
632
+ * The caller of this function should be looping on the control messages found
633
+ * in \a msg. \a cmsg should point to the control message that the caller wants
634
+ * processed.
635
+ * On return, a pointer to a control message is returned. On the next iteration,
636
+ * CMSG_NXTHDR(msg, ret_val) should be passed as \a cmsg. */
637
+ struct cmsghdr* process_timestamp(grpc_tcp* tcp, msghdr* msg,
638
+ struct cmsghdr* cmsg) {
639
+ auto next_cmsg = CMSG_NXTHDR(msg, cmsg);
640
+ if (next_cmsg == nullptr) {
641
+ if (grpc_tcp_trace.enabled()) {
642
+ gpr_log(GPR_ERROR, "Received timestamp without extended error");
643
+ }
644
+ return cmsg;
645
+ }
646
+
647
+ if (!(next_cmsg->cmsg_level == SOL_IP || next_cmsg->cmsg_level == SOL_IPV6) ||
648
+ !(next_cmsg->cmsg_type == IP_RECVERR ||
649
+ next_cmsg->cmsg_type == IPV6_RECVERR)) {
650
+ if (grpc_tcp_trace.enabled()) {
651
+ gpr_log(GPR_ERROR, "Unexpected control message");
652
+ }
653
+ return cmsg;
654
+ }
655
+
656
+ auto tss =
657
+ reinterpret_cast<struct grpc_core::scm_timestamping*>(CMSG_DATA(cmsg));
658
+ auto serr = reinterpret_cast<struct sock_extended_err*>(CMSG_DATA(next_cmsg));
659
+ if (serr->ee_errno != ENOMSG ||
660
+ serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
661
+ gpr_log(GPR_ERROR, "Unexpected control message");
662
+ return cmsg;
663
+ }
664
+ /* The error handling can potentially be done on another thread so we need
665
+ * to protect the traced buffer list. A lock free list might be better. Using
666
+ * a simple mutex for now. */
667
+ gpr_mu_lock(&tcp->tb_mu);
668
+ grpc_core::TracedBuffer::ProcessTimestamp(&tcp->tb_head, serr, tss);
669
+ gpr_mu_unlock(&tcp->tb_mu);
670
+ return next_cmsg;
671
+ }
672
+
673
+ /** For linux platforms, reads the socket's error queue and processes error
674
+ * messages from the queue. Returns true if all the errors processed were
675
+ * timestamps. Returns false if any of the errors were not timestamps. For
676
+ * non-linux platforms, error processing is not used/enabled currently.
677
+ */
678
+ static bool process_errors(grpc_tcp* tcp) {
679
+ while (true) {
680
+ struct iovec iov;
681
+ iov.iov_base = nullptr;
682
+ iov.iov_len = 0;
683
+ struct msghdr msg;
684
+ msg.msg_name = nullptr;
685
+ msg.msg_namelen = 0;
686
+ msg.msg_iov = &iov;
687
+ msg.msg_iovlen = 0;
688
+ msg.msg_flags = 0;
689
+
690
+ union {
691
+ char rbuf[1024 /*CMSG_SPACE(sizeof(scm_timestamping)) +
692
+ CMSG_SPACE(sizeof(sock_extended_err) + sizeof(sockaddr_in))*/];
693
+ struct cmsghdr align;
694
+ } aligned_buf;
695
+ memset(&aligned_buf, 0, sizeof(aligned_buf));
696
+
697
+ msg.msg_control = aligned_buf.rbuf;
698
+ msg.msg_controllen = sizeof(aligned_buf.rbuf);
699
+
700
+ int r, saved_errno;
701
+ do {
702
+ r = recvmsg(tcp->fd, &msg, MSG_ERRQUEUE);
703
+ saved_errno = errno;
704
+ } while (r < 0 && saved_errno == EINTR);
705
+
706
+ if (r == -1 && saved_errno == EAGAIN) {
707
+ return true; /* No more errors to process */
708
+ }
709
+ if (r == -1) {
710
+ return false;
711
+ }
712
+ if (grpc_tcp_trace.enabled()) {
713
+ if ((msg.msg_flags & MSG_CTRUNC) == 1) {
714
+ gpr_log(GPR_INFO, "Error message was truncated.");
715
+ }
716
+ }
717
+
718
+ if (msg.msg_controllen == 0) {
719
+ /* There was no control message found. It was probably spurious. */
720
+ return true;
721
+ }
722
+ for (auto cmsg = CMSG_FIRSTHDR(&msg); cmsg && cmsg->cmsg_len;
723
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
724
+ if (cmsg->cmsg_level != SOL_SOCKET ||
725
+ cmsg->cmsg_type != SCM_TIMESTAMPING) {
726
+ /* Got a control message that is not a timestamp. Don't know how to
727
+ * handle this. */
728
+ if (grpc_tcp_trace.enabled()) {
729
+ gpr_log(GPR_INFO,
730
+ "unknown control message cmsg_level:%d cmsg_type:%d",
731
+ cmsg->cmsg_level, cmsg->cmsg_type);
732
+ }
733
+ return false;
734
+ }
735
+ process_timestamp(tcp, &msg, cmsg);
736
+ }
737
+ }
738
+ }
739
+
740
+ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) {
741
+ grpc_tcp* tcp = static_cast<grpc_tcp*>(arg);
742
+ if (grpc_tcp_trace.enabled()) {
743
+ gpr_log(GPR_INFO, "TCP:%p got_error: %s", tcp, grpc_error_string(error));
744
+ }
745
+
746
+ if (error != GRPC_ERROR_NONE ||
747
+ static_cast<bool>(gpr_atm_acq_load(&tcp->stop_error_notification))) {
748
+ /* We aren't going to register to hear on error anymore, so it is safe to
749
+ * unref. */
750
+ grpc_core::TracedBuffer::Shutdown(&tcp->tb_head, GRPC_ERROR_REF(error));
751
+ TCP_UNREF(tcp, "error-tracking");
752
+ return;
753
+ }
754
+
755
+ /* We are still interested in collecting timestamps, so let's try reading
756
+ * them. */
757
+ if (!process_errors(tcp)) {
758
+ /* This was not a timestamps error. This was an actual error. Set the
759
+ * read and write closures to be ready.
760
+ */
761
+ grpc_fd_set_readable(tcp->em_fd);
762
+ grpc_fd_set_writable(tcp->em_fd);
763
+ }
764
+ GRPC_CLOSURE_INIT(&tcp->error_closure, tcp_handle_error, tcp,
765
+ grpc_schedule_on_exec_ctx);
766
+ grpc_fd_notify_on_error(tcp->em_fd, &tcp->error_closure);
767
+ }
768
+
769
+ #else /* GRPC_LINUX_ERRQUEUE */
770
+ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg,
771
+ size_t sending_length,
772
+ ssize_t* sent_length,
773
+ grpc_error** error) {
774
+ gpr_log(GPR_ERROR, "Write with timestamps not supported for this platform");
775
+ GPR_ASSERT(0);
776
+ return false;
777
+ }
778
+
779
+ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) {
780
+ gpr_log(GPR_ERROR, "Error handling is not supported for this platform");
781
+ GPR_ASSERT(0);
782
+ }
783
+ #endif /* GRPC_LINUX_ERRQUEUE */
784
+
516
785
  /* returns true if done, false if pending; if returning true, *error is set */
517
786
  #if defined(IOV_MAX) && IOV_MAX < 1000
518
787
  #define MAX_WRITE_IOVEC IOV_MAX
@@ -557,19 +826,20 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
557
826
  msg.msg_namelen = 0;
558
827
  msg.msg_iov = iov;
559
828
  msg.msg_iovlen = iov_size;
560
- msg.msg_control = nullptr;
561
- msg.msg_controllen = 0;
562
829
  msg.msg_flags = 0;
830
+ if (tcp->outgoing_buffer_arg != nullptr) {
831
+ if (!tcp_write_with_timestamps(tcp, &msg, sending_length, &sent_length,
832
+ error))
833
+ return true; /* something went wrong with timestamps */
834
+ } else {
835
+ msg.msg_control = nullptr;
836
+ msg.msg_controllen = 0;
563
837
 
564
- GRPC_STATS_INC_TCP_WRITE_SIZE(sending_length);
565
- GRPC_STATS_INC_TCP_WRITE_IOV_SIZE(iov_size);
838
+ GRPC_STATS_INC_TCP_WRITE_SIZE(sending_length);
839
+ GRPC_STATS_INC_TCP_WRITE_IOV_SIZE(iov_size);
566
840
 
567
- GPR_TIMER_SCOPE("sendmsg", 1);
568
- do {
569
- /* TODO(klempner): Cork if this is a partial write */
570
- GRPC_STATS_INC_SYSCALL_WRITE();
571
- sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS);
572
- } while (sent_length < 0 && errno == EINTR);
841
+ sent_length = tcp_send(tcp->fd, &msg);
842
+ }
573
843
 
574
844
  if (sent_length < 0) {
575
845
  if (errno == EAGAIN) {
@@ -593,6 +863,7 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
593
863
  }
594
864
 
595
865
  GPR_ASSERT(tcp->outgoing_byte_idx == 0);
866
+ tcp->bytes_counter += sent_length;
596
867
  trailing = sending_length - static_cast<size_t>(sent_length);
597
868
  while (trailing > 0) {
598
869
  size_t slice_length;
@@ -607,7 +878,6 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) {
607
878
  trailing -= slice_length;
608
879
  }
609
880
  }
610
-
611
881
  if (outgoing_slice_idx == tcp->outgoing_buffer->count) {
612
882
  *error = GRPC_ERROR_NONE;
613
883
  grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer);
@@ -640,14 +910,13 @@ static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error) {
640
910
  const char* str = grpc_error_string(error);
641
911
  gpr_log(GPR_INFO, "write: %s", str);
642
912
  }
643
-
644
913
  GRPC_CLOSURE_SCHED(cb, error);
645
914
  TCP_UNREF(tcp, "write");
646
915
  }
647
916
  }
648
917
 
649
918
  static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf,
650
- grpc_closure* cb) {
919
+ grpc_closure* cb, void* arg) {
651
920
  GPR_TIMER_SCOPE("tcp_write", 0);
652
921
  grpc_tcp* tcp = reinterpret_cast<grpc_tcp*>(ep);
653
922
  grpc_error* error = GRPC_ERROR_NONE;
@@ -675,6 +944,10 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf,
675
944
  }
676
945
  tcp->outgoing_buffer = buf;
677
946
  tcp->outgoing_byte_idx = 0;
947
+ tcp->outgoing_buffer_arg = arg;
948
+ if (arg) {
949
+ GPR_ASSERT(grpc_event_engine_can_track_errors());
950
+ }
678
951
 
679
952
  if (!tcp_flush(tcp, &error)) {
680
953
  TCP_REF(tcp, "write");
@@ -792,6 +1065,8 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd,
792
1065
  tcp->bytes_read_this_round = 0;
793
1066
  /* Will be set to false by the very first endpoint read function */
794
1067
  tcp->is_first_read = true;
1068
+ tcp->bytes_counter = -1;
1069
+ tcp->socket_ts_enabled = false;
795
1070
  /* paired with unref in grpc_tcp_destroy */
796
1071
  gpr_ref_init(&tcp->refcount, 1);
797
1072
  gpr_atm_no_barrier_store(&tcp->shutdown_count, 0);
@@ -803,6 +1078,19 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd,
803
1078
  /* Tell network status tracker about new endpoint */
804
1079
  grpc_network_status_register_endpoint(&tcp->base);
805
1080
  grpc_resource_quota_unref_internal(resource_quota);
1081
+ gpr_mu_init(&tcp->tb_mu);
1082
+ tcp->tb_head = nullptr;
1083
+ /* Start being notified on errors if event engine can track errors. */
1084
+ if (grpc_event_engine_can_track_errors()) {
1085
+ /* Grab a ref to tcp so that we can safely access the tcp struct when
1086
+ * processing errors. We unref when we no longer want to track errors
1087
+ * separately. */
1088
+ TCP_REF(tcp, "error-tracking");
1089
+ gpr_atm_rel_store(&tcp->stop_error_notification, 0);
1090
+ GRPC_CLOSURE_INIT(&tcp->error_closure, tcp_handle_error, tcp,
1091
+ grpc_schedule_on_exec_ctx);
1092
+ grpc_fd_notify_on_error(tcp->em_fd, &tcp->error_closure);
1093
+ }
806
1094
 
807
1095
  return &tcp->base;
808
1096
  }
@@ -821,6 +1109,11 @@ void grpc_tcp_destroy_and_release_fd(grpc_endpoint* ep, int* fd,
821
1109
  tcp->release_fd = fd;
822
1110
  tcp->release_fd_cb = done;
823
1111
  grpc_slice_buffer_reset_and_unref_internal(&tcp->last_read_buffer);
1112
+ if (grpc_event_engine_can_track_errors()) {
1113
+ /* Stop errors notification. */
1114
+ gpr_atm_no_barrier_store(&tcp->stop_error_notification, true);
1115
+ grpc_fd_set_error(tcp->em_fd);
1116
+ }
824
1117
  TCP_UNREF(tcp, "destroy");
825
1118
  }
826
1119