aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib')
-rw-r--r--src/core/lib/gpr/arena.cc45
-rw-r--r--src/core/lib/gpr/cpu_linux.cc4
-rw-r--r--src/core/lib/gpr/cpu_posix.cc2
-rw-r--r--src/core/lib/gpr/log_linux.cc1
-rw-r--r--src/core/lib/gpr/thd.cc51
-rw-r--r--src/core/lib/gpr/thd.h72
-rw-r--r--src/core/lib/gpr/thd_posix.cc154
-rw-r--r--src/core/lib/gpr/thd_windows.cc107
-rw-r--r--src/core/lib/gprpp/manual_constructor.h2
-rw-r--r--src/core/lib/gprpp/memory.h6
-rw-r--r--src/core/lib/gprpp/orphanable.h1
-rw-r--r--src/core/lib/gprpp/ref_counted.h2
-rw-r--r--src/core/lib/gprpp/ref_counted_ptr.h1
-rw-r--r--src/core/lib/gprpp/thd.h135
-rw-r--r--src/core/lib/gprpp/thd_posix.cc209
-rw-r--r--src/core/lib/gprpp/thd_windows.cc162
-rw-r--r--src/core/lib/iomgr/endpoint.cc2
-rw-r--r--src/core/lib/iomgr/endpoint_pair_windows.cc9
-rw-r--r--src/core/lib/iomgr/ev_epollex_linux.cc20
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.cc70
-rw-r--r--src/core/lib/iomgr/ev_posix.cc52
-rw-r--r--src/core/lib/iomgr/exec_ctx.cc2
-rw-r--r--src/core/lib/iomgr/exec_ctx.h28
-rw-r--r--src/core/lib/iomgr/executor.cc22
-rw-r--r--src/core/lib/iomgr/fork_posix.cc4
-rw-r--r--src/core/lib/iomgr/iocp_windows.cc2
-rw-r--r--src/core/lib/iomgr/iomgr.cc3
-rw-r--r--src/core/lib/iomgr/iomgr_custom.cc63
-rw-r--r--src/core/lib/iomgr/iomgr_custom.h (renamed from src/core/lib/iomgr/iomgr_uv.h)24
-rw-r--r--src/core/lib/iomgr/iomgr_internal.cc43
-rw-r--r--src/core/lib/iomgr/iomgr_internal.h12
-rw-r--r--src/core/lib/iomgr/iomgr_posix.cc31
-rw-r--r--src/core/lib/iomgr/iomgr_uv.cc35
-rw-r--r--src/core/lib/iomgr/iomgr_windows.cc30
-rw-r--r--src/core/lib/iomgr/pollset.cc56
-rw-r--r--src/core/lib/iomgr/pollset.h18
-rw-r--r--src/core/lib/iomgr/pollset_custom.cc106
-rw-r--r--src/core/lib/iomgr/pollset_custom.h35
-rw-r--r--src/core/lib/iomgr/pollset_set.cc (renamed from src/core/lib/iomgr/pollset_set_uv.cc)36
-rw-r--r--src/core/lib/iomgr/pollset_set.h11
-rw-r--r--src/core/lib/iomgr/pollset_set_custom.cc48
-rw-r--r--src/core/lib/iomgr/pollset_set_custom.h26
-rw-r--r--src/core/lib/iomgr/pollset_set_windows.cc25
-rw-r--r--src/core/lib/iomgr/pollset_uv.cc145
-rw-r--r--src/core/lib/iomgr/pollset_uv.h9
-rw-r--r--src/core/lib/iomgr/pollset_windows.cc30
-rw-r--r--src/core/lib/iomgr/port.h27
-rw-r--r--src/core/lib/iomgr/resolve_address.cc50
-rw-r--r--src/core/lib/iomgr/resolve_address.h29
-rw-r--r--src/core/lib/iomgr/resolve_address_custom.cc187
-rw-r--r--src/core/lib/iomgr/resolve_address_custom.h43
-rw-r--r--src/core/lib/iomgr/resolve_address_posix.cc30
-rw-r--r--src/core/lib/iomgr/resolve_address_uv.cc286
-rw-r--r--src/core/lib/iomgr/resolve_address_windows.cc30
-rw-r--r--src/core/lib/iomgr/resource_quota.h4
-rw-r--r--src/core/lib/iomgr/sockaddr.h14
-rw-r--r--src/core/lib/iomgr/sockaddr_custom.h54
-rw-r--r--src/core/lib/iomgr/sockaddr_posix.h24
-rw-r--r--src/core/lib/iomgr/sockaddr_utils.cc156
-rw-r--r--src/core/lib/iomgr/sockaddr_utils.h2
-rw-r--r--src/core/lib/iomgr/sockaddr_windows.h19
-rw-r--r--src/core/lib/iomgr/socket_utils.h9
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.cc18
-rw-r--r--src/core/lib/iomgr/socket_utils_linux.cc3
-rw-r--r--src/core/lib/iomgr/socket_utils_posix.cc2
-rw-r--r--src/core/lib/iomgr/socket_utils_uv.cc17
-rw-r--r--src/core/lib/iomgr/socket_utils_windows.cc8
-rw-r--r--src/core/lib/iomgr/tcp_client.cc36
-rw-r--r--src/core/lib/iomgr/tcp_client.h11
-rw-r--r--src/core/lib/iomgr/tcp_client_custom.cc151
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.cc30
-rw-r--r--src/core/lib/iomgr/tcp_client_uv.cc177
-rw-r--r--src/core/lib/iomgr/tcp_client_windows.cc31
-rw-r--r--src/core/lib/iomgr/tcp_custom.cc365
-rw-r--r--src/core/lib/iomgr/tcp_custom.h83
-rw-r--r--src/core/lib/iomgr/tcp_posix.cc2
-rw-r--r--src/core/lib/iomgr/tcp_server.cc73
-rw-r--r--src/core/lib/iomgr/tcp_server.h22
-rw-r--r--src/core/lib/iomgr/tcp_server_custom.cc479
-rw-r--r--src/core/lib/iomgr/tcp_server_posix.cc49
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_common.cc5
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc8
-rw-r--r--src/core/lib/iomgr/tcp_server_uv.cc473
-rw-r--r--src/core/lib/iomgr/tcp_server_windows.cc62
-rw-r--r--src/core/lib/iomgr/tcp_uv.cc627
-rw-r--r--src/core/lib/iomgr/tcp_uv.h53
-rw-r--r--src/core/lib/iomgr/tcp_windows.cc2
-rw-r--r--src/core/lib/iomgr/timer.cc45
-rw-r--r--src/core/lib/iomgr/timer.h48
-rw-r--r--src/core/lib/iomgr/timer_custom.cc93
-rw-r--r--src/core/lib/iomgr/timer_custom.h43
-rw-r--r--src/core/lib/iomgr/timer_generic.cc20
-rw-r--r--src/core/lib/iomgr/timer_heap.cc4
-rw-r--r--src/core/lib/iomgr/timer_manager.cc29
-rw-r--r--src/core/lib/iomgr/timer_uv.cc62
-rw-r--r--src/core/lib/iomgr/udp_server.cc489
-rw-r--r--src/core/lib/iomgr/udp_server.h62
-rw-r--r--src/core/lib/iomgr/unix_sockets_posix.cc12
-rw-r--r--src/core/lib/iomgr/wakeup_fd_cv.cc2
-rw-r--r--src/core/lib/profiling/basic_timers.cc13
-rw-r--r--src/core/lib/security/credentials/alts/alts_credentials.cc119
-rw-r--r--src/core/lib/security/credentials/alts/alts_credentials.h102
-rw-r--r--src/core/lib/security/credentials/alts/check_gcp_environment.cc72
-rw-r--r--src/core/lib/security/credentials/alts/check_gcp_environment.h57
-rw-r--r--src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc67
-rw-r--r--src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc33
-rw-r--r--src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc114
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc126
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc46
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h112
-rw-r--r--src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc58
-rw-r--r--src/core/lib/security/credentials/fake/fake_credentials.cc3
-rw-r--r--src/core/lib/security/credentials/fake/fake_credentials.h3
-rw-r--r--src/core/lib/security/security_connector/alts_security_connector.cc287
-rw-r--r--src/core/lib/security/security_connector/alts_security_connector.h69
-rw-r--r--src/core/lib/security/security_connector/security_connector.cc13
-rw-r--r--src/core/lib/security/transport/client_auth_filter.cc40
-rw-r--r--src/core/lib/security/transport/lb_targets_info.cc61
-rw-r--r--src/core/lib/security/transport/target_authority_table.cc75
-rw-r--r--src/core/lib/security/transport/target_authority_table.h (renamed from src/core/lib/security/transport/lb_targets_info.h)22
-rw-r--r--src/core/lib/slice/slice_hash_table.cc147
-rw-r--r--src/core/lib/slice/slice_hash_table.h221
-rw-r--r--src/core/lib/slice/slice_weak_hash_table.h105
-rw-r--r--src/core/lib/surface/call.cc124
-rw-r--r--src/core/lib/surface/init.cc4
-rw-r--r--src/core/lib/surface/lame_client.cc10
-rw-r--r--src/core/lib/transport/byte_stream.cc208
-rw-r--r--src/core/lib/transport/byte_stream.h185
-rw-r--r--src/core/lib/transport/metadata_batch.cc24
-rw-r--r--src/core/lib/transport/metadata_batch.h9
-rw-r--r--src/core/lib/transport/service_config.cc194
-rw-r--r--src/core/lib/transport/service_config.h256
-rw-r--r--src/core/lib/transport/static_metadata.cc602
-rw-r--r--src/core/lib/transport/static_metadata.h176
-rw-r--r--src/core/lib/transport/status_metadata.cc54
-rw-r--r--src/core/lib/transport/status_metadata.h (renamed from src/core/lib/iomgr/timer_uv.h)20
-rw-r--r--src/core/lib/transport/transport.cc2
-rw-r--r--src/core/lib/transport/transport.h38
-rw-r--r--src/core/lib/transport/transport_op_string.cc13
139 files changed, 6748 insertions, 3747 deletions
diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc
index 444bb3d719..b02c5b9fb6 100644
--- a/src/core/lib/gpr/arena.cc
+++ b/src/core/lib/gpr/arena.cc
@@ -26,6 +26,49 @@
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
+// Uncomment this to use a simple arena that simply allocates the
+// requested amount of memory for each call to gpr_arena_alloc(). This
+// effectively eliminates the efficiency gain of using an arena, but it
+// may be useful for debugging purposes.
+//#define SIMPLE_ARENA_FOR_DEBUGGING
+
+#ifdef SIMPLE_ARENA_FOR_DEBUGGING
+
+#include <grpc/support/sync.h>
+
+struct gpr_arena {
+ gpr_mu mu;
+ void** ptrs;
+ size_t num_ptrs;
+};
+
+gpr_arena* gpr_arena_create(size_t ignored_initial_size) {
+ gpr_arena* arena = (gpr_arena*)gpr_zalloc(sizeof(*arena));
+ gpr_mu_init(&arena->mu);
+ return arena;
+}
+
+size_t gpr_arena_destroy(gpr_arena* arena) {
+ gpr_mu_destroy(&arena->mu);
+ for (size_t i = 0; i < arena->num_ptrs; ++i) {
+ gpr_free(arena->ptrs[i]);
+ }
+ gpr_free(arena->ptrs);
+ gpr_free(arena);
+ return 1; // Value doesn't matter, since it won't be used.
+}
+
+void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
+ gpr_mu_lock(&arena->mu);
+ arena->ptrs =
+ (void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1));
+ void* retval = arena->ptrs[arena->num_ptrs++] = gpr_zalloc(size);
+ gpr_mu_unlock(&arena->mu);
+ return retval;
+}
+
+#else // SIMPLE_ARENA_FOR_DEBUGGING
+
// TODO(roth): We currently assume that all callers need alignment of 16
// bytes, which may be wrong in some cases. As part of converting the
// arena API to C++, we should consider replacing gpr_arena_alloc() with a
@@ -105,3 +148,5 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone));
return ptr + start - z->size_begin;
}
+
+#endif // SIMPLE_ARENA_FOR_DEBUGGING
diff --git a/src/core/lib/gpr/cpu_linux.cc b/src/core/lib/gpr/cpu_linux.cc
index fda28916f8..9fc2f0b141 100644
--- a/src/core/lib/gpr/cpu_linux.cc
+++ b/src/core/lib/gpr/cpu_linux.cc
@@ -71,6 +71,10 @@ unsigned gpr_cpu_current_cpu(void) {
gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
return 0;
}
+ if (static_cast<unsigned>(cpu) >= gpr_cpu_num_cores()) {
+ gpr_log(GPR_ERROR, "Cannot handle hot-plugged CPUs");
+ return 0;
+ }
return static_cast<unsigned>(cpu);
#endif
}
diff --git a/src/core/lib/gpr/cpu_posix.cc b/src/core/lib/gpr/cpu_posix.cc
index 7a77f7ab64..915fd4976c 100644
--- a/src/core/lib/gpr/cpu_posix.cc
+++ b/src/core/lib/gpr/cpu_posix.cc
@@ -37,7 +37,7 @@ static long ncpus = 0;
static pthread_key_t thread_id_key;
static void init_ncpus() {
- ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+ ncpus = sysconf(_SC_NPROCESSORS_CONF);
if (ncpus < 1 || ncpus > INT32_MAX) {
gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1");
ncpus = 1;
diff --git a/src/core/lib/gpr/log_linux.cc b/src/core/lib/gpr/log_linux.cc
index d743eedf38..e4417d9d5d 100644
--- a/src/core/lib/gpr/log_linux.cc
+++ b/src/core/lib/gpr/log_linux.cc
@@ -32,6 +32,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
+#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
diff --git a/src/core/lib/gpr/thd.cc b/src/core/lib/gpr/thd.cc
deleted file mode 100644
index b5341c41b4..0000000000
--- a/src/core/lib/gpr/thd.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* Platform-independent features for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/gpr/thd.h"
-
-#include <string.h>
-
-enum { GPR_THD_JOINABLE = 1 };
-
-gpr_thd_options gpr_thd_options_default(void) {
- gpr_thd_options options;
- memset(&options, 0, sizeof(options));
- return options;
-}
-
-void gpr_thd_options_set_detached(gpr_thd_options* options) {
- options->flags &= ~GPR_THD_JOINABLE;
-}
-
-void gpr_thd_options_set_joinable(gpr_thd_options* options) {
- options->flags |= GPR_THD_JOINABLE;
-}
-
-int gpr_thd_options_is_detached(const gpr_thd_options* options) {
- if (!options) return 1;
- return (options->flags & GPR_THD_JOINABLE) == 0;
-}
-
-int gpr_thd_options_is_joinable(const gpr_thd_options* options) {
- if (!options) return 0;
- return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
-}
diff --git a/src/core/lib/gpr/thd.h b/src/core/lib/gpr/thd.h
deleted file mode 100644
index 920b336708..0000000000
--- a/src/core/lib/gpr/thd.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_LIB_GPR_THD_H
-#define GRPC_CORE_LIB_GPR_THD_H
-/** Internal thread interface for GPR.
-
- Types
- gpr_thd_options options used when creating a thread
- */
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/support/thd_id.h>
-#include <grpc/support/time.h>
-
-/** Thread creation options. */
-typedef struct {
- int flags; /** Opaque field. Get and set with accessors below. */
-} gpr_thd_options;
-
-/** Create a new thread running (*thd_body)(arg) and place its thread identifier
- in *t, and return true. If there are insufficient resources, return false.
- thd_name is the name of the thread for identification purposes on platforms
- that support thread naming.
- If options==NULL, default options are used.
- The thread is immediately runnable, and exits when (*thd_body)() returns. */
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
- void (*thd_body)(void* arg), void* arg,
- const gpr_thd_options* options);
-
-/** Return a gpr_thd_options struct with all fields set to defaults. */
-gpr_thd_options gpr_thd_options_default(void);
-
-/** Set the thread to become detached on startup - this is the default. */
-void gpr_thd_options_set_detached(gpr_thd_options* options);
-
-/** Set the thread to become joinable - mutually exclusive with detached. */
-void gpr_thd_options_set_joinable(gpr_thd_options* options);
-
-/** Returns non-zero if the option detached is set. */
-int gpr_thd_options_is_detached(const gpr_thd_options* options);
-
-/** Returns non-zero if the option joinable is set. */
-int gpr_thd_options_is_joinable(const gpr_thd_options* options);
-
-/** Blocks until the specified thread properly terminates.
- Calling this on a detached thread has unpredictable results. */
-void gpr_thd_join(gpr_thd_id t);
-
-/* Internal interfaces between modules within the gpr support library. */
-void gpr_thd_init();
-
-/* Wait for all outstanding threads to finish, up to deadline */
-int gpr_await_threads(gpr_timespec deadline);
-
-#endif /* GRPC_CORE_LIB_GPR_THD_H */
diff --git a/src/core/lib/gpr/thd_posix.cc b/src/core/lib/gpr/thd_posix.cc
deleted file mode 100644
index fcd174bfba..0000000000
--- a/src/core/lib/gpr/thd_posix.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* Posix implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_POSIX_SYNC
-
-#include "src/core/lib/gpr/thd.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd_id.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "src/core/lib/gpr/fork.h"
-#include "src/core/lib/gpr/useful.h"
-
-static gpr_mu g_mu;
-static gpr_cv g_cv;
-static int g_thread_count;
-static int g_awaiting_threads;
-
-struct thd_arg {
- void (*body)(void* arg); /* body of a thread */
- void* arg; /* argument to a thread */
- const char* name; /* name of thread. Can be nullptr. */
-};
-
-static void inc_thd_count();
-static void dec_thd_count();
-
-/* Body of every thread started via gpr_thd_new. */
-static void* thread_body(void* v) {
- struct thd_arg a = *static_cast<struct thd_arg*>(v);
- free(v);
- if (a.name != nullptr) {
-#if GPR_APPLE_PTHREAD_NAME
- /* Apple supports 64 characters, and will truncate if it's longer. */
- pthread_setname_np(a.name);
-#elif GPR_LINUX_PTHREAD_NAME
- /* Linux supports 16 characters max, and will error if it's longer. */
- char buf[16];
- size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
- strncpy(buf, a.name, buf_len);
- buf[buf_len] = '\0';
- pthread_setname_np(pthread_self(), buf);
-#endif // GPR_APPLE_PTHREAD_NAME
- }
- (*a.body)(a.arg);
- dec_thd_count();
- return nullptr;
-}
-
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
- void (*thd_body)(void* arg), void* arg,
- const gpr_thd_options* options) {
- int thread_started;
- pthread_attr_t attr;
- pthread_t p;
- /* don't use gpr_malloc as we may cause an infinite recursion with
- * the profiling code */
- struct thd_arg* a = static_cast<struct thd_arg*>(malloc(sizeof(*a)));
- GPR_ASSERT(a != nullptr);
- a->body = thd_body;
- a->arg = arg;
- a->name = thd_name;
- inc_thd_count();
-
- GPR_ASSERT(pthread_attr_init(&attr) == 0);
- if (gpr_thd_options_is_detached(options)) {
- GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
- 0);
- } else {
- GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
- 0);
- }
- thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
- GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
- if (!thread_started) {
- /* don't use gpr_free, as this was allocated using malloc (see above) */
- free(a);
- dec_thd_count();
- }
- *t = (gpr_thd_id)p;
- return thread_started;
-}
-
-gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
-
-void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, nullptr); }
-
-/*****************************************
- * Only used when fork support is enabled
- */
-
-static void inc_thd_count() {
- if (grpc_fork_support_enabled()) {
- gpr_mu_lock(&g_mu);
- g_thread_count++;
- gpr_mu_unlock(&g_mu);
- }
-}
-
-static void dec_thd_count() {
- if (grpc_fork_support_enabled()) {
- gpr_mu_lock(&g_mu);
- g_thread_count--;
- if (g_awaiting_threads && g_thread_count == 0) {
- gpr_cv_signal(&g_cv);
- }
- gpr_mu_unlock(&g_mu);
- }
-}
-
-void gpr_thd_init() {
- gpr_mu_init(&g_mu);
- gpr_cv_init(&g_cv);
- g_thread_count = 0;
- g_awaiting_threads = 0;
-}
-
-int gpr_await_threads(gpr_timespec deadline) {
- gpr_mu_lock(&g_mu);
- g_awaiting_threads = 1;
- int res = 0;
- if (g_thread_count > 0) {
- res = gpr_cv_wait(&g_cv, &g_mu, deadline);
- }
- g_awaiting_threads = 0;
- gpr_mu_unlock(&g_mu);
- return res == 0;
-}
-
-#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/lib/gpr/thd_windows.cc b/src/core/lib/gpr/thd_windows.cc
deleted file mode 100644
index b467bd2662..0000000000
--- a/src/core/lib/gpr/thd_windows.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-/* Windows implementation for gpr threads. */
-
-#include <grpc/support/port_platform.h>
-
-#ifdef GPR_WINDOWS
-
-#include "src/core/lib/gpr/thd.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/thd_id.h>
-#include <string.h>
-
-#if defined(_MSC_VER)
-#define thread_local __declspec(thread)
-#elif defined(__GNUC__)
-#define thread_local __thread
-#else
-#error "Unknown compiler - please file a bug report"
-#endif
-
-struct thd_info {
- void (*body)(void* arg); /* body of a thread */
- void* arg; /* argument to a thread */
- HANDLE join_event; /* if joinable, the join event */
- int joinable; /* true if not detached */
-};
-
-static thread_local struct thd_info* g_thd_info;
-
-/* Destroys a thread info */
-static void destroy_thread(struct thd_info* t) {
- if (t->joinable) CloseHandle(t->join_event);
- gpr_free(t);
-}
-
-void gpr_thd_init(void) {}
-
-/* Body of every thread started via gpr_thd_new. */
-static DWORD WINAPI thread_body(void* v) {
- g_thd_info = (struct thd_info*)v;
- g_thd_info->body(g_thd_info->arg);
- if (g_thd_info->joinable) {
- BOOL ret = SetEvent(g_thd_info->join_event);
- GPR_ASSERT(ret);
- } else {
- destroy_thread(g_thd_info);
- }
- return 0;
-}
-
-int gpr_thd_new(gpr_thd_id* t, const char* thd_name,
- void (*thd_body)(void* arg), void* arg,
- const gpr_thd_options* options) {
- HANDLE handle;
- struct thd_info* info = (struct thd_info*)gpr_malloc(sizeof(*info));
- info->body = thd_body;
- info->arg = arg;
- *t = 0;
- if (gpr_thd_options_is_joinable(options)) {
- info->joinable = 1;
- info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (info->join_event == NULL) {
- gpr_free(info);
- return 0;
- }
- } else {
- info->joinable = 0;
- }
- handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
- if (handle == NULL) {
- destroy_thread(info);
- } else {
- *t = (gpr_thd_id)info;
- CloseHandle(handle);
- }
- return handle != NULL;
-}
-
-gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
-
-void gpr_thd_join(gpr_thd_id t) {
- struct thd_info* info = (struct thd_info*)t;
- DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
- GPR_ASSERT(ret == WAIT_OBJECT_0);
- destroy_thread(info);
-}
-
-#endif /* GPR_WINDOWS */
diff --git a/src/core/lib/gprpp/manual_constructor.h b/src/core/lib/gprpp/manual_constructor.h
index a177048605..7f827ca8b7 100644
--- a/src/core/lib/gprpp/manual_constructor.h
+++ b/src/core/lib/gprpp/manual_constructor.h
@@ -156,7 +156,7 @@ class PolymorphicManualConstructor {
static_assert(
manual_ctor_impl::is_one_of<DerivedType, DerivedTypes...>::value,
"DerivedType must be one of the predeclared DerivedTypes");
- GPR_ASSERT(reinterpret_cast<BaseType*>(static_cast<DerivedType*>(p)) == p);
+ GPR_ASSERT(static_cast<BaseType*>(p) == p);
}
typename std::aligned_storage<
diff --git a/src/core/lib/gprpp/memory.h b/src/core/lib/gprpp/memory.h
index f84e20eeea..ba2f546675 100644
--- a/src/core/lib/gprpp/memory.h
+++ b/src/core/lib/gprpp/memory.h
@@ -30,12 +30,12 @@
namespace grpc_core {
// The alignment of memory returned by gpr_malloc().
-constexpr size_t kAllignmentForDefaultAllocationInBytes = 8;
+constexpr size_t kAlignmentForDefaultAllocationInBytes = 8;
// Alternative to new, since we cannot use it (for fear of libstdc++)
template <typename T, typename... Args>
inline T* New(Args&&... args) {
- void* p = alignof(T) > kAllignmentForDefaultAllocationInBytes
+ void* p = alignof(T) > kAlignmentForDefaultAllocationInBytes
? gpr_malloc_aligned(sizeof(T), alignof(T))
: gpr_malloc(sizeof(T));
return new (p) T(std::forward<Args>(args)...);
@@ -45,7 +45,7 @@ inline T* New(Args&&... args) {
template <typename T>
inline void Delete(T* p) {
p->~T();
- if (alignof(T) > kAllignmentForDefaultAllocationInBytes) {
+ if (alignof(T) > kAlignmentForDefaultAllocationInBytes) {
gpr_free_aligned(p);
} else {
gpr_free(p);
diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h
index 9e9e7f015f..a5bc8d8efc 100644
--- a/src/core/lib/gprpp/orphanable.h
+++ b/src/core/lib/gprpp/orphanable.h
@@ -24,6 +24,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include <cinttypes>
#include <memory>
#include "src/core/lib/debug/trace.h"
diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h
index 02b115a40e..46bfaf7fb8 100644
--- a/src/core/lib/gprpp/ref_counted.h
+++ b/src/core/lib/gprpp/ref_counted.h
@@ -24,6 +24,8 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include <cinttypes>
+
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/gprpp/debug_location.h"
diff --git a/src/core/lib/gprpp/ref_counted_ptr.h b/src/core/lib/gprpp/ref_counted_ptr.h
index 72088e76ef..388e2ec410 100644
--- a/src/core/lib/gprpp/ref_counted_ptr.h
+++ b/src/core/lib/gprpp/ref_counted_ptr.h
@@ -33,6 +33,7 @@ template <typename T>
class RefCountedPtr {
public:
RefCountedPtr() {}
+ RefCountedPtr(std::nullptr_t) {}
// If value is non-null, we take ownership of a ref to it.
explicit RefCountedPtr(T* value) { value_ = value; }
diff --git a/src/core/lib/gprpp/thd.h b/src/core/lib/gprpp/thd.h
new file mode 100644
index 0000000000..05c7ded45f
--- /dev/null
+++ b/src/core/lib/gprpp/thd.h
@@ -0,0 +1,135 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_GPRPP_THD_H
+#define GRPC_CORE_LIB_GPRPP_THD_H
+
+/** Internal thread interface. */
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd_id.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/memory.h"
+
+namespace grpc_core {
+namespace internal {
+
+/// Base class for platform-specific thread-state
+class ThreadInternalsInterface {
+ public:
+ virtual ~ThreadInternalsInterface() {}
+ virtual void Start() GRPC_ABSTRACT;
+ virtual void Join() GRPC_ABSTRACT;
+ GRPC_ABSTRACT_BASE_CLASS
+};
+
+} // namespace internal
+
+class Thread {
+ public:
+ /// Default constructor only to allow use in structs that lack constructors
+ /// Does not produce a validly-constructed thread; must later
+ /// use placement new to construct a real thread. Does not init mu_ and cv_
+ Thread() : state_(FAKE), impl_(nullptr) {}
+
+ /// Normal constructor to create a thread with name \a thd_name,
+ /// which will execute a thread based on function \a thd_body
+ /// with argument \a arg once it is started.
+ /// The optional \a success argument indicates whether the thread
+ /// is successfully created.
+ Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+ bool* success = nullptr);
+
+ /// Move constructor for thread. After this is called, the other thread
+ /// no longer represents a living thread object
+ Thread(Thread&& other) : state_(other.state_), impl_(other.impl_) {
+ other.state_ = MOVED;
+ other.impl_ = nullptr;
+ }
+
+ /// Move assignment operator for thread. After this is called, the other
+ /// thread no longer represents a living thread object. Not allowed if this
+ /// thread actually exists
+ Thread& operator=(Thread&& other) {
+ if (this != &other) {
+ // TODO(vjpai): if we can be sure that all Thread's are actually
+ // constructed, then we should assert GPR_ASSERT(impl_ == nullptr) here.
+ // However, as long as threads come in structures that are
+ // allocated via gpr_malloc, this will not be the case, so we cannot
+ // assert it for the time being.
+ state_ = other.state_;
+ impl_ = other.impl_;
+ other.state_ = MOVED;
+ other.impl_ = nullptr;
+ }
+ return *this;
+ }
+
+ /// The destructor is strictly optional; either the thread never came to life
+ /// and the constructor itself killed it or it has already been joined and
+ /// the Join function kills it. The destructor shouldn't have to do anything.
+ ~Thread() { GPR_ASSERT(impl_ == nullptr); }
+
+ void Start() {
+ if (impl_ != nullptr) {
+ GPR_ASSERT(state_ == ALIVE);
+ state_ = STARTED;
+ impl_->Start();
+ } else {
+ GPR_ASSERT(state_ == FAILED);
+ }
+ };
+
+ void Join() {
+ if (impl_ != nullptr) {
+ impl_->Join();
+ grpc_core::Delete(impl_);
+ state_ = DONE;
+ impl_ = nullptr;
+ } else {
+ GPR_ASSERT(state_ == FAILED);
+ }
+ };
+
+ static void Init();
+ static bool AwaitAll(gpr_timespec deadline);
+
+ private:
+ Thread(const Thread&) = delete;
+ Thread& operator=(const Thread&) = delete;
+
+ /// The thread states are as follows:
+ /// FAKE -- just a dummy placeholder Thread created by the default constructor
+ /// ALIVE -- an actual thread of control exists associated with this thread
+ /// STARTED -- the thread of control has been started
+ /// DONE -- the thread of control has completed and been joined
+ /// FAILED -- the thread of control never came alive
+ /// MOVED -- contents were moved out and we're no longer tracking them
+ enum ThreadState { FAKE, ALIVE, STARTED, DONE, FAILED, MOVED };
+ ThreadState state_;
+ internal::ThreadInternalsInterface* impl_;
+};
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_GPRPP_THD_H */
diff --git a/src/core/lib/gprpp/thd_posix.cc b/src/core/lib/gprpp/thd_posix.cc
new file mode 100644
index 0000000000..2f6c2edcae
--- /dev/null
+++ b/src/core/lib/gprpp/thd_posix.cc
@@ -0,0 +1,209 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* Posix implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_POSIX_SYNC
+
+#include "src/core/lib/gprpp/thd.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd_id.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/core/lib/gpr/fork.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/memory.h"
+
+namespace grpc_core {
+namespace {
+gpr_mu g_mu;
+gpr_cv g_cv;
+int g_thread_count;
+int g_awaiting_threads;
+
+class ThreadInternalsPosix;
+struct thd_arg {
+ ThreadInternalsPosix* thread;
+ void (*body)(void* arg); /* body of a thread */
+ void* arg; /* argument to a thread */
+ const char* name; /* name of thread. Can be nullptr. */
+};
+
+class ThreadInternalsPosix
+ : public grpc_core::internal::ThreadInternalsInterface {
+ public:
+ ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg),
+ void* arg, bool* success)
+ : started_(false) {
+ gpr_mu_init(&mu_);
+ gpr_cv_init(&ready_);
+ pthread_attr_t attr;
+ /* don't use gpr_malloc as we may cause an infinite recursion with
+ * the profiling code */
+ thd_arg* info = static_cast<thd_arg*>(malloc(sizeof(*info)));
+ GPR_ASSERT(info != nullptr);
+ info->thread = this;
+ info->body = thd_body;
+ info->arg = arg;
+ info->name = thd_name;
+ inc_thd_count();
+
+ GPR_ASSERT(pthread_attr_init(&attr) == 0);
+ GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
+ 0);
+
+ *success =
+ (pthread_create(&pthread_id_, &attr,
+ [](void* v) -> void* {
+ thd_arg arg = *static_cast<thd_arg*>(v);
+ free(v);
+ if (arg.name != nullptr) {
+#if GPR_APPLE_PTHREAD_NAME
+ /* Apple supports 64 characters, and will
+ * truncate if it's longer. */
+ pthread_setname_np(arg.name);
+#elif GPR_LINUX_PTHREAD_NAME
+ /* Linux supports 16 characters max, and will
+ * error if it's longer. */
+ char buf[16];
+ size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
+ strncpy(buf, arg.name, buf_len);
+ buf[buf_len] = '\0';
+ pthread_setname_np(pthread_self(), buf);
+#endif // GPR_APPLE_PTHREAD_NAME
+ }
+
+ gpr_mu_lock(&arg.thread->mu_);
+ while (!arg.thread->started_) {
+ gpr_cv_wait(&arg.thread->ready_, &arg.thread->mu_,
+ gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ }
+ gpr_mu_unlock(&arg.thread->mu_);
+
+ (*arg.body)(arg.arg);
+ dec_thd_count();
+ return nullptr;
+ },
+ info) == 0);
+
+ GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
+
+ if (!success) {
+ /* don't use gpr_free, as this was allocated using malloc (see above) */
+ free(info);
+ dec_thd_count();
+ }
+ };
+
+ ~ThreadInternalsPosix() override {
+ gpr_mu_destroy(&mu_);
+ gpr_cv_destroy(&ready_);
+ }
+
+ void Start() override {
+ gpr_mu_lock(&mu_);
+ started_ = true;
+ gpr_cv_signal(&ready_);
+ gpr_mu_unlock(&mu_);
+ }
+
+ void Join() override { pthread_join(pthread_id_, nullptr); }
+
+ private:
+ /*****************************************
+ * Only used when fork support is enabled
+ */
+
+ static void inc_thd_count() {
+ if (grpc_fork_support_enabled()) {
+ gpr_mu_lock(&g_mu);
+ g_thread_count++;
+ gpr_mu_unlock(&g_mu);
+ }
+ }
+
+ static void dec_thd_count() {
+ if (grpc_fork_support_enabled()) {
+ gpr_mu_lock(&g_mu);
+ g_thread_count--;
+ if (g_awaiting_threads && g_thread_count == 0) {
+ gpr_cv_signal(&g_cv);
+ }
+ gpr_mu_unlock(&g_mu);
+ }
+ }
+
+ gpr_mu mu_;
+ gpr_cv ready_;
+ bool started_;
+ pthread_t pthread_id_;
+};
+
+} // namespace
+
+Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+ bool* success) {
+ bool outcome = false;
+ impl_ =
+ grpc_core::New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome);
+ if (outcome) {
+ state_ = ALIVE;
+ } else {
+ state_ = FAILED;
+ grpc_core::Delete(impl_);
+ impl_ = nullptr;
+ }
+
+ if (success != nullptr) {
+ *success = outcome;
+ }
+}
+
+void Thread::Init() {
+ gpr_mu_init(&g_mu);
+ gpr_cv_init(&g_cv);
+ g_thread_count = 0;
+ g_awaiting_threads = 0;
+}
+
+bool Thread::AwaitAll(gpr_timespec deadline) {
+ gpr_mu_lock(&g_mu);
+ g_awaiting_threads = 1;
+ int res = 0;
+ while ((g_thread_count > 0) &&
+ (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0)) {
+ res = gpr_cv_wait(&g_cv, &g_mu, deadline);
+ }
+ g_awaiting_threads = 0;
+ gpr_mu_unlock(&g_mu);
+ return res == 0;
+}
+
+} // namespace grpc_core
+
+// The following is in the external namespace as it is exposed as C89 API
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }
+
+#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/lib/gprpp/thd_windows.cc b/src/core/lib/gprpp/thd_windows.cc
new file mode 100644
index 0000000000..59ea02f3d2
--- /dev/null
+++ b/src/core/lib/gprpp/thd_windows.cc
@@ -0,0 +1,162 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* Windows implementation for gpr threads. */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINDOWS
+
+#include "src/core/lib/gprpp/thd.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd_id.h>
+#include <string.h>
+
+#include "src/core/lib/gprpp/memory.h"
+
+#if defined(_MSC_VER)
+#define thread_local __declspec(thread)
+#define WIN_LAMBDA
+#elif defined(__GNUC__)
+#define thread_local __thread
+#define WIN_LAMBDA WINAPI
+#else
+#error "Unknown compiler - please file a bug report"
+#endif
+
+namespace {
+class ThreadInternalsWindows;
+struct thd_info {
+ ThreadInternalsWindows* thread;
+ void (*body)(void* arg); /* body of a thread */
+ void* arg; /* argument to a thread */
+ HANDLE join_event; /* the join event */
+};
+
+thread_local struct thd_info* g_thd_info;
+
+class ThreadInternalsWindows
+ : public grpc_core::internal::ThreadInternalsInterface {
+ public:
+ ThreadInternalsWindows(void (*thd_body)(void* arg), void* arg, bool* success)
+ : started_(false) {
+ gpr_mu_init(&mu_);
+ gpr_cv_init(&ready_);
+
+ HANDLE handle;
+ info_ = (struct thd_info*)gpr_malloc(sizeof(*info_));
+ info_->thread = this;
+ info_->body = thd_body;
+ info_->arg = arg;
+
+ info_->join_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (info_->join_event == nullptr) {
+ gpr_free(info_);
+ *success = false;
+ } else {
+ handle = CreateThread(
+ nullptr, 64 * 1024,
+ [](void* v) WIN_LAMBDA -> DWORD {
+ g_thd_info = static_cast<thd_info*>(v);
+ gpr_mu_lock(&g_thd_info->thread->mu_);
+ while (!g_thd_info->thread->started_) {
+ gpr_cv_wait(&g_thd_info->thread->ready_, &g_thd_info->thread->mu_,
+ gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ }
+ gpr_mu_unlock(&g_thd_info->thread->mu_);
+ g_thd_info->body(g_thd_info->arg);
+ BOOL ret = SetEvent(g_thd_info->join_event);
+ GPR_ASSERT(ret);
+ return 0;
+ },
+ info_, 0, nullptr);
+ if (handle == nullptr) {
+ destroy_thread();
+ *success = false;
+ } else {
+ CloseHandle(handle);
+ *success = true;
+ }
+ }
+ }
+
+ ~ThreadInternalsWindows() override {
+ gpr_mu_destroy(&mu_);
+ gpr_cv_destroy(&ready_);
+ }
+
+ void Start() override {
+ gpr_mu_lock(&mu_);
+ started_ = true;
+ gpr_cv_signal(&ready_);
+ gpr_mu_unlock(&mu_);
+ }
+
+ void Join() override {
+ DWORD ret = WaitForSingleObject(info_->join_event, INFINITE);
+ GPR_ASSERT(ret == WAIT_OBJECT_0);
+ destroy_thread();
+ }
+
+ private:
+ void destroy_thread() {
+ CloseHandle(info_->join_event);
+ gpr_free(info_);
+ }
+
+ gpr_mu mu_;
+ gpr_cv ready_;
+ bool started_;
+ thd_info* info_;
+};
+
+} // namespace
+
+namespace grpc_core {
+
+void Thread::Init() {}
+
+bool Thread::AwaitAll(gpr_timespec deadline) {
+ // TODO: Consider adding this if needed
+ return false;
+}
+
+Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
+ bool* success) {
+ bool outcome = false;
+ impl_ = grpc_core::New<ThreadInternalsWindows>(thd_body, arg, &outcome);
+ if (outcome) {
+ state_ = ALIVE;
+ } else {
+ state_ = FAILED;
+ grpc_core::Delete(impl_);
+ impl_ = nullptr;
+ }
+
+ if (success != nullptr) {
+ *success = outcome;
+ }
+}
+
+} // namespace grpc_core
+
+gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)g_thd_info; }
+
+#endif /* GPR_WINDOWS */
diff --git a/src/core/lib/iomgr/endpoint.cc b/src/core/lib/iomgr/endpoint.cc
index e22c21e4bd..92e7930111 100644
--- a/src/core/lib/iomgr/endpoint.cc
+++ b/src/core/lib/iomgr/endpoint.cc
@@ -20,6 +20,8 @@
#include "src/core/lib/iomgr/endpoint.h"
+grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+
void grpc_endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* slices,
grpc_closure* cb) {
ep->vtable->read(ep, slices, cb);
diff --git a/src/core/lib/iomgr/endpoint_pair_windows.cc b/src/core/lib/iomgr/endpoint_pair_windows.cc
index 416c9d88a1..177331d681 100644
--- a/src/core/lib/iomgr/endpoint_pair_windows.cc
+++ b/src/core/lib/iomgr/endpoint_pair_windows.cc
@@ -22,6 +22,7 @@
#ifdef GRPC_WINSOCK_SOCKET
#include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include <errno.h>
@@ -46,19 +47,19 @@ static void create_sockets(SOCKET sv[2]) {
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_family = AF_INET;
- GPR_ASSERT(bind(lst_sock, (struct sockaddr*)&addr, sizeof(addr)) !=
+ GPR_ASSERT(bind(lst_sock, (grpc_sockaddr*)&addr, sizeof(addr)) !=
SOCKET_ERROR);
GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
- GPR_ASSERT(getsockname(lst_sock, (struct sockaddr*)&addr, &addr_len) !=
+ GPR_ASSERT(getsockname(lst_sock, (grpc_sockaddr*)&addr, &addr_len) !=
SOCKET_ERROR);
cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
WSA_FLAG_OVERLAPPED);
GPR_ASSERT(cli_sock != INVALID_SOCKET);
- GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr*)&addr, addr_len, NULL, NULL,
+ GPR_ASSERT(WSAConnect(cli_sock, (grpc_sockaddr*)&addr, addr_len, NULL, NULL,
NULL, NULL) == 0);
- svr_sock = accept(lst_sock, (struct sockaddr*)&addr, &addr_len);
+ svr_sock = accept(lst_sock, (grpc_sockaddr*)&addr, &addr_len);
GPR_ASSERT(svr_sock != INVALID_SOCKET);
closesocket(lst_sock);
diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc
index d3cbaf9d0a..0ef7c03056 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -59,7 +59,7 @@
//#define GRPC_EPOLLEX_CREATE_WORKERS_ON_HEAP 1
#define MAX_EPOLL_EVENTS 100
-#define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 16
+#define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 1
grpc_core::DebugOnlyTraceFlag grpc_trace_pollable_refcount(false,
"pollable_refcount");
@@ -198,7 +198,6 @@ struct grpc_pollset_worker {
struct grpc_pollset {
gpr_mu mu;
- gpr_atm worker_count;
pollable* active_pollable;
bool kicked_without_poller;
grpc_closure* shutdown_closure;
@@ -686,7 +685,6 @@ static grpc_error* pollset_kick_all(grpc_pollset* pollset) {
static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
gpr_mu_init(&pollset->mu);
- gpr_atm_no_barrier_store(&pollset->worker_count, 0);
pollset->active_pollable = POLLABLE_REF(g_empty_pollable, "pollset");
pollset->kicked_without_poller = false;
pollset->shutdown_closure = nullptr;
@@ -760,20 +758,8 @@ static grpc_error* pollable_process_events(grpc_pollset* pollset,
pollable* pollable_obj, bool drain) {
GPR_TIMER_SCOPE("pollable_process_events", 0);
static const char* err_desc = "pollset_process_events";
- // Use a simple heuristic to determine how many fd events to process
- // per loop iteration. (events/workers)
- int handle_count = 1;
- int worker_count = gpr_atm_no_barrier_load(&pollset->worker_count);
- GPR_ASSERT(worker_count > 0);
- handle_count =
- (pollable_obj->event_count - pollable_obj->event_cursor) / worker_count;
- if (handle_count == 0) {
- handle_count = 1;
- } else if (handle_count > MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL) {
- handle_count = MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL;
- }
grpc_error* error = GRPC_ERROR_NONE;
- for (int i = 0; (drain || i < handle_count) &&
+ for (int i = 0; (drain || i < MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL) &&
pollable_obj->event_cursor != pollable_obj->event_count;
i++) {
int n = pollable_obj->event_cursor++;
@@ -898,7 +884,6 @@ static bool begin_worker(grpc_pollset* pollset, grpc_pollset_worker* worker,
GPR_TIMER_SCOPE("begin_worker", 0);
bool do_poll =
(pollset->shutdown_closure == nullptr && !pollset->already_shutdown);
- gpr_atm_no_barrier_fetch_add(&pollset->worker_count, 1);
if (worker_hdl != nullptr) *worker_hdl = worker;
worker->initialized_cv = false;
worker->kicked = false;
@@ -979,7 +964,6 @@ static void end_worker(grpc_pollset* pollset, grpc_pollset_worker* worker,
if (worker->initialized_cv) {
gpr_cv_destroy(&worker->cv);
}
- gpr_atm_no_barrier_fetch_add(&pollset->worker_count, -1);
}
#ifndef NDEBUG
diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc
index e979ff7eb5..436537bc0b 100644
--- a/src/core/lib/iomgr/ev_poll_posix.cc
+++ b/src/core/lib/iomgr/ev_poll_posix.cc
@@ -38,9 +38,9 @@
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/gpr/murmur_hash.h"
-#include "src/core/lib/gpr/thd.h"
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/block_annotate.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/wakeup_fd_cv.h"
@@ -255,8 +255,13 @@ typedef struct poll_result {
} poll_result;
typedef struct poll_args {
+ grpc_core::Thread poller_thd;
gpr_cv trigger;
int trigger_set;
+ bool harvestable;
+ gpr_cv harvest;
+ bool joinable;
+ gpr_cv join;
struct pollfd* fds;
nfds_t nfds;
poll_result* result;
@@ -266,15 +271,17 @@ typedef struct poll_args {
// This is a 2-tiered cache, we mantain a hash table
// of active poll calls, so we can wait on the result
-// of that call. We also maintain a freelist of inactive
-// poll threads.
+// of that call. We also maintain freelists of inactive
+// poll args and of dead poller threads.
typedef struct poll_hash_table {
poll_args* free_pollers;
poll_args** active_pollers;
+ poll_args* dead_pollers;
unsigned int size;
unsigned int count;
} poll_hash_table;
+// TODO(kpayson64): Eliminate use of global non-POD variables
poll_hash_table poll_cache;
grpc_cv_fd_table g_cvfds;
@@ -869,7 +876,6 @@ static grpc_error* pollset_work(grpc_pollset* pollset,
grpc_pollset_worker** worker_hdl,
grpc_millis deadline) {
GPR_TIMER_SCOPE("pollset_work", 0);
-
grpc_pollset_worker worker;
if (worker_hdl) *worker_hdl = &worker;
grpc_error* error = GRPC_ERROR_NONE;
@@ -920,7 +926,8 @@ static grpc_error* pollset_work(grpc_pollset* pollset,
gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
while (keep_polling) {
keep_polling = 0;
- if (!pollset->kicked_without_pollers) {
+ if (!pollset->kicked_without_pollers ||
+ deadline <= grpc_core::ExecCtx::Get()->Now()) {
if (!added_worker) {
push_front_worker(pollset, &worker);
added_worker = 1;
@@ -1301,6 +1308,7 @@ static void pollset_set_del_fd(grpc_pollset_set* pollset_set, grpc_fd* fd) {
static void run_poll(void* args);
static void cache_poller_locked(poll_args* args);
+static void cache_harvest_locked();
static void cache_insert_locked(poll_args* args) {
uint32_t key = gpr_murmur_hash3(args->fds, args->nfds * sizeof(struct pollfd),
@@ -1363,6 +1371,10 @@ static poll_args* get_poller_locked(struct pollfd* fds, nfds_t count) {
poll_args* pargs =
static_cast<poll_args*>(gpr_malloc(sizeof(struct poll_args)));
gpr_cv_init(&pargs->trigger);
+ gpr_cv_init(&pargs->harvest);
+ gpr_cv_init(&pargs->join);
+ pargs->harvestable = false;
+ pargs->joinable = false;
pargs->fds = fds;
pargs->nfds = count;
pargs->next = nullptr;
@@ -1370,11 +1382,9 @@ static poll_args* get_poller_locked(struct pollfd* fds, nfds_t count) {
pargs->trigger_set = 0;
init_result(pargs);
cache_poller_locked(pargs);
- gpr_thd_id t_id;
- gpr_thd_options opt = gpr_thd_options_default();
gpr_ref(&g_cvfds.pollcount);
- gpr_thd_options_set_detached(&opt);
- GPR_ASSERT(gpr_thd_new(&t_id, "grpc_poller", &run_poll, pargs, &opt));
+ pargs->poller_thd = grpc_core::Thread("grpc_poller", &run_poll, pargs);
+ pargs->poller_thd.Start();
return pargs;
}
@@ -1439,7 +1449,33 @@ static void cache_destroy_locked(poll_args* args) {
poll_cache.free_pollers = args->next;
}
- gpr_free(args);
+ // Now move this args to the dead poller list for later join
+ if (poll_cache.dead_pollers != nullptr) {
+ poll_cache.dead_pollers->prev = args;
+ }
+ args->prev = nullptr;
+ args->next = poll_cache.dead_pollers;
+ poll_cache.dead_pollers = args;
+}
+
+static void cache_harvest_locked() {
+ while (poll_cache.dead_pollers) {
+ poll_args* args = poll_cache.dead_pollers;
+ poll_cache.dead_pollers = poll_cache.dead_pollers->next;
+ // Keep the list consistent in case new dead pollers get added when we
+ // release the lock below to wait on joining
+ if (poll_cache.dead_pollers) {
+ poll_cache.dead_pollers->prev = nullptr;
+ }
+ args->harvestable = true;
+ gpr_cv_signal(&args->harvest);
+ while (!args->joinable) {
+ gpr_cv_wait(&args->join, &g_cvfds.mu,
+ gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ }
+ args->poller_thd.Join();
+ gpr_free(args);
+ }
}
static void decref_poll_result(poll_result* res) {
@@ -1471,6 +1507,7 @@ static void run_poll(void* args) {
poll_result* result = pargs->result;
int retval = g_cvfds.poll(result->fds, result->nfds, CV_POLL_PERIOD_MS);
gpr_mu_lock(&g_cvfds.mu);
+ cache_harvest_locked();
if (retval != 0) {
result->completed = 1;
result->retval = retval;
@@ -1490,6 +1527,7 @@ static void run_poll(void* args) {
deadline = gpr_time_add(deadline, thread_grace);
pargs->trigger_set = 0;
gpr_cv_wait(&pargs->trigger, &g_cvfds.mu, deadline);
+ cache_harvest_locked();
if (!pargs->trigger_set) {
cache_destroy_locked(pargs);
break;
@@ -1498,10 +1536,15 @@ static void run_poll(void* args) {
gpr_mu_unlock(&g_cvfds.mu);
}
- // We still have the lock here
if (gpr_unref(&g_cvfds.pollcount)) {
gpr_cv_signal(&g_cvfds.shutdown_cv);
}
+ while (!pargs->harvestable) {
+ gpr_cv_wait(&pargs->harvest, &g_cvfds.mu,
+ gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ }
+ pargs->joinable = true;
+ gpr_cv_signal(&pargs->join);
gpr_mu_unlock(&g_cvfds.mu);
}
@@ -1514,6 +1557,7 @@ static int cvfd_poll(struct pollfd* fds, nfds_t nfds, int timeout) {
nfds_t nsockfds = 0;
poll_result* result = nullptr;
gpr_mu_lock(&g_cvfds.mu);
+ cache_harvest_locked();
pollcv = static_cast<grpc_cv_node*>(gpr_malloc(sizeof(grpc_cv_node)));
pollcv->next = nullptr;
gpr_cv pollcv_cv;
@@ -1577,12 +1621,14 @@ static int cvfd_poll(struct pollfd* fds, nfds_t nfds, int timeout) {
pargs->trigger_set = 1;
gpr_cv_signal(&pargs->trigger);
gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline);
+ cache_harvest_locked();
res = result->retval;
errno = result->err;
result->watchcount--;
remove_cvn(&result->watchers, pollcv);
} else if (!skip_poll) {
gpr_cv_wait(&pollcv_cv, &g_cvfds.mu, deadline);
+ cache_harvest_locked();
}
idx = 0;
@@ -1639,6 +1685,7 @@ static void global_cv_fd_table_init() {
for (unsigned int i = 0; i < poll_cache.size; i++) {
poll_cache.active_pollers[i] = nullptr;
}
+ poll_cache.dead_pollers = nullptr;
gpr_mu_unlock(&g_cvfds.mu);
}
@@ -1657,6 +1704,7 @@ static void global_cv_fd_table_shutdown() {
grpc_poll_function = g_cvfds.poll;
gpr_free(g_cvfds.cvfds);
+ cache_harvest_locked();
gpr_free(poll_cache.active_pollers);
gpr_mu_unlock(&g_cvfds.mu);
diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc
index 39ce459f1e..8b80070265 100644
--- a/src/core/lib/iomgr/ev_posix.cc
+++ b/src/core/lib/iomgr/ev_posix.cc
@@ -224,26 +224,26 @@ void grpc_fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) {
g_event_engine->fd_notify_on_write(fd, closure);
}
-size_t grpc_pollset_size(void) { return g_event_engine->pollset_size; }
+static size_t pollset_size(void) { return g_event_engine->pollset_size; }
-void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
GRPC_POLLING_API_TRACE("pollset_init(%p)", pollset);
g_event_engine->pollset_init(pollset, mu);
}
-void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
GRPC_POLLING_API_TRACE("pollset_shutdown(%p)", pollset);
g_event_engine->pollset_shutdown(pollset, closure);
}
-void grpc_pollset_destroy(grpc_pollset* pollset) {
+static void pollset_destroy(grpc_pollset* pollset) {
GRPC_POLLING_API_TRACE("pollset_destroy(%p)", pollset);
g_event_engine->pollset_destroy(pollset);
}
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
- grpc_pollset_worker** worker,
- grpc_millis deadline) {
+static grpc_error* pollset_work(grpc_pollset* pollset,
+ grpc_pollset_worker** worker,
+ grpc_millis deadline) {
GRPC_POLLING_API_TRACE("pollset_work(%p, %" PRIdPTR ") begin", pollset,
deadline);
grpc_error* err = g_event_engine->pollset_work(pollset, worker, deadline);
@@ -252,8 +252,8 @@ grpc_error* grpc_pollset_work(grpc_pollset* pollset,
return err;
}
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
- grpc_pollset_worker* specific_worker) {
+static grpc_error* pollset_kick(grpc_pollset* pollset,
+ grpc_pollset_worker* specific_worker) {
GRPC_POLLING_API_TRACE("pollset_kick(%p, %p)", pollset, specific_worker);
return g_event_engine->pollset_kick(pollset, specific_worker);
}
@@ -264,43 +264,57 @@ void grpc_pollset_add_fd(grpc_pollset* pollset, struct grpc_fd* fd) {
g_event_engine->pollset_add_fd(pollset, fd);
}
-grpc_pollset_set* grpc_pollset_set_create(void) {
+void pollset_global_init() {}
+void pollset_global_shutdown() {}
+
+grpc_pollset_vtable grpc_posix_pollset_vtable = {
+ pollset_global_init, pollset_global_shutdown,
+ pollset_init, pollset_shutdown,
+ pollset_destroy, pollset_work,
+ pollset_kick, pollset_size};
+
+static grpc_pollset_set* pollset_set_create(void) {
grpc_pollset_set* pss = g_event_engine->pollset_set_create();
GRPC_POLLING_API_TRACE("pollset_set_create(%p)", pss);
return pss;
}
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {
+static void pollset_set_destroy(grpc_pollset_set* pollset_set) {
GRPC_POLLING_API_TRACE("pollset_set_destroy(%p)", pollset_set);
g_event_engine->pollset_set_destroy(pollset_set);
}
-void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
- grpc_pollset* pollset) {
+static void pollset_set_add_pollset(grpc_pollset_set* pollset_set,
+ grpc_pollset* pollset) {
GRPC_POLLING_API_TRACE("pollset_set_add_pollset(%p, %p)", pollset_set,
pollset);
g_event_engine->pollset_set_add_pollset(pollset_set, pollset);
}
-void grpc_pollset_set_del_pollset(grpc_pollset_set* pollset_set,
- grpc_pollset* pollset) {
+static void pollset_set_del_pollset(grpc_pollset_set* pollset_set,
+ grpc_pollset* pollset) {
GRPC_POLLING_API_TRACE("pollset_set_del_pollset(%p, %p)", pollset_set,
pollset);
g_event_engine->pollset_set_del_pollset(pollset_set, pollset);
}
-void grpc_pollset_set_add_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {
+static void pollset_set_add_pollset_set(grpc_pollset_set* bag,
+ grpc_pollset_set* item) {
GRPC_POLLING_API_TRACE("pollset_set_add_pollset_set(%p, %p)", bag, item);
g_event_engine->pollset_set_add_pollset_set(bag, item);
}
-void grpc_pollset_set_del_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {
+static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
+ grpc_pollset_set* item) {
GRPC_POLLING_API_TRACE("pollset_set_del_pollset_set(%p, %p)", bag, item);
g_event_engine->pollset_set_del_pollset_set(bag, item);
}
+grpc_pollset_set_vtable grpc_posix_pollset_set_vtable = {
+ pollset_set_create, pollset_set_destroy,
+ pollset_set_add_pollset, pollset_set_del_pollset,
+ pollset_set_add_pollset_set, pollset_set_del_pollset_set};
+
void grpc_pollset_set_add_fd(grpc_pollset_set* pollset_set, grpc_fd* fd) {
GRPC_POLLING_API_TRACE("pollset_set_add_fd(%p, %d)", pollset_set,
grpc_fd_wrapped_fd(fd));
diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc
index 132fe87870..2f544b20ab 100644
--- a/src/core/lib/iomgr/exec_ctx.cc
+++ b/src/core/lib/iomgr/exec_ctx.cc
@@ -23,7 +23,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/profiling/timers.h"
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index de97164f02..72d0ae58c1 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -54,23 +54,32 @@ grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec timespec);
namespace grpc_core {
/** Execution context.
* A bag of data that collects information along a callstack.
- * Generally created at public API entry points, and passed down as
- * pointer to child functions that manipulate it.
+ * It is created on the stack at public API entry points, and stored internally
+ * as a thread-local variable.
+ *
+ * Generally, to create an exec_ctx instance, add the following line at the top
+ * of the public API entry point or at the start of a thread's work function :
+ *
+ * grpc_core::ExecCtx exec_ctx;
+ *
+ * Access the created ExecCtx instance using :
+ * grpc_core::ExecCtx::Get()
*
* Specific responsibilities (this may grow in the future):
* - track a list of work that needs to be delayed until the top of the
* call stack (this provides a convenient mechanism to run callbacks
* without worrying about locking issues)
- * - provide a decision maker (via grpc_exec_ctx_ready_to_finish) that provides
+ * - provide a decision maker (via IsReadyToFinish) that provides a
* signal as to whether a borrowed thread should continue to do work or
* should actively try to finish up and get this thread back to its owner
*
* CONVENTIONS:
* - Instance of this must ALWAYS be constructed on the stack, never
* heap allocated.
- * - Instances and pointers to them must always be called exec_ctx.
- * - Instances are always passed as the first argument to a function that
- * takes it, and always as a pointer (grpc_exec_ctx is never copied).
+ * - Exactly one instance of ExecCtx must be created per thread. Instances must
+ * always be called exec_ctx.
+ * - Do not pass exec_ctx as a parameter to a function. Always access it using
+ * grpc_core::ExecCtx::Get()
*/
class ExecCtx {
public:
@@ -171,6 +180,10 @@ on outside context */
return reinterpret_cast<ExecCtx*>(gpr_tls_get(&exec_ctx_));
}
+ static void Set(ExecCtx* exec_ctx) {
+ gpr_tls_set(&exec_ctx_, reinterpret_cast<intptr_t>(exec_ctx));
+ }
+
protected:
/** Check if ready to finish */
virtual bool CheckReadyToFinish() { return false; }
@@ -180,9 +193,6 @@ on outside context */
private:
/** Set exec_ctx_ to exec_ctx */
- void Set(ExecCtx* exec_ctx) {
- gpr_tls_set(&exec_ctx_, reinterpret_cast<intptr_t>(exec_ctx));
- }
grpc_closure_list closure_list_ = GRPC_CLOSURE_LIST_INIT;
CombinerData combiner_data_ = {nullptr, nullptr};
diff --git a/src/core/lib/iomgr/executor.cc b/src/core/lib/iomgr/executor.cc
index e7f412a562..b017db53f8 100644
--- a/src/core/lib/iomgr/executor.cc
+++ b/src/core/lib/iomgr/executor.cc
@@ -29,9 +29,9 @@
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/gpr/spinlock.h"
-#include "src/core/lib/gpr/thd.h"
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#define MAX_DEPTH 2
@@ -43,7 +43,7 @@ typedef struct {
size_t depth;
bool shutdown;
bool queued_long_job;
- gpr_thd_id id;
+ grpc_core::Thread thd;
} thread_state;
static thread_state* g_thread_state;
@@ -101,13 +101,13 @@ void grpc_executor_set_threading(bool threading) {
for (size_t i = 0; i < g_max_threads; i++) {
gpr_mu_init(&g_thread_state[i].mu);
gpr_cv_init(&g_thread_state[i].cv);
+ g_thread_state[i].thd = grpc_core::Thread();
g_thread_state[i].elems = GRPC_CLOSURE_LIST_INIT;
}
- gpr_thd_options opt = gpr_thd_options_default();
- gpr_thd_options_set_joinable(&opt);
- gpr_thd_new(&g_thread_state[0].id, "grpc_executor", executor_thread,
- &g_thread_state[0], &opt);
+ g_thread_state[0].thd =
+ grpc_core::Thread("grpc_executor", executor_thread, &g_thread_state[0]);
+ g_thread_state[0].thd.Start();
} else {
if (cur_threads == 0) return;
for (size_t i = 0; i < g_max_threads; i++) {
@@ -121,7 +121,7 @@ void grpc_executor_set_threading(bool threading) {
gpr_spinlock_lock(&g_adding_thread_lock);
gpr_spinlock_unlock(&g_adding_thread_lock);
for (gpr_atm i = 0; i < g_cur_threads; i++) {
- gpr_thd_join(g_thread_state[i].id);
+ g_thread_state[i].thd.Join();
}
gpr_atm_no_barrier_store(&g_cur_threads, 0);
for (size_t i = 0; i < g_max_threads; i++) {
@@ -264,10 +264,10 @@ static void executor_push(grpc_closure* closure, grpc_error* error,
if (cur_thread_count < g_max_threads) {
gpr_atm_no_barrier_store(&g_cur_threads, cur_thread_count + 1);
- gpr_thd_options opt = gpr_thd_options_default();
- gpr_thd_options_set_joinable(&opt);
- gpr_thd_new(&g_thread_state[cur_thread_count].id, "gpr_executor",
- executor_thread, &g_thread_state[cur_thread_count], &opt);
+ g_thread_state[cur_thread_count].thd =
+ grpc_core::Thread("grpc_executor", executor_thread,
+ &g_thread_state[cur_thread_count]);
+ g_thread_state[cur_thread_count].thd.Start();
}
gpr_spinlock_unlock(&g_adding_thread_lock);
}
diff --git a/src/core/lib/iomgr/fork_posix.cc b/src/core/lib/iomgr/fork_posix.cc
index d32fbc4588..f8645ab157 100644
--- a/src/core/lib/iomgr/fork_posix.cc
+++ b/src/core/lib/iomgr/fork_posix.cc
@@ -29,7 +29,7 @@
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/fork.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/timer_manager.h"
@@ -53,7 +53,7 @@ void grpc_prefork() {
grpc_timer_manager_set_threading(false);
grpc_executor_set_threading(false);
grpc_core::ExecCtx::Get()->Flush();
- if (!gpr_await_threads(
+ if (!grpc_core::Thread::AwaitAll(
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(3, GPR_TIMESPAN)))) {
gpr_log(GPR_ERROR, "gRPC thread still active! Cannot fork!");
diff --git a/src/core/lib/iomgr/iocp_windows.cc b/src/core/lib/iomgr/iocp_windows.cc
index 5285734719..ce77231036 100644
--- a/src/core/lib/iomgr/iocp_windows.cc
+++ b/src/core/lib/iomgr/iocp_windows.cc
@@ -30,7 +30,7 @@
#include <grpc/support/log_windows.h>
#include "src/core/lib/debug/stats.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/iocp_windows.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/socket_windows.h"
diff --git a/src/core/lib/iomgr/iomgr.cc b/src/core/lib/iomgr/iomgr.cc
index 70a80e1998..468814eaee 100644
--- a/src/core/lib/iomgr/iomgr.cc
+++ b/src/core/lib/iomgr/iomgr.cc
@@ -31,8 +31,8 @@
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
@@ -47,6 +47,7 @@ static grpc_iomgr_object g_root_object;
void grpc_iomgr_init() {
grpc_core::ExecCtx exec_ctx;
+ grpc_determine_iomgr_platform();
g_shutdown = 0;
gpr_mu_init(&g_mu);
gpr_cv_init(&g_rcv);
diff --git a/src/core/lib/iomgr/iomgr_custom.cc b/src/core/lib/iomgr/iomgr_custom.cc
new file mode 100644
index 0000000000..d34c8e7cd1
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_custom.cc
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <grpc/support/thd_id.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/pollset_set_custom.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
+
+gpr_thd_id g_init_thread;
+
+static void iomgr_platform_init(void) {
+ grpc_core::ExecCtx exec_ctx;
+ grpc_executor_set_threading(false);
+ g_init_thread = gpr_thd_currentid();
+ grpc_pollset_global_init();
+}
+static void iomgr_platform_flush(void) {}
+static void iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); }
+
+static grpc_iomgr_platform_vtable vtable = {
+ iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+
+void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
+ grpc_custom_resolver_vtable* resolver,
+ grpc_custom_timer_vtable* timer,
+ grpc_custom_poller_vtable* poller) {
+ grpc_custom_endpoint_init(socket);
+ grpc_custom_timer_init(timer);
+ grpc_custom_pollset_init(poller);
+ grpc_custom_pollset_set_init();
+ grpc_custom_resolver_init(resolver);
+ grpc_set_iomgr_platform_vtable(&vtable);
+}
+
+#ifdef GRPC_CUSTOM_SOCKET
+grpc_iomgr_platform_vtable* grpc_default_iomgr_platform_vtable() {
+ return &vtable;
+}
+#endif
diff --git a/src/core/lib/iomgr/iomgr_uv.h b/src/core/lib/iomgr/iomgr_custom.h
index 4d62f00ad6..ceb6c65db2 100644
--- a/src/core/lib/iomgr/iomgr_uv.h
+++ b/src/core/lib/iomgr/iomgr_custom.h
@@ -16,24 +16,32 @@
*
*/
-#ifndef GRPC_CORE_LIB_IOMGR_IOMGR_UV_H
-#define GRPC_CORE_LIB_IOMGR_IOMGR_UV_H
+#ifndef GRPC_CORE_LIB_IOMGR_IOMGR_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_IOMGR_CUSTOM_H
#include <grpc/support/port_platform.h>
-#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/timer_custom.h"
#include <grpc/support/thd_id.h>
/* The thread ID of the thread on which grpc was initialized. Used to verify
- * that all calls into libuv are made on that same thread */
+ * that all calls into the custom iomgr are made on that same thread */
extern gpr_thd_id g_init_thread;
-#ifdef GRPC_UV_THREAD_CHECK
-#define GRPC_UV_ASSERT_SAME_THREAD() \
+#ifdef GRPC_CUSTOM_IOMGR_THREAD_CHECK
+#define GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD() \
GPR_ASSERT(gpr_thd_currentid() == g_init_thread)
#else
-#define GRPC_UV_ASSERT_SAME_THREAD()
+#define GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD()
#endif /* GRPC_UV_THREAD_CHECK */
-#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_UV_H */
+void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
+ grpc_custom_resolver_vtable* resolver,
+ grpc_custom_timer_vtable* timer,
+ grpc_custom_poller_vtable* poller);
+
+#endif /* GRPC_CORE_LIB_IOMGR_IOMGR_CUSTOM_H */
diff --git a/src/core/lib/iomgr/iomgr_internal.cc b/src/core/lib/iomgr/iomgr_internal.cc
new file mode 100644
index 0000000000..32dbabb79d
--- /dev/null
+++ b/src/core/lib/iomgr/iomgr_internal.cc
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_manager.h"
+
+static grpc_iomgr_platform_vtable* iomgr_platform_vtable = nullptr;
+
+void grpc_set_iomgr_platform_vtable(grpc_iomgr_platform_vtable* vtable) {
+ iomgr_platform_vtable = vtable;
+}
+
+void grpc_determine_iomgr_platform() {
+ if (iomgr_platform_vtable == nullptr) {
+ grpc_set_default_iomgr_platform();
+ }
+}
+
+void grpc_iomgr_platform_init() { iomgr_platform_vtable->init(); }
+
+void grpc_iomgr_platform_flush() { iomgr_platform_vtable->flush(); }
+
+void grpc_iomgr_platform_shutdown() { iomgr_platform_vtable->shutdown(); }
diff --git a/src/core/lib/iomgr/iomgr_internal.h b/src/core/lib/iomgr/iomgr_internal.h
index 644219fb4d..b011d9c7b1 100644
--- a/src/core/lib/iomgr/iomgr_internal.h
+++ b/src/core/lib/iomgr/iomgr_internal.h
@@ -31,9 +31,21 @@ typedef struct grpc_iomgr_object {
struct grpc_iomgr_object* prev;
} grpc_iomgr_object;
+typedef struct grpc_iomgr_platform_vtable {
+ void (*init)(void);
+ void (*flush)(void);
+ void (*shutdown)(void);
+} grpc_iomgr_platform_vtable;
+
void grpc_iomgr_register_object(grpc_iomgr_object* obj, const char* name);
void grpc_iomgr_unregister_object(grpc_iomgr_object* obj);
+void grpc_determine_iomgr_platform();
+
+void grpc_set_iomgr_platform_vtable(grpc_iomgr_platform_vtable* vtable);
+
+void grpc_set_default_iomgr_platform();
+
void grpc_iomgr_platform_init(void);
/** flush any globally queued work from iomgr */
void grpc_iomgr_platform_flush(void);
diff --git a/src/core/lib/iomgr/iomgr_posix.cc b/src/core/lib/iomgr/iomgr_posix.cc
index 35b8adf01e..66c9cb7ff7 100644
--- a/src/core/lib/iomgr/iomgr_posix.cc
+++ b/src/core/lib/iomgr/iomgr_posix.cc
@@ -24,19 +24,44 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/iomgr_posix.h"
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/timer.h"
-void grpc_iomgr_platform_init(void) {
+extern grpc_tcp_server_vtable grpc_posix_tcp_server_vtable;
+extern grpc_tcp_client_vtable grpc_posix_tcp_client_vtable;
+extern grpc_timer_vtable grpc_generic_timer_vtable;
+extern grpc_pollset_vtable grpc_posix_pollset_vtable;
+extern grpc_pollset_set_vtable grpc_posix_pollset_set_vtable;
+extern grpc_address_resolver_vtable grpc_posix_resolver_vtable;
+
+static void iomgr_platform_init(void) {
grpc_wakeup_fd_global_init();
grpc_event_engine_init();
}
-void grpc_iomgr_platform_flush(void) {}
+static void iomgr_platform_flush(void) {}
-void grpc_iomgr_platform_shutdown(void) {
+static void iomgr_platform_shutdown(void) {
grpc_event_engine_shutdown();
grpc_wakeup_fd_global_destroy();
}
+static grpc_iomgr_platform_vtable vtable = {
+ iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+
+void grpc_set_default_iomgr_platform() {
+ grpc_set_tcp_client_impl(&grpc_posix_tcp_client_vtable);
+ grpc_set_tcp_server_impl(&grpc_posix_tcp_server_vtable);
+ grpc_set_timer_impl(&grpc_generic_timer_vtable);
+ grpc_set_pollset_vtable(&grpc_posix_pollset_vtable);
+ grpc_set_pollset_set_vtable(&grpc_posix_pollset_set_vtable);
+ grpc_set_resolver_impl(&grpc_posix_resolver_vtable);
+ grpc_set_iomgr_platform_vtable(&vtable);
+}
+
#endif /* GRPC_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/iomgr_uv.cc b/src/core/lib/iomgr/iomgr_uv.cc
index c11c37ca20..4a984446db 100644
--- a/src/core/lib/iomgr/iomgr_uv.cc
+++ b/src/core/lib/iomgr/iomgr_uv.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,26 +20,21 @@
#include "src/core/lib/iomgr/port.h"
-#ifdef GRPC_UV
+#if defined(GRPC_CUSTOM_SOCKET) && defined(GRPC_UV)
-#include <grpc/support/thd_id.h>
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/timer_custom.h"
-#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/executor.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/pollset_uv.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
+extern grpc_socket_vtable grpc_uv_socket_vtable;
+extern grpc_custom_resolver_vtable uv_resolver_vtable;
+extern grpc_custom_timer_vtable uv_timer_vtable;
+extern grpc_custom_poller_vtable uv_pollset_vtable;
-gpr_thd_id g_init_thread;
-
-void grpc_iomgr_platform_init(void) {
- grpc_core::ExecCtx exec_ctx;
- grpc_pollset_global_init();
-
- grpc_executor_set_threading(false);
- g_init_thread = gpr_thd_currentid();
+void grpc_set_default_iomgr_platform() {
+ grpc_custom_iomgr_init(&grpc_uv_socket_vtable, &uv_resolver_vtable,
+ &uv_timer_vtable, &uv_pollset_vtable);
}
-void grpc_iomgr_platform_flush(void) {}
-void grpc_iomgr_platform_shutdown(void) { grpc_pollset_global_shutdown(); }
-
-#endif /* GRPC_UV */
+#endif
diff --git a/src/core/lib/iomgr/iomgr_windows.cc b/src/core/lib/iomgr/iomgr_windows.cc
index 8c4888ca97..cdef89cbf0 100644
--- a/src/core/lib/iomgr/iomgr_windows.cc
+++ b/src/core/lib/iomgr/iomgr_windows.cc
@@ -29,7 +29,18 @@
#include "src/core/lib/iomgr/iocp_windows.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/pollset_windows.h"
+#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/socket_windows.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/iomgr/timer.h"
+
+extern grpc_tcp_server_vtable grpc_windows_tcp_server_vtable;
+extern grpc_tcp_client_vtable grpc_windows_tcp_client_vtable;
+extern grpc_timer_vtable grpc_generic_timer_vtable;
+extern grpc_pollset_vtable grpc_windows_pollset_vtable;
+extern grpc_pollset_set_vtable grpc_windows_pollset_set_vtable;
+extern grpc_address_resolver_vtable grpc_windows_resolver_vtable;
/* Windows' io manager is going to be fully designed using IO completion
ports. All of what we're doing here is basically make sure that
@@ -46,18 +57,31 @@ static void winsock_shutdown(void) {
GPR_ASSERT(status == 0);
}
-void grpc_iomgr_platform_init(void) {
+static void iomgr_platform_init(void) {
winsock_init();
grpc_iocp_init();
grpc_pollset_global_init();
}
-void grpc_iomgr_platform_flush(void) { grpc_iocp_flush(); }
+static void iomgr_platform_flush(void) { grpc_iocp_flush(); }
-void grpc_iomgr_platform_shutdown(void) {
+static void iomgr_platform_shutdown(void) {
grpc_pollset_global_shutdown();
grpc_iocp_shutdown();
winsock_shutdown();
}
+static grpc_iomgr_platform_vtable vtable = {
+ iomgr_platform_init, iomgr_platform_flush, iomgr_platform_shutdown};
+
+void grpc_set_default_iomgr_platform() {
+ grpc_set_tcp_client_impl(&grpc_windows_tcp_client_vtable);
+ grpc_set_tcp_server_impl(&grpc_windows_tcp_server_vtable);
+ grpc_set_timer_impl(&grpc_generic_timer_vtable);
+ grpc_set_pollset_vtable(&grpc_windows_pollset_vtable);
+ grpc_set_pollset_set_vtable(&grpc_windows_pollset_set_vtable);
+ grpc_set_resolver_impl(&grpc_windows_resolver_vtable);
+ grpc_set_iomgr_platform_vtable(&vtable);
+}
+
#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/pollset.cc b/src/core/lib/iomgr/pollset.cc
new file mode 100644
index 0000000000..ebfef1dbc7
--- /dev/null
+++ b/src/core/lib/iomgr/pollset.cc
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/pollset.h"
+
+grpc_pollset_vtable* grpc_pollset_impl;
+
+void grpc_set_pollset_vtable(grpc_pollset_vtable* vtable) {
+ grpc_pollset_impl = vtable;
+}
+
+void grpc_pollset_global_init() { grpc_pollset_impl->global_init(); }
+
+void grpc_pollset_global_shutdown() { grpc_pollset_impl->global_shutdown(); }
+
+void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+ grpc_pollset_impl->init(pollset, mu);
+}
+
+void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+ grpc_pollset_impl->shutdown(pollset, closure);
+}
+
+void grpc_pollset_destroy(grpc_pollset* pollset) {
+ grpc_pollset_impl->destroy(pollset);
+}
+
+grpc_error* grpc_pollset_work(grpc_pollset* pollset,
+ grpc_pollset_worker** worker,
+ grpc_millis deadline) {
+ return grpc_pollset_impl->work(pollset, worker, deadline);
+}
+
+grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
+ grpc_pollset_worker* specific_worker) {
+ return grpc_pollset_impl->kick(pollset, specific_worker);
+}
+
+size_t grpc_pollset_size(void) { return grpc_pollset_impl->pollset_size(); }
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
index 9cc3e4c7fa..28472b360d 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -38,6 +38,24 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount;
typedef struct grpc_pollset grpc_pollset;
typedef struct grpc_pollset_worker grpc_pollset_worker;
+typedef struct grpc_pollset_vtable {
+ void (*global_init)(void);
+ void (*global_shutdown)(void);
+ void (*init)(grpc_pollset* pollset, gpr_mu** mu);
+ void (*shutdown)(grpc_pollset* pollset, grpc_closure* closure);
+ void (*destroy)(grpc_pollset* pollset);
+ grpc_error* (*work)(grpc_pollset* pollset, grpc_pollset_worker** worker,
+ grpc_millis deadline);
+ grpc_error* (*kick)(grpc_pollset* pollset,
+ grpc_pollset_worker* specific_worker);
+ size_t (*pollset_size)(void);
+} grpc_pollset_vtable;
+
+void grpc_set_pollset_vtable(grpc_pollset_vtable* vtable);
+
+void grpc_pollset_global_init(void);
+void grpc_pollset_global_shutdown(void);
+
size_t grpc_pollset_size(void);
/* Initialize a pollset: assumes *pollset contains all zeros */
void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu);
diff --git a/src/core/lib/iomgr/pollset_custom.cc b/src/core/lib/iomgr/pollset_custom.cc
new file mode 100644
index 0000000000..04bd104055
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_custom.cc
@@ -0,0 +1,106 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
+#include "src/core/lib/iomgr/timer.h"
+
+#include "src/core/lib/debug/trace.h"
+
+static grpc_custom_poller_vtable* poller_vtable;
+
+struct grpc_pollset {
+ gpr_mu mu;
+};
+
+static size_t pollset_size() { return sizeof(grpc_pollset); }
+
+static void pollset_global_init() { poller_vtable->init(); }
+
+static void pollset_global_shutdown() { poller_vtable->shutdown(); }
+
+static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ gpr_mu_init(&pollset->mu);
+ *mu = &pollset->mu;
+}
+
+static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
+}
+
+static void pollset_destroy(grpc_pollset* pollset) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ gpr_mu_destroy(&pollset->mu);
+}
+
+static grpc_error* pollset_work(grpc_pollset* pollset,
+ grpc_pollset_worker** worker_hdl,
+ grpc_millis deadline) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ gpr_mu_unlock(&pollset->mu);
+ grpc_millis now = grpc_core::ExecCtx::Get()->Now();
+ size_t timeout = 0;
+ if (deadline > now) {
+ timeout = deadline - now;
+ }
+ // We yield here because the poll() call might yield
+ // control back to the application
+ grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get();
+ grpc_core::ExecCtx::Set(nullptr);
+ poller_vtable->poll(timeout);
+ grpc_core::ExecCtx::Set(curr);
+ grpc_core::ExecCtx::Get()->InvalidateNow();
+ if (grpc_core::ExecCtx::Get()->HasWork()) {
+ grpc_core::ExecCtx::Get()->Flush();
+ }
+ gpr_mu_lock(&pollset->mu);
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error* pollset_kick(grpc_pollset* pollset,
+ grpc_pollset_worker* specific_worker) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ poller_vtable->kick();
+ return GRPC_ERROR_NONE;
+}
+
+grpc_pollset_vtable custom_pollset_vtable = {
+ pollset_global_init, pollset_global_shutdown,
+ pollset_init, pollset_shutdown,
+ pollset_destroy, pollset_work,
+ pollset_kick, pollset_size};
+
+void grpc_custom_pollset_init(grpc_custom_poller_vtable* vtable) {
+ poller_vtable = vtable;
+ grpc_set_pollset_vtable(&custom_pollset_vtable);
+}
diff --git a/src/core/lib/iomgr/pollset_custom.h b/src/core/lib/iomgr/pollset_custom.h
new file mode 100644
index 0000000000..9e2027f7f4
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_custom.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+
+typedef struct grpc_custom_poller_vtable {
+ void (*init)();
+ void (*poll)(size_t timeout_ms);
+ void (*kick)();
+ void (*shutdown)();
+} grpc_custom_poller_vtable;
+
+void grpc_custom_pollset_init(grpc_custom_poller_vtable* vtable);
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_CUSTOM_H */
diff --git a/src/core/lib/iomgr/pollset_set_uv.cc b/src/core/lib/iomgr/pollset_set.cc
index 50814c1f0a..42a647a737 100644
--- a/src/core/lib/iomgr/pollset_set_uv.cc
+++ b/src/core/lib/iomgr/pollset_set.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2016 gRPC authors.
+ * Copyright 2018 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,28 +18,38 @@
#include <grpc/support/port_platform.h>
-#include "src/core/lib/iomgr/port.h"
+#include "src/core/lib/iomgr/pollset_set.h"
-#ifdef GRPC_UV
+grpc_pollset_set_vtable* grpc_pollset_set_impl;
-#include "src/core/lib/iomgr/pollset_set.h"
+void grpc_set_pollset_set_vtable(grpc_pollset_set_vtable* vtable) {
+ grpc_pollset_set_impl = vtable;
+}
-grpc_pollset_set* grpc_pollset_set_create(void) {
- return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
+grpc_pollset_set* grpc_pollset_set_create() {
+ return grpc_pollset_set_impl->create();
}
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}
+void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {
+ grpc_pollset_set_impl->destroy(pollset_set);
+}
void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
- grpc_pollset* pollset) {}
+ grpc_pollset* pollset) {
+ grpc_pollset_set_impl->add_pollset(pollset_set, pollset);
+}
void grpc_pollset_set_del_pollset(grpc_pollset_set* pollset_set,
- grpc_pollset* pollset) {}
+ grpc_pollset* pollset) {
+ grpc_pollset_set_impl->del_pollset(pollset_set, pollset);
+}
void grpc_pollset_set_add_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {}
+ grpc_pollset_set* item) {
+ grpc_pollset_set_impl->add_pollset_set(bag, item);
+}
void grpc_pollset_set_del_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {}
-
-#endif /* GRPC_UV */
+ grpc_pollset_set* item) {
+ grpc_pollset_set_impl->del_pollset_set(bag, item);
+}
diff --git a/src/core/lib/iomgr/pollset_set.h b/src/core/lib/iomgr/pollset_set.h
index 18f30aa94e..d3355b8ff8 100644
--- a/src/core/lib/iomgr/pollset_set.h
+++ b/src/core/lib/iomgr/pollset_set.h
@@ -30,6 +30,17 @@
typedef struct grpc_pollset_set grpc_pollset_set;
+typedef struct grpc_pollset_set_vtable {
+ grpc_pollset_set* (*create)(void);
+ void (*destroy)(grpc_pollset_set* pollset_set);
+ void (*add_pollset)(grpc_pollset_set* pollset_set, grpc_pollset* pollset);
+ void (*del_pollset)(grpc_pollset_set* pollset_set, grpc_pollset* pollset);
+ void (*add_pollset_set)(grpc_pollset_set* bag, grpc_pollset_set* item);
+ void (*del_pollset_set)(grpc_pollset_set* bag, grpc_pollset_set* item);
+} grpc_pollset_set_vtable;
+
+void grpc_set_pollset_set_vtable(grpc_pollset_set_vtable* vtable);
+
grpc_pollset_set* grpc_pollset_set_create(void);
void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set);
void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
diff --git a/src/core/lib/iomgr/pollset_set_custom.cc b/src/core/lib/iomgr/pollset_set_custom.cc
new file mode 100644
index 0000000000..b1ee66020d
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set_custom.cc
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include "src/core/lib/iomgr/pollset_set.h"
+
+grpc_pollset_set* pollset_set_create(void) {
+ return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
+}
+
+void pollset_set_destroy(grpc_pollset_set* pollset_set) {}
+
+void pollset_set_add_pollset(grpc_pollset_set* pollset_set,
+ grpc_pollset* pollset) {}
+
+void pollset_set_del_pollset(grpc_pollset_set* pollset_set,
+ grpc_pollset* pollset) {}
+
+void pollset_set_add_pollset_set(grpc_pollset_set* bag,
+ grpc_pollset_set* item) {}
+
+void pollset_set_del_pollset_set(grpc_pollset_set* bag,
+ grpc_pollset_set* item) {}
+
+static grpc_pollset_set_vtable vtable = {
+ pollset_set_create, pollset_set_destroy,
+ pollset_set_add_pollset, pollset_set_del_pollset,
+ pollset_set_add_pollset_set, pollset_set_del_pollset_set};
+
+void grpc_custom_pollset_set_init() { grpc_set_pollset_set_vtable(&vtable); }
diff --git a/src/core/lib/iomgr/pollset_set_custom.h b/src/core/lib/iomgr/pollset_set_custom.h
new file mode 100644
index 0000000000..80e19a1fef
--- /dev/null
+++ b/src/core/lib/iomgr/pollset_set_custom.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_POLLSET_SET_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_POLLSET_SET_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+void grpc_custom_pollset_set_init();
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_SET_CUSTOM_H */
diff --git a/src/core/lib/iomgr/pollset_set_windows.cc b/src/core/lib/iomgr/pollset_set_windows.cc
index ff3f6a944e..bb9e7f5d28 100644
--- a/src/core/lib/iomgr/pollset_set_windows.cc
+++ b/src/core/lib/iomgr/pollset_set_windows.cc
@@ -25,22 +25,27 @@
#include "src/core/lib/iomgr/pollset_set_windows.h"
-grpc_pollset_set* grpc_pollset_set_create(void) {
+static grpc_pollset_set* pollset_set_create(void) {
return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
}
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}
+static void pollset_set_destroy(grpc_pollset_set* pollset_set) {}
-void grpc_pollset_set_add_pollset(grpc_pollset_set* pollset_set,
- grpc_pollset* pollset) {}
+static void pollset_set_add_pollset(grpc_pollset_set* pollset_set,
+ grpc_pollset* pollset) {}
-void grpc_pollset_set_del_pollset(grpc_pollset_set* pollset_set,
- grpc_pollset* pollset) {}
+static void pollset_set_del_pollset(grpc_pollset_set* pollset_set,
+ grpc_pollset* pollset) {}
-void grpc_pollset_set_add_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {}
+static void pollset_set_add_pollset_set(grpc_pollset_set* bag,
+ grpc_pollset_set* item) {}
-void grpc_pollset_set_del_pollset_set(grpc_pollset_set* bag,
- grpc_pollset_set* item) {}
+static void pollset_set_del_pollset_set(grpc_pollset_set* bag,
+ grpc_pollset_set* item) {}
+
+grpc_pollset_set_vtable grpc_windows_pollset_set_vtable = {
+ pollset_set_create, pollset_set_destroy,
+ pollset_set_add_pollset, pollset_set_del_pollset,
+ pollset_set_add_pollset_set, pollset_set_del_pollset_set};
#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/pollset_uv.cc b/src/core/lib/iomgr/pollset_uv.cc
index c6a2f43bf1..bade6eae6c 100644
--- a/src/core/lib/iomgr/pollset_uv.cc
+++ b/src/core/lib/iomgr/pollset_uv.cc
@@ -22,137 +22,72 @@
#ifdef GRPC_UV
-#include <uv.h>
-
-#include <string.h>
-
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/pollset.h"
-#include "src/core/lib/iomgr/pollset_uv.h"
+#include "src/core/lib/iomgr/pollset_custom.h"
-#include "src/core/lib/debug/trace.h"
-
-grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount");
-
-struct grpc_pollset {
- uv_timer_t* timer;
- int shutting_down;
-};
+#include <uv.h>
/* Indicates that grpc_pollset_work should run an iteration of the UV loop
before running callbacks. This defaults to 1, and should be disabled if
grpc_pollset_work will be called within the callstack of uv_run */
-int grpc_pollset_work_run_loop;
-
-gpr_mu grpc_polling_mu;
+int grpc_pollset_work_run_loop = 1;
-/* This is used solely to kick the uv loop, by setting a callback to be run
- immediately in the next loop iteration.
- Note: In the future, if there is a bug that involves missing wakeups in the
- future, try adding a uv_async_t to kick the loop differently */
-uv_timer_t* dummy_uv_handle;
+static bool g_kicked = false;
-size_t grpc_pollset_size() { return sizeof(grpc_pollset); }
+typedef struct uv_poller_handle {
+ uv_timer_t poll_timer;
+ uv_timer_t kick_timer;
+ int refs;
+} uv_poller_handle;
-void dummy_timer_cb(uv_timer_t* handle) {}
+static uv_poller_handle* g_handle;
-void dummy_handle_close_cb(uv_handle_t* handle) { gpr_free(handle); }
-
-void grpc_pollset_global_init(void) {
- gpr_mu_init(&grpc_polling_mu);
- dummy_uv_handle = (uv_timer_t*)gpr_malloc(sizeof(uv_timer_t));
- uv_timer_init(uv_default_loop(), dummy_uv_handle);
- grpc_pollset_work_run_loop = 1;
-}
-
-void grpc_pollset_global_shutdown(void) {
- GRPC_UV_ASSERT_SAME_THREAD();
- gpr_mu_destroy(&grpc_polling_mu);
- uv_close((uv_handle_t*)dummy_uv_handle, dummy_handle_close_cb);
+static void init() {
+ g_handle = (uv_poller_handle*)gpr_malloc(sizeof(uv_poller_handle));
+ g_handle->refs = 2;
+ uv_timer_init(uv_default_loop(), &g_handle->poll_timer);
+ uv_timer_init(uv_default_loop(), &g_handle->kick_timer);
}
-static void timer_run_cb(uv_timer_t* timer) {}
+static void empty_timer_cb(uv_timer_t* handle) {}
-static void timer_close_cb(uv_handle_t* handle) {
- handle->data = (void*)1;
- gpr_free(handle);
-}
+static void kick_timer_cb(uv_timer_t* handle) { g_kicked = false; }
-void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
- GRPC_UV_ASSERT_SAME_THREAD();
- *mu = &grpc_polling_mu;
- pollset->timer = (uv_timer_t*)gpr_malloc(sizeof(uv_timer_t));
- uv_timer_init(uv_default_loop(), pollset->timer);
- pollset->shutting_down = 0;
+static void run_loop(size_t timeout) {
+ if (grpc_pollset_work_run_loop) {
+ if (timeout == 0) {
+ uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ } else {
+ uv_timer_start(&g_handle->poll_timer, empty_timer_cb, timeout, 0);
+ uv_run(uv_default_loop(), UV_RUN_ONCE);
+ uv_timer_stop(&g_handle->poll_timer);
+ }
+ }
}
-void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
- GPR_ASSERT(!pollset->shutting_down);
- GRPC_UV_ASSERT_SAME_THREAD();
- pollset->shutting_down = 1;
- if (grpc_pollset_work_run_loop) {
- // Drain any pending UV callbacks without blocking
- uv_run(uv_default_loop(), UV_RUN_NOWAIT);
- } else {
- // kick the loop once
- uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0);
+static void kick() {
+ if (!g_kicked) {
+ g_kicked = true;
+ uv_timer_start(&g_handle->kick_timer, kick_timer_cb, 0, 0);
}
- GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
}
-void grpc_pollset_destroy(grpc_pollset* pollset) {
- GRPC_UV_ASSERT_SAME_THREAD();
- uv_close((uv_handle_t*)pollset->timer, timer_close_cb);
- // timer.data is a boolean indicating that the timer has finished closing
- pollset->timer->data = (void*)0;
- if (grpc_pollset_work_run_loop) {
- while (!pollset->timer->data) {
- uv_run(uv_default_loop(), UV_RUN_NOWAIT);
- }
+static void close_timer_cb(uv_handle_t* handle) {
+ g_handle->refs--;
+ if (g_handle->refs == 0) {
+ gpr_free(g_handle);
}
}
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
- grpc_pollset_worker** worker_hdl,
- grpc_millis deadline) {
- uint64_t timeout;
- GRPC_UV_ASSERT_SAME_THREAD();
- gpr_mu_unlock(&grpc_polling_mu);
+static void shutdown() {
+ uv_close((uv_handle_t*)&g_handle->poll_timer, close_timer_cb);
+ uv_close((uv_handle_t*)&g_handle->kick_timer, close_timer_cb);
if (grpc_pollset_work_run_loop) {
- grpc_millis now = grpc_core::ExecCtx::Get()->Now();
- if (deadline >= now) {
- timeout = deadline - now;
- } else {
- timeout = 0;
- }
- /* We special-case timeout=0 so that we don't bother with the timer when
- the loop won't block anyway */
- if (timeout > 0) {
- uv_timer_start(pollset->timer, timer_run_cb, timeout, 0);
- /* Run until there is some I/O activity or the timer triggers. It doesn't
- matter which happens */
- uv_run(uv_default_loop(), UV_RUN_ONCE);
- uv_timer_stop(pollset->timer);
- } else {
- uv_run(uv_default_loop(), UV_RUN_NOWAIT);
- }
- }
- if (!grpc_closure_list_empty(*grpc_core::ExecCtx::Get()->closure_list())) {
- grpc_core::ExecCtx::Get()->Flush();
+ GPR_ASSERT(uv_run(uv_default_loop(), UV_RUN_DEFAULT) == 0);
}
- gpr_mu_lock(&grpc_polling_mu);
- return GRPC_ERROR_NONE;
}
-grpc_error* grpc_pollset_kick(grpc_pollset* pollset,
- grpc_pollset_worker* specific_worker) {
- GRPC_UV_ASSERT_SAME_THREAD();
- uv_timer_start(dummy_uv_handle, dummy_timer_cb, 0, 0);
- return GRPC_ERROR_NONE;
-}
+grpc_custom_poller_vtable uv_pollset_vtable = {init, run_loop, kick, shutdown};
#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/pollset_uv.h b/src/core/lib/iomgr/pollset_uv.h
index 566c110ca6..de82bcc1d3 100644
--- a/src/core/lib/iomgr/pollset_uv.h
+++ b/src/core/lib/iomgr/pollset_uv.h
@@ -21,7 +21,12 @@
extern int grpc_pollset_work_run_loop;
-void grpc_pollset_global_init(void);
-void grpc_pollset_global_shutdown(void);
+typedef struct grpc_custom_poller_vtable {
+ void (*init)(void);
+ void (*run_loop)(int blocking);
+} grpc_custom_poller_vtable;
+
+void grpc_custom_pollset_global_init(grpc_custom_poller_vtable* vtable);
+void grpc_custom_pollset_global_shutdown(void);
#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_UV_H */
diff --git a/src/core/lib/iomgr/pollset_windows.cc b/src/core/lib/iomgr/pollset_windows.cc
index 62ab760875..e9a808d8ad 100644
--- a/src/core/lib/iomgr/pollset_windows.cc
+++ b/src/core/lib/iomgr/pollset_windows.cc
@@ -24,7 +24,7 @@
#include <grpc/support/log.h>
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/iocp_windows.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/pollset.h"
@@ -38,7 +38,7 @@ gpr_mu grpc_polling_mu;
static grpc_pollset_worker* g_active_poller;
static grpc_pollset_worker g_global_root_worker;
-void grpc_pollset_global_init(void) {
+static void pollset_global_init(void) {
gpr_mu_init(&grpc_polling_mu);
g_active_poller = NULL;
g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
@@ -46,7 +46,7 @@ void grpc_pollset_global_init(void) {
&g_global_root_worker;
}
-void grpc_pollset_global_shutdown(void) { gpr_mu_destroy(&grpc_polling_mu); }
+static void pollset_global_shutdown(void) { gpr_mu_destroy(&grpc_polling_mu); }
static void remove_worker(grpc_pollset_worker* worker,
grpc_pollset_worker_link_type type) {
@@ -80,21 +80,21 @@ static void push_front_worker(grpc_pollset_worker* root,
worker->links[type].next->links[type].prev = worker;
}
-size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
+static size_t pollset_size(void) { return sizeof(grpc_pollset); }
/* There isn't really any such thing as a pollset under Windows, due to the
nature of the IO completion ports. We're still going to provide a minimal
set of features for the sake of the rest of grpc. But grpc_pollset_work
won't actually do any polling, and return as quickly as possible. */
-void grpc_pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
+static void pollset_init(grpc_pollset* pollset, gpr_mu** mu) {
*mu = &grpc_polling_mu;
pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
&pollset->root_worker;
}
-void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
+static void pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
pollset->shutting_down = 1;
grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
if (!pollset->is_iocp_worker) {
@@ -104,11 +104,11 @@ void grpc_pollset_shutdown(grpc_pollset* pollset, grpc_closure* closure) {
}
}
-void grpc_pollset_destroy(grpc_pollset* pollset) {}
+static void pollset_destroy(grpc_pollset* pollset) {}
-grpc_error* grpc_pollset_work(grpc_pollset* pollset,
- grpc_pollset_worker** worker_hdl,
- grpc_millis deadline) {
+static grpc_error* pollset_work(grpc_pollset* pollset,
+ grpc_pollset_worker** worker_hdl,
+ grpc_millis deadline) {
grpc_pollset_worker worker;
if (worker_hdl) *worker_hdl = &worker;
@@ -182,8 +182,8 @@ done:
return GRPC_ERROR_NONE;
}
-grpc_error* grpc_pollset_kick(grpc_pollset* p,
- grpc_pollset_worker* specific_worker) {
+static grpc_error* pollset_kick(grpc_pollset* p,
+ grpc_pollset_worker* specific_worker) {
if (specific_worker != NULL) {
if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
for (specific_worker =
@@ -220,4 +220,10 @@ grpc_error* grpc_pollset_kick(grpc_pollset* p,
return GRPC_ERROR_NONE;
}
+grpc_pollset_vtable grpc_windows_pollset_vtable = {
+ pollset_global_init, pollset_global_shutdown,
+ pollset_init, pollset_shutdown,
+ pollset_destroy, pollset_work,
+ pollset_kick, pollset_size};
+
#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index 25090898ed..c1dcc52618 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -21,8 +21,11 @@
#ifndef GRPC_CORE_LIB_IOMGR_PORT_H
#define GRPC_CORE_LIB_IOMGR_PORT_H
-#if defined(GRPC_UV)
-// Do nothing
+#ifdef GRPC_UV
+#define GRPC_CUSTOM_SOCKET
+#endif
+#if defined(GRPC_CUSTOM_SOCKET)
+// Do Nothing
#elif defined(GPR_MANYLINUX1)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_HAVE_IFADDRS 1
@@ -33,13 +36,10 @@
#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
#define GRPC_LINUX_EPOLL 1
#elif defined(GPR_WINDOWS)
-#define GRPC_TIMER_USE_GENERIC 1
#define GRPC_WINSOCK_SOCKET 1
#define GRPC_WINDOWS_SOCKETUTILS 1
#elif defined(GPR_ANDROID)
@@ -49,10 +49,8 @@
#define GRPC_HAVE_UNIX_SOCKET 1
#define GRPC_LINUX_EVENTFD 1
#define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_LINUX)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_HAVE_IFADDRS 1
@@ -64,9 +62,7 @@
#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_HOST_NAME_MAX 1
#define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
#ifdef __GLIBC_PREREQ
#if __GLIBC_PREREQ(2, 4)
#define GRPC_LINUX_EPOLL 1
@@ -100,11 +96,9 @@
#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_SYSCONF 1
#define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_FREEBSD)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_HAVE_IFADDRS 1
@@ -114,36 +108,31 @@
#define GRPC_POSIX_FORK 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_OPENBSD)
#define GRPC_HAVE_IFADDRS 1
#define GRPC_HAVE_IPV6_RECVPKTINFO 1
#define GRPC_HAVE_UNIX_SOCKET 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
#elif defined(GPR_NACL)
#define GRPC_HAVE_ARPA_NAMESER 1
#define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
#define GRPC_POSIX_SOCKET 1
-#define GRPC_POSIX_SOCKETADDR 1
#define GRPC_POSIX_SOCKETUTILS 1
#define GRPC_POSIX_WAKEUP_FD 1
-#define GRPC_TIMER_USE_GENERIC 1
#elif !defined(GPR_NO_AUTODETECT_PLATFORM)
#error "Platform not recognized"
#endif
#if defined(GRPC_POSIX_SOCKET) + defined(GRPC_WINSOCK_SOCKET) + \
- defined(GRPC_CUSTOM_SOCKET) + defined(GRPC_UV) != \
+ defined(GRPC_CUSTOM_SOCKET) != \
1
-#error Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET
+#error \
+ "Must define exactly one of GRPC_POSIX_SOCKET, GRPC_WINSOCK_SOCKET, GRPC_CUSTOM_SOCKET"
#endif
#if defined(GRPC_POSIX_HOST_NAME_MAX) && defined(GRPC_POSIX_SYSCONF)
diff --git a/src/core/lib/iomgr/resolve_address.cc b/src/core/lib/iomgr/resolve_address.cc
new file mode 100644
index 0000000000..f2a4676369
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address.cc
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/alloc.h>
+#include "src/core/lib/iomgr/resolve_address.h"
+
+grpc_address_resolver_vtable* grpc_resolve_address_impl;
+
+void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable) {
+ grpc_resolve_address_impl = vtable;
+}
+
+void grpc_resolve_address(const char* addr, const char* default_port,
+ grpc_pollset_set* interested_parties,
+ grpc_closure* on_done,
+ grpc_resolved_addresses** addresses) {
+ grpc_resolve_address_impl->resolve_address(
+ addr, default_port, interested_parties, on_done, addresses);
+}
+
+void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
+ if (addrs != nullptr) {
+ gpr_free(addrs->addrs);
+ }
+ gpr_free(addrs);
+}
+
+grpc_error* grpc_blocking_resolve_address(const char* name,
+ const char* default_port,
+ grpc_resolved_addresses** addresses) {
+ return grpc_resolve_address_impl->blocking_resolve_address(name, default_port,
+ addresses);
+}
diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h
index 10a7822654..7da5caaa8e 100644
--- a/src/core/lib/iomgr/resolve_address.h
+++ b/src/core/lib/iomgr/resolve_address.h
@@ -37,20 +37,33 @@ typedef struct {
grpc_resolved_address* addrs;
} grpc_resolved_addresses;
+typedef struct grpc_address_resolver_vtable {
+ void (*resolve_address)(const char* addr, const char* default_port,
+ grpc_pollset_set* interested_parties,
+ grpc_closure* on_done,
+ grpc_resolved_addresses** addresses);
+ grpc_error* (*blocking_resolve_address)(const char* name,
+ const char* default_port,
+ grpc_resolved_addresses** addresses);
+} grpc_address_resolver_vtable;
+
+void grpc_set_resolver_impl(grpc_address_resolver_vtable* vtable);
+
/* Asynchronously resolve addr. Use default_port if a port isn't designated
in addr, otherwise use the port in addr. */
/* TODO(ctiller): add a timeout here */
-extern void (*grpc_resolve_address)(const char* addr, const char* default_port,
- grpc_pollset_set* interested_parties,
- grpc_closure* on_done,
- grpc_resolved_addresses** addresses);
+void grpc_resolve_address(const char* addr, const char* default_port,
+ grpc_pollset_set* interested_parties,
+ grpc_closure* on_done,
+ grpc_resolved_addresses** addresses);
+
/* Destroy resolved addresses */
void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addresses);
-/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
+/* Resolve addr in a blocking fashion. On success,
result must be freed with grpc_resolved_addresses_destroy. */
-extern grpc_error* (*grpc_blocking_resolve_address)(
- const char* name, const char* default_port,
- grpc_resolved_addresses** addresses);
+grpc_error* grpc_blocking_resolve_address(const char* name,
+ const char* default_port,
+ grpc_resolved_addresses** addresses);
#endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/lib/iomgr/resolve_address_custom.cc b/src/core/lib/iomgr/resolve_address_custom.cc
new file mode 100644
index 0000000000..9cf7817f66
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address_custom.cc
@@ -0,0 +1,187 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include <grpc/support/log.h>
+#include "src/core/lib/gpr/host_port.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+
+#include <string.h>
+
+typedef struct grpc_custom_resolver {
+ grpc_closure* on_done;
+ grpc_resolved_addresses** addresses;
+ char* host;
+ char* port;
+} grpc_custom_resolver;
+
+static grpc_custom_resolver_vtable* resolve_address_vtable = nullptr;
+
+static int retry_named_port_failure(grpc_custom_resolver* r,
+ grpc_resolved_addresses** res) {
+ // This loop is copied from resolve_address_posix.c
+ const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
+ for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
+ if (strcmp(r->port, svc[i][0]) == 0) {
+ gpr_free(r->port);
+ r->port = gpr_strdup(svc[i][1]);
+ if (res) {
+ grpc_error* error =
+ resolve_address_vtable->resolve(r->host, r->port, res);
+ if (error != GRPC_ERROR_NONE) {
+ GRPC_ERROR_UNREF(error);
+ return 0;
+ }
+ } else {
+ resolve_address_vtable->resolve_async(r, r->host, r->port);
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void grpc_custom_resolve_callback(grpc_custom_resolver* r,
+ grpc_resolved_addresses* result,
+ grpc_error* error) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ grpc_core::ExecCtx exec_ctx;
+ if (error == GRPC_ERROR_NONE) {
+ *r->addresses = result;
+ } else if (retry_named_port_failure(r, nullptr)) {
+ return;
+ }
+ if (r->on_done) {
+ GRPC_CLOSURE_SCHED(r->on_done, error);
+ }
+ gpr_free(r->host);
+ gpr_free(r->port);
+ gpr_free(r);
+}
+
+static grpc_error* try_split_host_port(const char* name,
+ const char* default_port, char** host,
+ char** port) {
+ /* parse name, splitting it into host and port parts */
+ grpc_error* error;
+ gpr_split_host_port(name, host, port);
+ if (*host == nullptr) {
+ char* msg;
+ gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
+ error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+ gpr_free(msg);
+ return error;
+ }
+ if (*port == nullptr) {
+ // TODO(murgatroid99): add tests for this case
+ if (default_port == nullptr) {
+ char* msg;
+ gpr_asprintf(&msg, "no port in name '%s'", name);
+ error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
+ gpr_free(msg);
+ return error;
+ }
+ *port = gpr_strdup(default_port);
+ }
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error* blocking_resolve_address_impl(
+ const char* name, const char* default_port,
+ grpc_resolved_addresses** addresses) {
+ char* host;
+ char* port;
+ grpc_error* err;
+
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+
+ err = try_split_host_port(name, default_port, &host, &port);
+ if (err != GRPC_ERROR_NONE) {
+ gpr_free(host);
+ gpr_free(port);
+ return err;
+ }
+
+ /* Call getaddrinfo */
+ grpc_custom_resolver resolver;
+ resolver.host = host;
+ resolver.port = port;
+
+ grpc_resolved_addresses* addrs;
+ grpc_core::ExecCtx* curr = grpc_core::ExecCtx::Get();
+ grpc_core::ExecCtx::Set(nullptr);
+ err = resolve_address_vtable->resolve(host, port, &addrs);
+ if (err != GRPC_ERROR_NONE) {
+ if (retry_named_port_failure(&resolver, &addrs)) {
+ GRPC_ERROR_UNREF(err);
+ err = GRPC_ERROR_NONE;
+ }
+ }
+ grpc_core::ExecCtx::Set(curr);
+ if (err == GRPC_ERROR_NONE) {
+ *addresses = addrs;
+ }
+ gpr_free(resolver.host);
+ gpr_free(resolver.port);
+ return err;
+}
+
+static void resolve_address_impl(const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties,
+ grpc_closure* on_done,
+ grpc_resolved_addresses** addrs) {
+ grpc_custom_resolver* r = nullptr;
+ char* host = nullptr;
+ char* port = nullptr;
+ grpc_error* err;
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ err = try_split_host_port(name, default_port, &host, &port);
+ if (err != GRPC_ERROR_NONE) {
+ GRPC_CLOSURE_SCHED(on_done, err);
+ gpr_free(host);
+ gpr_free(port);
+ return;
+ }
+ r = (grpc_custom_resolver*)gpr_malloc(sizeof(grpc_custom_resolver));
+ r->on_done = on_done;
+ r->addresses = addrs;
+ r->host = host;
+ r->port = port;
+
+ /* Call getaddrinfo */
+ resolve_address_vtable->resolve_async(r, r->host, r->port);
+}
+
+static grpc_address_resolver_vtable custom_resolver_vtable = {
+ resolve_address_impl, blocking_resolve_address_impl};
+
+void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl) {
+ resolve_address_vtable = impl;
+ grpc_set_resolver_impl(&custom_resolver_vtable);
+}
diff --git a/src/core/lib/iomgr/resolve_address_custom.h b/src/core/lib/iomgr/resolve_address_custom.h
new file mode 100644
index 0000000000..e0c6714087
--- /dev/null
+++ b/src/core/lib/iomgr/resolve_address_custom.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+typedef struct grpc_custom_resolver grpc_custom_resolver;
+
+typedef struct grpc_custom_resolver_vtable {
+ grpc_error* (*resolve)(char* host, char* port, grpc_resolved_addresses** res);
+ void (*resolve_async)(grpc_custom_resolver* resolver, char* host, char* port);
+} grpc_custom_resolver_vtable;
+
+void grpc_custom_resolve_callback(grpc_custom_resolver* resolver,
+ grpc_resolved_addresses* result,
+ grpc_error* error);
+
+/* Internal APIs */
+void grpc_custom_resolver_init(grpc_custom_resolver_vtable* impl);
+
+#endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_CUSTOM_H */
diff --git a/src/core/lib/iomgr/resolve_address_posix.cc b/src/core/lib/iomgr/resolve_address_posix.cc
index 9307f19bcf..a82075542f 100644
--- a/src/core/lib/iomgr/resolve_address_posix.cc
+++ b/src/core/lib/iomgr/resolve_address_posix.cc
@@ -35,14 +35,14 @@
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/block_annotate.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
-static grpc_error* blocking_resolve_address_impl(
+static grpc_error* posix_blocking_resolve_address(
const char* name, const char* default_port,
grpc_resolved_addresses** addresses) {
grpc_core::ExecCtx exec_ctx;
@@ -141,10 +141,6 @@ done:
return err;
}
-grpc_error* (*grpc_blocking_resolve_address)(
- const char* name, const char* default_port,
- grpc_resolved_addresses** addresses) = blocking_resolve_address_impl;
-
typedef struct {
char* name;
char* default_port;
@@ -165,17 +161,10 @@ static void do_request_thread(void* rp, grpc_error* error) {
gpr_free(r);
}
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
- if (addrs != nullptr) {
- gpr_free(addrs->addrs);
- }
- gpr_free(addrs);
-}
-
-static void resolve_address_impl(const char* name, const char* default_port,
- grpc_pollset_set* interested_parties,
- grpc_closure* on_done,
- grpc_resolved_addresses** addrs) {
+static void posix_resolve_address(const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties,
+ grpc_closure* on_done,
+ grpc_resolved_addresses** addrs) {
request* r = static_cast<request*>(gpr_malloc(sizeof(request)));
GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r,
grpc_executor_scheduler(GRPC_EXECUTOR_SHORT));
@@ -186,9 +175,6 @@ static void resolve_address_impl(const char* name, const char* default_port,
GRPC_CLOSURE_SCHED(&r->request_closure, GRPC_ERROR_NONE);
}
-void (*grpc_resolve_address)(
- const char* name, const char* default_port,
- grpc_pollset_set* interested_parties, grpc_closure* on_done,
- grpc_resolved_addresses** addrs) = resolve_address_impl;
-
+grpc_address_resolver_vtable grpc_posix_resolver_vtable = {
+ posix_resolve_address, posix_blocking_resolve_address};
#endif
diff --git a/src/core/lib/iomgr/resolve_address_uv.cc b/src/core/lib/iomgr/resolve_address_uv.cc
deleted file mode 100644
index 4d8ea596f3..0000000000
--- a/src/core/lib/iomgr/resolve_address_uv.cc
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/iomgr/port.h"
-#ifdef GRPC_UV
-
-#include <uv.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-
-#include "src/core/lib/gpr/host_port.h"
-#include "src/core/lib/gpr/useful.h"
-#include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-
-#include <string.h>
-
-typedef struct request {
- grpc_closure* on_done;
- grpc_resolved_addresses** addresses;
- struct addrinfo* hints;
- char* host;
- char* port;
-} request;
-
-static int retry_named_port_failure(int status, request* r,
- uv_getaddrinfo_cb getaddrinfo_cb) {
- if (status != 0) {
- // This loop is copied from resolve_address_posix.c
- const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
- for (size_t i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
- if (strcmp(r->port, svc[i][0]) == 0) {
- int retry_status;
- uv_getaddrinfo_t* req =
- (uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t));
- req->data = r;
- r->port = gpr_strdup(svc[i][1]);
- retry_status = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_cb,
- r->host, r->port, r->hints);
- if (retry_status < 0 || getaddrinfo_cb == NULL) {
- // The callback will not be called
- gpr_free(req);
- }
- return retry_status;
- }
- }
- }
- /* If this function calls uv_getaddrinfo, it will return that function's
- return value. That function only returns numbers <=0, so we can safely
- return 1 to indicate that we never retried */
- return 1;
-}
-
-static grpc_error* handle_addrinfo_result(int status, struct addrinfo* result,
- grpc_resolved_addresses** addresses) {
- struct addrinfo* resp;
- size_t i;
- if (status != 0) {
- grpc_error* error;
- *addresses = NULL;
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed");
- error =
- grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- return error;
- }
- (*addresses) =
- (grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses));
- (*addresses)->naddrs = 0;
- for (resp = result; resp != NULL; resp = resp->ai_next) {
- (*addresses)->naddrs++;
- }
- (*addresses)->addrs = (grpc_resolved_address*)gpr_malloc(
- sizeof(grpc_resolved_address) * (*addresses)->naddrs);
- i = 0;
- for (resp = result; resp != NULL; resp = resp->ai_next) {
- memcpy(&(*addresses)->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
- (*addresses)->addrs[i].len = resp->ai_addrlen;
- i++;
- }
-
- {
- for (i = 0; i < (*addresses)->naddrs; i++) {
- char* buf;
- grpc_sockaddr_to_string(&buf, &(*addresses)->addrs[i], 0);
- gpr_free(buf);
- }
- }
- return GRPC_ERROR_NONE;
-}
-
-static void getaddrinfo_callback(uv_getaddrinfo_t* req, int status,
- struct addrinfo* res) {
- request* r = (request*)req->data;
- grpc_core::ExecCtx exec_ctx;
- grpc_error* error;
- int retry_status;
- char* port = r->port;
-
- gpr_free(req);
- retry_status = retry_named_port_failure(status, r, getaddrinfo_callback);
- if (retry_status == 0) {
- /* The request is being retried. It is using its own port string, so we free
- * the original one */
- gpr_free(port);
- return;
- }
- /* Either no retry was attempted, or the retry failed. Either way, the
- original error probably has more interesting information */
- error = handle_addrinfo_result(status, res, r->addresses);
- GRPC_CLOSURE_SCHED(r->on_done, error);
-
- gpr_free(r->hints);
- gpr_free(r->host);
- gpr_free(r->port);
- gpr_free(r);
- uv_freeaddrinfo(res);
-}
-
-static grpc_error* try_split_host_port(const char* name,
- const char* default_port, char** host,
- char** port) {
- /* parse name, splitting it into host and port parts */
- grpc_error* error;
- gpr_split_host_port(name, host, port);
- if (*host == NULL) {
- char* msg;
- gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
- error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
- gpr_free(msg);
- return error;
- }
- if (*port == NULL) {
- // TODO(murgatroid99): add tests for this case
- if (default_port == NULL) {
- char* msg;
- gpr_asprintf(&msg, "no port in name '%s'", name);
- error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
- gpr_free(msg);
- return error;
- }
- *port = gpr_strdup(default_port);
- }
- return GRPC_ERROR_NONE;
-}
-
-static grpc_error* blocking_resolve_address_impl(
- const char* name, const char* default_port,
- grpc_resolved_addresses** addresses) {
- char* host;
- char* port;
- struct addrinfo hints;
- uv_getaddrinfo_t req;
- int s;
- grpc_error* err;
- int retry_status;
- request r;
-
- GRPC_UV_ASSERT_SAME_THREAD();
-
- req.addrinfo = NULL;
-
- err = try_split_host_port(name, default_port, &host, &port);
- if (err != GRPC_ERROR_NONE) {
- goto done;
- }
-
- /* Call getaddrinfo */
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */
- hints.ai_socktype = SOCK_STREAM; /* stream socket */
- hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */
-
- s = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints);
- r.addresses = addresses;
- r.hints = &hints;
- r.host = host;
- r.port = port;
- retry_status = retry_named_port_failure(s, &r, NULL);
- if (retry_status <= 0) {
- s = retry_status;
- }
- err = handle_addrinfo_result(s, req.addrinfo, addresses);
-
-done:
- gpr_free(host);
- gpr_free(port);
- if (req.addrinfo) {
- uv_freeaddrinfo(req.addrinfo);
- }
- return err;
-}
-
-grpc_error* (*grpc_blocking_resolve_address)(
- const char* name, const char* default_port,
- grpc_resolved_addresses** addresses) = blocking_resolve_address_impl;
-
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
- if (addrs != NULL) {
- gpr_free(addrs->addrs);
- }
- gpr_free(addrs);
-}
-
-static void resolve_address_impl(const char* name, const char* default_port,
- grpc_pollset_set* interested_parties,
- grpc_closure* on_done,
- grpc_resolved_addresses** addrs) {
- uv_getaddrinfo_t* req = NULL;
- request* r = NULL;
- struct addrinfo* hints = NULL;
- char* host = NULL;
- char* port = NULL;
- grpc_error* err;
- int s;
- GRPC_UV_ASSERT_SAME_THREAD();
- err = try_split_host_port(name, default_port, &host, &port);
- if (err != GRPC_ERROR_NONE) {
- GRPC_CLOSURE_SCHED(on_done, err);
- gpr_free(host);
- gpr_free(port);
- return;
- }
- r = (request*)gpr_malloc(sizeof(request));
- r->on_done = on_done;
- r->addresses = addrs;
- r->host = host;
- r->port = port;
- req = (uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t));
- req->data = r;
-
- /* Call getaddrinfo */
- hints = (addrinfo*)gpr_malloc(sizeof(struct addrinfo));
- memset(hints, 0, sizeof(struct addrinfo));
- hints->ai_family = AF_UNSPEC; /* ipv4 or ipv6 */
- hints->ai_socktype = SOCK_STREAM; /* stream socket */
- hints->ai_flags = AI_PASSIVE; /* for wildcard IP address */
- r->hints = hints;
-
- s = uv_getaddrinfo(uv_default_loop(), req, getaddrinfo_callback, host, port,
- hints);
-
- if (s != 0) {
- *addrs = NULL;
- err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getaddrinfo failed");
- err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(s)));
- GRPC_CLOSURE_SCHED(on_done, err);
- gpr_free(r);
- gpr_free(req);
- gpr_free(hints);
- gpr_free(host);
- gpr_free(port);
- }
-}
-
-void (*grpc_resolve_address)(
- const char* name, const char* default_port,
- grpc_pollset_set* interested_parties, grpc_closure* on_done,
- grpc_resolved_addresses** addrs) = resolve_address_impl;
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/resolve_address_windows.cc b/src/core/lib/iomgr/resolve_address_windows.cc
index 4e1dcaabaf..71c92615ad 100644
--- a/src/core/lib/iomgr/resolve_address_windows.cc
+++ b/src/core/lib/iomgr/resolve_address_windows.cc
@@ -37,7 +37,7 @@
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/block_annotate.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
@@ -51,7 +51,7 @@ typedef struct {
grpc_resolved_addresses** addresses;
} request;
-static grpc_error* blocking_resolve_address_impl(
+static grpc_error* windows_blocking_resolve_address(
const char* name, const char* default_port,
grpc_resolved_addresses** addresses) {
grpc_core::ExecCtx exec_ctx;
@@ -130,10 +130,6 @@ done:
return error;
}
-grpc_error* (*grpc_blocking_resolve_address)(
- const char* name, const char* default_port,
- grpc_resolved_addresses** addresses) = blocking_resolve_address_impl;
-
/* Callback to be passed to grpc_executor to asynch-ify
* grpc_blocking_resolve_address */
static void do_request_thread(void* rp, grpc_error* error) {
@@ -150,17 +146,10 @@ static void do_request_thread(void* rp, grpc_error* error) {
gpr_free(r);
}
-void grpc_resolved_addresses_destroy(grpc_resolved_addresses* addrs) {
- if (addrs != NULL) {
- gpr_free(addrs->addrs);
- }
- gpr_free(addrs);
-}
-
-static void resolve_address_impl(const char* name, const char* default_port,
- grpc_pollset_set* interested_parties,
- grpc_closure* on_done,
- grpc_resolved_addresses** addresses) {
+static void windows_resolve_address(const char* name, const char* default_port,
+ grpc_pollset_set* interested_parties,
+ grpc_closure* on_done,
+ grpc_resolved_addresses** addresses) {
request* r = (request*)gpr_malloc(sizeof(request));
GRPC_CLOSURE_INIT(&r->request_closure, do_request_thread, r,
grpc_executor_scheduler(GRPC_EXECUTOR_SHORT));
@@ -171,9 +160,6 @@ static void resolve_address_impl(const char* name, const char* default_port,
GRPC_CLOSURE_SCHED(&r->request_closure, GRPC_ERROR_NONE);
}
-void (*grpc_resolve_address)(
- const char* name, const char* default_port,
- grpc_pollset_set* interested_parties, grpc_closure* on_done,
- grpc_resolved_addresses** addresses) = resolve_address_impl;
-
+grpc_address_resolver_vtable grpc_windows_resolver_vtable = {
+ windows_resolve_address, windows_blocking_resolve_address};
#endif
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index 4e1c651278..89e8a39118 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -139,8 +139,4 @@ void grpc_resource_user_alloc_slices(
grpc_resource_user_slice_allocator* slice_allocator, size_t length,
size_t count, grpc_slice_buffer* dest);
-/* Allocate one slice of length \a size synchronously. */
-grpc_slice grpc_resource_user_slice_malloc(grpc_resource_user* resource_user,
- size_t size);
-
#endif /* GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H */
diff --git a/src/core/lib/iomgr/sockaddr.h b/src/core/lib/iomgr/sockaddr.h
index 3b30da8a7d..5edf735cd1 100644
--- a/src/core/lib/iomgr/sockaddr.h
+++ b/src/core/lib/iomgr/sockaddr.h
@@ -25,18 +25,8 @@
#include <grpc/support/port_platform.h>
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-#include <uv.h>
-#endif
-
-#ifdef GPR_WINDOWS
-#include "src/core/lib/iomgr/sockaddr_windows.h"
-#endif
-
-#ifdef GRPC_POSIX_SOCKETADDR
+#include "src/core/lib/iomgr/sockaddr_custom.h"
#include "src/core/lib/iomgr/sockaddr_posix.h"
-#endif
+#include "src/core/lib/iomgr/sockaddr_windows.h"
#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_H */
diff --git a/src/core/lib/iomgr/sockaddr_custom.h b/src/core/lib/iomgr/sockaddr_custom.h
new file mode 100644
index 0000000000..d85cc504d3
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr_custom.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stddef.h>
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_UV
+
+#include <uv.h>
+
+// TODO(kpayson) It would be nice to abstract this so we don't
+// depend on anything uv specific
+typedef struct sockaddr grpc_sockaddr;
+typedef struct sockaddr_in grpc_sockaddr_in;
+typedef struct in_addr grpc_in_addr;
+typedef struct sockaddr_in6 grpc_sockaddr_in6;
+typedef struct in6_addr grpc_in6_addr;
+
+#define GRPC_INET_ADDRSTRLEN INET_ADDRSTRLEN
+#define GRPC_INET6_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define GRPC_SOCK_STREAM SOCK_STREAM
+#define GRPC_SOCK_DGRAM SOCK_DGRAM
+
+#define GRPC_AF_UNSPEC AF_UNSPEC
+#define GRPC_AF_UNIX AF_UNIX
+#define GRPC_AF_INET AF_INET
+#define GRPC_AF_INET6 AF_INET6
+
+#define GRPC_AI_PASSIVE AI_PASSIVE
+
+#endif // GRPC_UV
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_CUSTOM_H */
diff --git a/src/core/lib/iomgr/sockaddr_posix.h b/src/core/lib/iomgr/sockaddr_posix.h
index 83981e0aa5..5b18bbc465 100644
--- a/src/core/lib/iomgr/sockaddr_posix.h
+++ b/src/core/lib/iomgr/sockaddr_posix.h
@@ -21,6 +21,9 @@
#include <grpc/support/port_platform.h>
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_POSIX_SOCKET
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -28,4 +31,25 @@
#include <sys/types.h>
#include <unistd.h>
+typedef struct sockaddr grpc_sockaddr;
+typedef struct sockaddr_in grpc_sockaddr_in;
+typedef struct in_addr grpc_in_addr;
+typedef struct sockaddr_in6 grpc_sockaddr_in6;
+typedef struct in6_addr grpc_in6_addr;
+
+#define GRPC_INET_ADDRSTRLEN INET_ADDRSTRLEN
+#define GRPC_INET6_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define GRPC_SOCK_STREAM SOCK_STREAM
+#define GRPC_SOCK_DGRAM SOCK_DGRAM
+
+#define GRPC_AF_UNSPEC AF_UNSPEC
+#define GRPC_AF_UNIX AF_UNIX
+#define GRPC_AF_INET AF_INET
+#define GRPC_AF_INET6 AF_INET6
+
+#define GRPC_AI_PASSIVE AI_PASSIVE
+
+#endif
+
#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_POSIX_H */
diff --git a/src/core/lib/iomgr/sockaddr_utils.cc b/src/core/lib/iomgr/sockaddr_utils.cc
index 88f9b2ffd9..bc3550a679 100644
--- a/src/core/lib/iomgr/sockaddr_utils.cc
+++ b/src/core/lib/iomgr/sockaddr_utils.cc
@@ -40,25 +40,25 @@ static const uint8_t kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0,
int grpc_sockaddr_is_v4mapped(const grpc_resolved_address* resolved_addr,
grpc_resolved_address* resolved_addr4_out) {
GPR_ASSERT(resolved_addr != resolved_addr4_out);
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
- struct sockaddr_in* addr4_out =
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+ grpc_sockaddr_in* addr4_out =
resolved_addr4_out == nullptr
? nullptr
- : reinterpret_cast<struct sockaddr_in*>(resolved_addr4_out->addr);
- if (addr->sa_family == AF_INET6) {
- const struct sockaddr_in6* addr6 =
- reinterpret_cast<const struct sockaddr_in6*>(addr);
+ : reinterpret_cast<grpc_sockaddr_in*>(resolved_addr4_out->addr);
+ if (addr->sa_family == GRPC_AF_INET6) {
+ const grpc_sockaddr_in6* addr6 =
+ reinterpret_cast<const grpc_sockaddr_in6*>(addr);
if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix,
sizeof(kV4MappedPrefix)) == 0) {
if (resolved_addr4_out != nullptr) {
/* Normalize ::ffff:0.0.0.0/96 to IPv4. */
memset(resolved_addr4_out, 0, sizeof(*resolved_addr4_out));
- addr4_out->sin_family = AF_INET;
+ addr4_out->sin_family = GRPC_AF_INET;
/* s6_addr32 would be nice, but it's non-standard. */
memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4);
addr4_out->sin_port = addr6->sin6_port;
- resolved_addr4_out->len = sizeof(struct sockaddr_in);
+ resolved_addr4_out->len = sizeof(grpc_sockaddr_in);
}
return 1;
}
@@ -69,19 +69,19 @@ int grpc_sockaddr_is_v4mapped(const grpc_resolved_address* resolved_addr,
int grpc_sockaddr_to_v4mapped(const grpc_resolved_address* resolved_addr,
grpc_resolved_address* resolved_addr6_out) {
GPR_ASSERT(resolved_addr != resolved_addr6_out);
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
- struct sockaddr_in6* addr6_out =
- reinterpret_cast<struct sockaddr_in6*>(resolved_addr6_out->addr);
- if (addr->sa_family == AF_INET) {
- const struct sockaddr_in* addr4 =
- reinterpret_cast<const struct sockaddr_in*>(addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+ grpc_sockaddr_in6* addr6_out =
+ reinterpret_cast<grpc_sockaddr_in6*>(resolved_addr6_out->addr);
+ if (addr->sa_family == GRPC_AF_INET) {
+ const grpc_sockaddr_in* addr4 =
+ reinterpret_cast<const grpc_sockaddr_in*>(addr);
memset(resolved_addr6_out, 0, sizeof(*resolved_addr6_out));
- addr6_out->sin6_family = AF_INET6;
+ addr6_out->sin6_family = GRPC_AF_INET6;
memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12);
memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4);
addr6_out->sin6_port = addr4->sin_port;
- resolved_addr6_out->len = sizeof(struct sockaddr_in6);
+ resolved_addr6_out->len = sizeof(grpc_sockaddr_in6);
return 1;
}
return 0;
@@ -89,32 +89,32 @@ int grpc_sockaddr_to_v4mapped(const grpc_resolved_address* resolved_addr,
int grpc_sockaddr_is_wildcard(const grpc_resolved_address* resolved_addr,
int* port_out) {
- const struct sockaddr* addr;
+ const grpc_sockaddr* addr;
grpc_resolved_address addr4_normalized;
if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr4_normalized)) {
resolved_addr = &addr4_normalized;
}
- addr = reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
- if (addr->sa_family == AF_INET) {
+ addr = reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+ if (addr->sa_family == GRPC_AF_INET) {
/* Check for 0.0.0.0 */
- const struct sockaddr_in* addr4 =
- reinterpret_cast<const struct sockaddr_in*>(addr);
+ const grpc_sockaddr_in* addr4 =
+ reinterpret_cast<const grpc_sockaddr_in*>(addr);
if (addr4->sin_addr.s_addr != 0) {
return 0;
}
- *port_out = ntohs(addr4->sin_port);
+ *port_out = grpc_ntohs(addr4->sin_port);
return 1;
- } else if (addr->sa_family == AF_INET6) {
+ } else if (addr->sa_family == GRPC_AF_INET6) {
/* Check for :: */
- const struct sockaddr_in6* addr6 =
- reinterpret_cast<const struct sockaddr_in6*>(addr);
+ const grpc_sockaddr_in6* addr6 =
+ reinterpret_cast<const grpc_sockaddr_in6*>(addr);
int i;
for (i = 0; i < 16; i++) {
if (addr6->sin6_addr.s6_addr[i] != 0) {
return 0;
}
}
- *port_out = ntohs(addr6->sin6_port);
+ *port_out = grpc_ntohs(addr6->sin6_port);
return 1;
} else {
return 0;
@@ -129,33 +129,33 @@ void grpc_sockaddr_make_wildcards(int port, grpc_resolved_address* wild4_out,
void grpc_sockaddr_make_wildcard4(int port,
grpc_resolved_address* resolved_wild_out) {
- struct sockaddr_in* wild_out =
- reinterpret_cast<struct sockaddr_in*>(resolved_wild_out->addr);
+ grpc_sockaddr_in* wild_out =
+ reinterpret_cast<grpc_sockaddr_in*>(resolved_wild_out->addr);
GPR_ASSERT(port >= 0 && port < 65536);
memset(resolved_wild_out, 0, sizeof(*resolved_wild_out));
- wild_out->sin_family = AF_INET;
- wild_out->sin_port = htons(static_cast<uint16_t>(port));
- resolved_wild_out->len = sizeof(struct sockaddr_in);
+ wild_out->sin_family = GRPC_AF_INET;
+ wild_out->sin_port = grpc_htons(static_cast<uint16_t>(port));
+ resolved_wild_out->len = sizeof(grpc_sockaddr_in);
}
void grpc_sockaddr_make_wildcard6(int port,
grpc_resolved_address* resolved_wild_out) {
- struct sockaddr_in6* wild_out =
- reinterpret_cast<struct sockaddr_in6*>(resolved_wild_out->addr);
+ grpc_sockaddr_in6* wild_out =
+ reinterpret_cast<grpc_sockaddr_in6*>(resolved_wild_out->addr);
GPR_ASSERT(port >= 0 && port < 65536);
memset(resolved_wild_out, 0, sizeof(*resolved_wild_out));
- wild_out->sin6_family = AF_INET6;
- wild_out->sin6_port = htons(static_cast<uint16_t>(port));
- resolved_wild_out->len = sizeof(struct sockaddr_in6);
+ wild_out->sin6_family = GRPC_AF_INET6;
+ wild_out->sin6_port = grpc_htons(static_cast<uint16_t>(port));
+ resolved_wild_out->len = sizeof(grpc_sockaddr_in6);
}
int grpc_sockaddr_to_string(char** out,
const grpc_resolved_address* resolved_addr,
int normalize) {
- const struct sockaddr* addr;
+ const grpc_sockaddr* addr;
const int save_errno = errno;
grpc_resolved_address addr_normalized;
- char ntop_buf[INET6_ADDRSTRLEN];
+ char ntop_buf[GRPC_INET6_ADDRSTRLEN];
const void* ip = nullptr;
int port = 0;
uint32_t sin6_scope_id = 0;
@@ -165,17 +165,17 @@ int grpc_sockaddr_to_string(char** out,
if (normalize && grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) {
resolved_addr = &addr_normalized;
}
- addr = reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
- if (addr->sa_family == AF_INET) {
- const struct sockaddr_in* addr4 =
- reinterpret_cast<const struct sockaddr_in*>(addr);
+ addr = reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
+ if (addr->sa_family == GRPC_AF_INET) {
+ const grpc_sockaddr_in* addr4 =
+ reinterpret_cast<const grpc_sockaddr_in*>(addr);
ip = &addr4->sin_addr;
- port = ntohs(addr4->sin_port);
- } else if (addr->sa_family == AF_INET6) {
- const struct sockaddr_in6* addr6 =
- reinterpret_cast<const struct sockaddr_in6*>(addr);
+ port = grpc_ntohs(addr4->sin_port);
+ } else if (addr->sa_family == GRPC_AF_INET6) {
+ const grpc_sockaddr_in6* addr6 =
+ reinterpret_cast<const grpc_sockaddr_in6*>(addr);
ip = &addr6->sin6_addr;
- port = ntohs(addr6->sin6_port);
+ port = grpc_ntohs(addr6->sin6_port);
sin6_scope_id = addr6->sin6_scope_id;
}
if (ip != nullptr && grpc_inet_ntop(addr->sa_family, ip, ntop_buf,
@@ -197,6 +197,22 @@ int grpc_sockaddr_to_string(char** out,
return ret;
}
+void grpc_string_to_sockaddr(grpc_resolved_address* out, char* addr, int port) {
+ grpc_sockaddr_in6* addr6 = (grpc_sockaddr_in6*)out->addr;
+ grpc_sockaddr_in* addr4 = (grpc_sockaddr_in*)out->addr;
+
+ if (grpc_inet_pton(GRPC_AF_INET6, addr, &addr6->sin6_addr) == 1) {
+ addr6->sin6_family = GRPC_AF_INET6;
+ out->len = sizeof(grpc_sockaddr_in6);
+ } else if (grpc_inet_pton(GRPC_AF_INET, addr, &addr4->sin_addr) == 1) {
+ addr4->sin_family = GRPC_AF_INET;
+ out->len = sizeof(grpc_sockaddr_in);
+ } else {
+ GPR_ASSERT(0);
+ }
+ grpc_sockaddr_set_port(out, port);
+}
+
char* grpc_sockaddr_to_uri(const grpc_resolved_address* resolved_addr) {
grpc_resolved_address addr_normalized;
if (grpc_sockaddr_is_v4mapped(resolved_addr, &addr_normalized)) {
@@ -219,33 +235,33 @@ char* grpc_sockaddr_to_uri(const grpc_resolved_address* resolved_addr) {
const char* grpc_sockaddr_get_uri_scheme(
const grpc_resolved_address* resolved_addr) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
switch (addr->sa_family) {
- case AF_INET:
+ case GRPC_AF_INET:
return "ipv4";
- case AF_INET6:
+ case GRPC_AF_INET6:
return "ipv6";
- case AF_UNIX:
+ case GRPC_AF_UNIX:
return "unix";
}
return nullptr;
}
int grpc_sockaddr_get_family(const grpc_resolved_address* resolved_addr) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
return addr->sa_family;
}
int grpc_sockaddr_get_port(const grpc_resolved_address* resolved_addr) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
switch (addr->sa_family) {
- case AF_INET:
- return ntohs(((struct sockaddr_in*)addr)->sin_port);
- case AF_INET6:
- return ntohs(((struct sockaddr_in6*)addr)->sin6_port);
+ case GRPC_AF_INET:
+ return grpc_ntohs(((grpc_sockaddr_in*)addr)->sin_port);
+ case GRPC_AF_INET6:
+ return grpc_ntohs(((grpc_sockaddr_in6*)addr)->sin6_port);
default:
if (grpc_is_unix_socket(resolved_addr)) {
return 1;
@@ -258,18 +274,18 @@ int grpc_sockaddr_get_port(const grpc_resolved_address* resolved_addr) {
int grpc_sockaddr_set_port(const grpc_resolved_address* resolved_addr,
int port) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
switch (addr->sa_family) {
- case AF_INET:
+ case GRPC_AF_INET:
GPR_ASSERT(port >= 0 && port < 65536);
- ((struct sockaddr_in*)addr)->sin_port =
- htons(static_cast<uint16_t>(port));
+ ((grpc_sockaddr_in*)addr)->sin_port =
+ grpc_htons(static_cast<uint16_t>(port));
return 1;
- case AF_INET6:
+ case GRPC_AF_INET6:
GPR_ASSERT(port >= 0 && port < 65536);
- ((struct sockaddr_in6*)addr)->sin6_port =
- htons(static_cast<uint16_t>(port));
+ ((grpc_sockaddr_in6*)addr)->sin6_port =
+ grpc_htons(static_cast<uint16_t>(port));
return 1;
default:
gpr_log(GPR_ERROR, "Unknown socket family %d in grpc_sockaddr_set_port",
diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h
index ace54a2a80..a4e90a73ab 100644
--- a/src/core/lib/iomgr/sockaddr_utils.h
+++ b/src/core/lib/iomgr/sockaddr_utils.h
@@ -71,6 +71,8 @@ int grpc_sockaddr_set_port(const grpc_resolved_address* addr, int port);
int grpc_sockaddr_to_string(char** out, const grpc_resolved_address* addr,
int normalize);
+void grpc_string_to_sockaddr(grpc_resolved_address* out, char* addr, int port);
+
/* Returns the URI string corresponding to \a addr */
char* grpc_sockaddr_to_uri(const grpc_resolved_address* addr);
diff --git a/src/core/lib/iomgr/sockaddr_windows.h b/src/core/lib/iomgr/sockaddr_windows.h
index 3a4fcc9e8a..4d637251a1 100644
--- a/src/core/lib/iomgr/sockaddr_windows.h
+++ b/src/core/lib/iomgr/sockaddr_windows.h
@@ -31,6 +31,25 @@
// must be included after the above
#include <mswsock.h>
+typedef struct sockaddr grpc_sockaddr;
+typedef struct sockaddr_in grpc_sockaddr_in;
+typedef struct in_addr grpc_in_addr;
+typedef struct sockaddr_in6 grpc_sockaddr_in6;
+typedef struct in6_addr grpc_in6_addr;
+
+#define GRPC_INET_ADDRSTRLEN INET_ADDRSTRLEN
+#define GRPC_INET6_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define GRPC_SOCK_STREAM SOCK_STREAM
+#define GRPC_SOCK_DGRAM SOCK_DGRAM
+
+#define GRPC_AF_UNSPEC AF_UNSPEC
+#define GRPC_AF_UNIX AF_UNIX
+#define GRPC_AF_INET AF_INET
+#define GRPC_AF_INET6 AF_INET6
+
+#define GRPC_AI_PASSIVE AI_PASSIVE
+
#endif
#endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_WINDOWS_H */
diff --git a/src/core/lib/iomgr/socket_utils.h b/src/core/lib/iomgr/socket_utils.h
index e96eb97a7e..cf1a7be648 100644
--- a/src/core/lib/iomgr/socket_utils.h
+++ b/src/core/lib/iomgr/socket_utils.h
@@ -23,6 +23,15 @@
#include <stddef.h>
+/* A wrapper for htons on POSIX and Windows */
+uint16_t grpc_htons(uint16_t hostshort);
+
+/* A wrapper for ntohs on POSIX and WINDOWS */
+uint16_t grpc_ntohs(uint16_t netshort);
+
+/* A wrapper for inet_pton on POSIX and WINDOWS */
+int grpc_inet_pton(int af, const char* src, void* dst);
+
/* A wrapper for inet_ntop on POSIX systems and InetNtop on Windows systems */
const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size);
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc
index 4fb6c7ad63..c52e237fa8 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -43,6 +43,7 @@
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
/* set a socket to non blocking mode */
@@ -215,12 +216,11 @@ static void probe_ipv6_once(void) {
if (fd < 0) {
gpr_log(GPR_INFO, "Disabling AF_INET6 sockets because socket() failed.");
} else {
- struct sockaddr_in6 addr;
+ grpc_sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr.s6_addr[15] = 1; /* [::1]:0 */
- if (bind(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) ==
- 0) {
+ if (bind(fd, reinterpret_cast<grpc_sockaddr*>(&addr), sizeof(addr)) == 0) {
g_ipv6_loopback_available = 1;
} else {
gpr_log(GPR_INFO,
@@ -280,8 +280,8 @@ static int create_socket(grpc_socket_factory* factory, int domain, int type,
grpc_error* grpc_create_dualstack_socket_using_factory(
grpc_socket_factory* factory, const grpc_resolved_address* resolved_addr,
int type, int protocol, grpc_dualstack_mode* dsmode, int* newfd) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
int family = addr->sa_family;
if (family == AF_INET6) {
if (grpc_ipv6_loopback_available()) {
@@ -311,6 +311,14 @@ grpc_error* grpc_create_dualstack_socket_using_factory(
return error_for_fd(*newfd, resolved_addr);
}
+uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
+
+uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
+
+int grpc_inet_pton(int af, const char* src, void* dst) {
+ return inet_pton(af, src, dst);
+}
+
const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
GPR_ASSERT(size <= (socklen_t)-1);
return inet_ntop(af, src, dst, static_cast<socklen_t>(size));
diff --git a/src/core/lib/iomgr/socket_utils_linux.cc b/src/core/lib/iomgr/socket_utils_linux.cc
index deb7c55267..1364cd35f6 100644
--- a/src/core/lib/iomgr/socket_utils_linux.cc
+++ b/src/core/lib/iomgr/socket_utils_linux.cc
@@ -37,8 +37,7 @@ int grpc_accept4(int sockfd, grpc_resolved_address* resolved_addr, int nonblock,
GPR_ASSERT(resolved_addr->len <= (socklen_t)-1);
flags |= nonblock ? SOCK_NONBLOCK : 0;
flags |= cloexec ? SOCK_CLOEXEC : 0;
- return accept4(sockfd,
- reinterpret_cast<struct sockaddr*>(resolved_addr->addr),
+ return accept4(sockfd, reinterpret_cast<grpc_sockaddr*>(resolved_addr->addr),
reinterpret_cast<socklen_t*>(&resolved_addr->len), flags);
}
diff --git a/src/core/lib/iomgr/socket_utils_posix.cc b/src/core/lib/iomgr/socket_utils_posix.cc
index c856f641e3..d5d00af976 100644
--- a/src/core/lib/iomgr/socket_utils_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_posix.cc
@@ -36,7 +36,7 @@ int grpc_accept4(int sockfd, grpc_resolved_address* resolved_addr, int nonblock,
int fd, flags;
GPR_ASSERT(sizeof(socklen_t) <= sizeof(size_t));
GPR_ASSERT(resolved_addr->len <= (socklen_t)-1);
- fd = accept(sockfd, (struct sockaddr*)resolved_addr->addr,
+ fd = accept(sockfd, (grpc_sockaddr*)resolved_addr->addr,
(socklen_t*)&resolved_addr->len);
if (fd >= 0) {
if (nonblock) {
diff --git a/src/core/lib/iomgr/socket_utils_uv.cc b/src/core/lib/iomgr/socket_utils_uv.cc
index 3f650eef66..8538abc7e4 100644
--- a/src/core/lib/iomgr/socket_utils_uv.cc
+++ b/src/core/lib/iomgr/socket_utils_uv.cc
@@ -22,15 +22,24 @@
#ifdef GRPC_UV
-#include <uv.h>
-
+#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/socket_utils.h"
#include <grpc/support/log.h>
+#include <uv.h>
+
+uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
+
+uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
+
+int grpc_inet_pton(int af, const char* src, void* dst) {
+ return inet_pton(af, src, dst);
+}
+
const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
- uv_inet_ntop(af, src, dst, size);
- return dst;
+ /* Windows InetNtopA wants a mutable ip pointer */
+ return inet_ntop(af, src, dst, (socklen_t)size);
}
#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/socket_utils_windows.cc b/src/core/lib/iomgr/socket_utils_windows.cc
index 5fc3b7617e..3e7b5b812d 100644
--- a/src/core/lib/iomgr/socket_utils_windows.cc
+++ b/src/core/lib/iomgr/socket_utils_windows.cc
@@ -27,6 +27,14 @@
#include <grpc/support/log.h>
+uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
+
+uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
+
+int grpc_inet_pton(int af, const char* src, void* dst) {
+ return inet_pton(af, src, dst);
+}
+
const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
/* Windows InetNtopA wants a mutable ip pointer */
return InetNtopA(af, (void*)src, dst, size);
diff --git a/src/core/lib/iomgr/tcp_client.cc b/src/core/lib/iomgr/tcp_client.cc
new file mode 100644
index 0000000000..6c0ba40781
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client.cc
@@ -0,0 +1,36 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/tcp_client.h"
+
+grpc_tcp_client_vtable* grpc_tcp_client_impl;
+
+void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
+ grpc_pollset_set* interested_parties,
+ const grpc_channel_args* channel_args,
+ const grpc_resolved_address* addr,
+ grpc_millis deadline) {
+ grpc_tcp_client_impl->connect(closure, ep, interested_parties, channel_args,
+ addr, deadline);
+}
+
+void grpc_set_tcp_client_impl(grpc_tcp_client_vtable* impl) {
+ grpc_tcp_client_impl = impl;
+}
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index a6b99e63c2..d209eeb8c2 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -27,6 +27,13 @@
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/iomgr/resolve_address.h"
+typedef struct grpc_tcp_client_vtable {
+ void (*connect)(grpc_closure* on_connect, grpc_endpoint** endpoint,
+ grpc_pollset_set* interested_parties,
+ const grpc_channel_args* channel_args,
+ const grpc_resolved_address* addr, grpc_millis deadline);
+} grpc_tcp_client_vtable;
+
/* Asynchronously connect to an address (specified as (addr, len)), and call
cb with arg and the completed connection when done (or call cb with arg and
NULL on failure).
@@ -38,4 +45,8 @@ void grpc_tcp_client_connect(grpc_closure* on_connect, grpc_endpoint** endpoint,
const grpc_resolved_address* addr,
grpc_millis deadline);
+void grpc_tcp_client_global_init();
+
+void grpc_set_tcp_client_impl(grpc_tcp_client_vtable* impl);
+
#endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H */
diff --git a/src/core/lib/iomgr/tcp_client_custom.cc b/src/core/lib/iomgr/tcp_client_custom.cc
new file mode 100644
index 0000000000..55632a55a1
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_client_custom.cc
@@ -0,0 +1,151 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/timer.h"
+
+extern grpc_core::TraceFlag grpc_tcp_trace;
+extern grpc_socket_vtable* grpc_custom_socket_vtable;
+
+struct grpc_custom_tcp_connect {
+ grpc_custom_socket* socket;
+ grpc_timer alarm;
+ grpc_closure on_alarm;
+ grpc_closure* closure;
+ grpc_endpoint** endpoint;
+ int refs;
+ char* addr_name;
+ grpc_resource_quota* resource_quota;
+};
+
+static void custom_tcp_connect_cleanup(grpc_custom_tcp_connect* connect) {
+ grpc_custom_socket* socket = connect->socket;
+ grpc_resource_quota_unref_internal(connect->resource_quota);
+ gpr_free(connect->addr_name);
+ gpr_free(connect);
+ socket->refs--;
+ if (socket->refs == 0) {
+ grpc_custom_socket_vtable->destroy(socket);
+ gpr_free(socket);
+ }
+}
+
+static void custom_close_callback(grpc_custom_socket* socket) {}
+
+static void on_alarm(void* acp, grpc_error* error) {
+ int done;
+ grpc_custom_socket* socket = (grpc_custom_socket*)acp;
+ grpc_custom_tcp_connect* connect = socket->connector;
+ if (grpc_tcp_trace.enabled()) {
+ const char* str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s",
+ connect->addr_name, str);
+ }
+ if (error == GRPC_ERROR_NONE) {
+ /* error == NONE implies that the timer ran out, and wasn't cancelled. If
+ it was cancelled, then the handler that cancelled it also should close
+ the handle, if applicable */
+ grpc_custom_socket_vtable->close(socket, custom_close_callback);
+ }
+ done = (--connect->refs == 0);
+ if (done) {
+ custom_tcp_connect_cleanup(connect);
+ }
+}
+
+static void custom_connect_callback(grpc_custom_socket* socket,
+ grpc_error* error) {
+ grpc_core::ExecCtx exec_ctx;
+ grpc_custom_tcp_connect* connect = socket->connector;
+ int done;
+ grpc_closure* closure = connect->closure;
+ grpc_timer_cancel(&connect->alarm);
+ if (error == GRPC_ERROR_NONE) {
+ *connect->endpoint = custom_tcp_endpoint_create(
+ socket, connect->resource_quota, connect->addr_name);
+ }
+ done = (--connect->refs == 0);
+ if (done) {
+ grpc_core::ExecCtx::Get()->Flush();
+ custom_tcp_connect_cleanup(connect);
+ }
+ GRPC_CLOSURE_SCHED(closure, error);
+}
+
+static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
+ grpc_pollset_set* interested_parties,
+ const grpc_channel_args* channel_args,
+ const grpc_resolved_address* resolved_addr,
+ grpc_millis deadline) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ (void)channel_args;
+ (void)interested_parties;
+ grpc_custom_tcp_connect* connect;
+ grpc_resource_quota* resource_quota = grpc_resource_quota_create(nullptr);
+ if (channel_args != nullptr) {
+ for (size_t i = 0; i < channel_args->num_args; i++) {
+ if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+ grpc_resource_quota_unref_internal(resource_quota);
+ resource_quota = grpc_resource_quota_ref_internal(
+ (grpc_resource_quota*)channel_args->args[i].value.pointer.p);
+ }
+ }
+ }
+ grpc_custom_socket* socket =
+ (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+ socket->refs = 2;
+ grpc_custom_socket_vtable->init(socket, GRPC_AF_UNSPEC);
+ connect =
+ (grpc_custom_tcp_connect*)gpr_malloc(sizeof(grpc_custom_tcp_connect));
+ connect->closure = closure;
+ connect->endpoint = ep;
+ connect->addr_name = grpc_sockaddr_to_uri(resolved_addr);
+ connect->resource_quota = resource_quota;
+ connect->socket = socket;
+ socket->connector = connect;
+ socket->endpoint = nullptr;
+ socket->listener = nullptr;
+ connect->refs = 2;
+
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %p %s: asynchronously connecting",
+ socket, connect->addr_name);
+ }
+
+ grpc_custom_socket_vtable->connect(
+ socket, (const grpc_sockaddr*)resolved_addr->addr, resolved_addr->len,
+ custom_connect_callback);
+ GRPC_CLOSURE_INIT(&connect->on_alarm, on_alarm, socket,
+ grpc_schedule_on_exec_ctx);
+ grpc_timer_init(&connect->alarm, deadline, &connect->on_alarm);
+}
+
+grpc_tcp_client_vtable custom_tcp_client_vtable = {tcp_connect};
diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc
index 3fe2989c6b..c21fb40ab1 100644
--- a/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/src/core/lib/iomgr/tcp_client_posix.cc
@@ -38,6 +38,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_posix.h"
+#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_mutator.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
@@ -293,7 +294,7 @@ void grpc_tcp_client_create_from_prepared_fd(
async_connect* ac;
do {
GPR_ASSERT(addr->len < ~(socklen_t)0);
- err = connect(fd, reinterpret_cast<const struct sockaddr*>(addr->addr),
+ err = connect(fd, reinterpret_cast<const grpc_sockaddr*>(addr->addr),
static_cast<socklen_t>(addr->len));
} while (err < 0 && errno == EINTR);
if (err >= 0) {
@@ -336,11 +337,11 @@ void grpc_tcp_client_create_from_prepared_fd(
gpr_mu_unlock(&ac->mu);
}
-static void tcp_client_connect_impl(grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties,
- const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) {
+static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep,
+ grpc_pollset_set* interested_parties,
+ const grpc_channel_args* channel_args,
+ const grpc_resolved_address* addr,
+ grpc_millis deadline) {
grpc_resolved_address mapped_addr;
grpc_fd* fdobj = nullptr;
grpc_error* error;
@@ -355,20 +356,5 @@ static void tcp_client_connect_impl(grpc_closure* closure, grpc_endpoint** ep,
ep);
}
-// overridden by api_fuzzer.c
-void (*grpc_tcp_client_connect_impl)(
- grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) = tcp_client_connect_impl;
-
-void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties,
- const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) {
- grpc_tcp_client_connect_impl(closure, ep, interested_parties, channel_args,
- addr, deadline);
-}
-
+grpc_tcp_client_vtable grpc_posix_tcp_client_vtable = {tcp_connect};
#endif
diff --git a/src/core/lib/iomgr/tcp_client_uv.cc b/src/core/lib/iomgr/tcp_client_uv.cc
deleted file mode 100644
index d29d6c8f41..0000000000
--- a/src/core/lib/iomgr/tcp_client_uv.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/iomgr/tcp_client.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
-#include "src/core/lib/iomgr/timer.h"
-
-extern grpc_core::TraceFlag grpc_tcp_trace;
-
-typedef struct grpc_uv_tcp_connect {
- uv_connect_t connect_req;
- grpc_timer alarm;
- grpc_closure on_alarm;
- uv_tcp_t* tcp_handle;
- grpc_closure* closure;
- grpc_endpoint** endpoint;
- int refs;
- char* addr_name;
- grpc_resource_quota* resource_quota;
-} grpc_uv_tcp_connect;
-
-static void uv_tcp_connect_cleanup(grpc_uv_tcp_connect* connect) {
- grpc_resource_quota_unref_internal(connect->resource_quota);
- gpr_free(connect->addr_name);
- gpr_free(connect);
-}
-
-static void tcp_close_callback(uv_handle_t* handle) { gpr_free(handle); }
-
-static void uv_tc_on_alarm(void* acp, grpc_error* error) {
- int done;
- grpc_uv_tcp_connect* connect = (grpc_uv_tcp_connect*)acp;
- if (grpc_tcp_trace.enabled()) {
- const char* str = grpc_error_string(error);
- gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s",
- connect->addr_name, str);
- }
- if (error == GRPC_ERROR_NONE) {
- /* error == NONE implies that the timer ran out, and wasn't cancelled. If
- it was cancelled, then the handler that cancelled it also should close
- the handle, if applicable */
- uv_close((uv_handle_t*)connect->tcp_handle, tcp_close_callback);
- }
- done = (--connect->refs == 0);
- if (done) {
- uv_tcp_connect_cleanup(connect);
- }
-}
-
-static void uv_tc_on_connect(uv_connect_t* req, int status) {
- grpc_uv_tcp_connect* connect = (grpc_uv_tcp_connect*)req->data;
- grpc_core::ExecCtx exec_ctx;
- grpc_error* error = GRPC_ERROR_NONE;
- int done;
- grpc_closure* closure = connect->closure;
- grpc_timer_cancel(&connect->alarm);
- if (status == 0) {
- *connect->endpoint = grpc_tcp_create(
- connect->tcp_handle, connect->resource_quota, connect->addr_name);
- } else {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Failed to connect to remote host");
- error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, -status);
- error =
- grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- if (status == UV_ECANCELED) {
- error =
- grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string("Timeout occurred"));
- // This should only happen if the handle is already closed
- } else {
- error = grpc_error_set_str(
- error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- uv_close((uv_handle_t*)connect->tcp_handle, tcp_close_callback);
- }
- }
- done = (--connect->refs == 0);
- if (done) {
- grpc_core::ExecCtx::Get()->Flush();
- uv_tcp_connect_cleanup(connect);
- }
- GRPC_CLOSURE_SCHED(closure, error);
-}
-
-static void tcp_client_connect_impl(grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties,
- const grpc_channel_args* channel_args,
- const grpc_resolved_address* resolved_addr,
- grpc_millis deadline) {
- grpc_uv_tcp_connect* connect;
- grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL);
- (void)channel_args;
- (void)interested_parties;
-
- GRPC_UV_ASSERT_SAME_THREAD();
-
- if (channel_args != NULL) {
- for (size_t i = 0; i < channel_args->num_args; i++) {
- if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
- grpc_resource_quota_unref_internal(resource_quota);
- resource_quota = grpc_resource_quota_ref_internal(
- (grpc_resource_quota*)channel_args->args[i].value.pointer.p);
- }
- }
- }
-
- connect = (grpc_uv_tcp_connect*)gpr_zalloc(sizeof(grpc_uv_tcp_connect));
- connect->closure = closure;
- connect->endpoint = ep;
- connect->tcp_handle = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
- connect->addr_name = grpc_sockaddr_to_uri(resolved_addr);
- connect->resource_quota = resource_quota;
- uv_tcp_init(uv_default_loop(), connect->tcp_handle);
- connect->connect_req.data = connect;
- connect->refs = 2; // One for the connect operation, one for the timer.
-
- if (grpc_tcp_trace.enabled()) {
- gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
- connect->addr_name);
- }
-
- // TODO(murgatroid99): figure out what the return value here means
- uv_tcp_connect(&connect->connect_req, connect->tcp_handle,
- (const struct sockaddr*)resolved_addr->addr, uv_tc_on_connect);
- GRPC_CLOSURE_INIT(&connect->on_alarm, uv_tc_on_alarm, connect,
- grpc_schedule_on_exec_ctx);
- grpc_timer_init(&connect->alarm, deadline, &connect->on_alarm);
-}
-
-// overridden by api_fuzzer.c
-void (*grpc_tcp_client_connect_impl)(
- grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) = tcp_client_connect_impl;
-
-void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties,
- const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) {
- grpc_tcp_client_connect_impl(closure, ep, interested_parties, channel_args,
- addr, deadline);
-}
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/tcp_client_windows.cc b/src/core/lib/iomgr/tcp_client_windows.cc
index 70c2495350..e5b5502597 100644
--- a/src/core/lib/iomgr/tcp_client_windows.cc
+++ b/src/core/lib/iomgr/tcp_client_windows.cc
@@ -122,12 +122,11 @@ static void on_connect(void* acp, grpc_error* error) {
/* Tries to issue one async connection, then schedules both an IOCP
notification request for the connection, and one timeout alert. */
-static void tcp_client_connect_impl(grpc_closure* on_done,
- grpc_endpoint** endpoint,
- grpc_pollset_set* interested_parties,
- const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) {
+static void tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint,
+ grpc_pollset_set* interested_parties,
+ const grpc_channel_args* channel_args,
+ const grpc_resolved_address* addr,
+ grpc_millis deadline) {
SOCKET sock = INVALID_SOCKET;
BOOL success;
int status;
@@ -175,7 +174,7 @@ static void tcp_client_connect_impl(grpc_closure* on_done,
grpc_sockaddr_make_wildcard6(0, &local_address);
status =
- bind(sock, (struct sockaddr*)&local_address.addr, (int)local_address.len);
+ bind(sock, (grpc_sockaddr*)&local_address.addr, (int)local_address.len);
if (status != 0) {
error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
goto failure;
@@ -183,7 +182,7 @@ static void tcp_client_connect_impl(grpc_closure* on_done,
socket = grpc_winsocket_create(sock, "client");
info = &socket->write_info;
- success = ConnectEx(sock, (struct sockaddr*)&addr->addr, (int)addr->len, NULL,
+ success = ConnectEx(sock, (grpc_sockaddr*)&addr->addr, (int)addr->len, NULL,
0, NULL, &info->overlapped);
/* It wouldn't be unusual to get a success immediately. But we'll still get
@@ -227,20 +226,6 @@ failure:
GRPC_CLOSURE_SCHED(on_done, final_error);
}
-// overridden by api_fuzzer.c
-void (*grpc_tcp_client_connect_impl)(
- grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) = tcp_client_connect_impl;
-
-void grpc_tcp_client_connect(grpc_closure* closure, grpc_endpoint** ep,
- grpc_pollset_set* interested_parties,
- const grpc_channel_args* channel_args,
- const grpc_resolved_address* addr,
- grpc_millis deadline) {
- grpc_tcp_client_connect_impl(closure, ep, interested_parties, channel_args,
- addr, deadline);
-}
+grpc_tcp_client_vtable grpc_windows_tcp_client_vtable = {tcp_connect};
#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_custom.cc b/src/core/lib/iomgr/tcp_custom.cc
new file mode 100644
index 0000000000..2b1fc93028
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_custom.cc
@@ -0,0 +1,365 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include <grpc/slice_buffer.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/network_status_tracker.h"
+#include "src/core/lib/iomgr/resource_quota.h"
+#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
+
+#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
+
+extern grpc_core::TraceFlag grpc_tcp_trace;
+
+grpc_socket_vtable* grpc_custom_socket_vtable = nullptr;
+extern grpc_tcp_server_vtable custom_tcp_server_vtable;
+extern grpc_tcp_client_vtable custom_tcp_client_vtable;
+
+void grpc_custom_endpoint_init(grpc_socket_vtable* impl) {
+ grpc_custom_socket_vtable = impl;
+ grpc_set_tcp_client_impl(&custom_tcp_client_vtable);
+ grpc_set_tcp_server_impl(&custom_tcp_server_vtable);
+}
+
+typedef struct {
+ grpc_endpoint base;
+ gpr_refcount refcount;
+ grpc_custom_socket* socket;
+
+ grpc_closure* read_cb;
+ grpc_closure* write_cb;
+
+ grpc_slice_buffer* read_slices;
+ grpc_slice_buffer* write_slices;
+
+ grpc_resource_user* resource_user;
+ grpc_resource_user_slice_allocator slice_allocator;
+
+ bool shutting_down;
+
+ char* peer_string;
+} custom_tcp_endpoint;
+
+static void tcp_free(grpc_custom_socket* s) {
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)s->endpoint;
+ grpc_resource_user_unref(tcp->resource_user);
+ gpr_free(tcp->peer_string);
+ gpr_free(tcp);
+ s->refs--;
+ if (s->refs == 0) {
+ grpc_custom_socket_vtable->destroy(s);
+ gpr_free(s);
+ }
+}
+
+#ifndef NDEBUG
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
+static void tcp_unref(custom_tcp_endpoint* tcp, const char* reason,
+ const char* file, int line) {
+ if (grpc_tcp_trace.enabled()) {
+ gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
+ gpr_log(file, line, GPR_LOG_SEVERITY_ERROR,
+ "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason,
+ val, val - 1);
+ }
+ if (gpr_unref(&tcp->refcount)) {
+ tcp_free(tcp->socket);
+ }
+}
+
+static void tcp_ref(custom_tcp_endpoint* tcp, const char* reason,
+ const char* file, int line) {
+ if (grpc_tcp_trace.enabled()) {
+ gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
+ gpr_log(file, line, GPR_LOG_SEVERITY_ERROR,
+ "TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason,
+ val, val + 1);
+ }
+ gpr_ref(&tcp->refcount);
+}
+#else
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_REF(tcp, reason) tcp_ref((tcp))
+static void tcp_unref(custom_tcp_endpoint* tcp) {
+ if (gpr_unref(&tcp->refcount)) {
+ tcp_free(tcp->socket);
+ }
+}
+
+static void tcp_ref(custom_tcp_endpoint* tcp) { gpr_ref(&tcp->refcount); }
+#endif
+
+static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) {
+ grpc_closure* cb = tcp->read_cb;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_DEBUG, "TCP:%p call_cb %p %p:%p", tcp->socket, cb, cb->cb,
+ cb->cb_arg);
+ size_t i;
+ const char* str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "read: error=%s", str);
+
+ for (i = 0; i < tcp->read_slices->count; i++) {
+ char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump);
+ gpr_free(dump);
+ }
+ }
+ TCP_UNREF(tcp, "read");
+ tcp->read_slices = nullptr;
+ tcp->read_cb = nullptr;
+ GRPC_CLOSURE_RUN(cb, error);
+}
+
+static void custom_read_callback(grpc_custom_socket* socket, size_t nread,
+ grpc_error* error) {
+ grpc_core::ExecCtx exec_ctx;
+ grpc_slice_buffer garbage;
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint;
+ if (error == GRPC_ERROR_NONE && nread == 0) {
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF");
+ }
+ if (error == GRPC_ERROR_NONE) {
+ // Successful read
+ if ((size_t)nread < tcp->read_slices->length) {
+ /* TODO(murgatroid99): Instead of discarding the unused part of the read
+ * buffer, reuse it as the next read buffer. */
+ grpc_slice_buffer_init(&garbage);
+ grpc_slice_buffer_trim_end(
+ tcp->read_slices, tcp->read_slices->length - (size_t)nread, &garbage);
+ grpc_slice_buffer_reset_and_unref_internal(&garbage);
+ }
+ } else {
+ grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
+ }
+ call_read_cb(tcp, error);
+}
+
+static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)tcpp;
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp->socket,
+ grpc_error_string(error));
+ }
+ if (error == GRPC_ERROR_NONE) {
+ /* Before calling read, we allocate a buffer with exactly one slice
+ * to tcp->read_slices and wait for the callback indicating that the
+ * allocation was successful. So slices[0] should always exist here */
+ char* buffer = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[0]);
+ size_t len = GRPC_SLICE_LENGTH(tcp->read_slices->slices[0]);
+ grpc_custom_socket_vtable->read(tcp->socket, buffer, len,
+ custom_read_callback);
+ } else {
+ grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
+ call_read_cb(tcp, GRPC_ERROR_REF(error));
+ }
+ if (grpc_tcp_trace.enabled()) {
+ const char* str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp->socket, str);
+ }
+}
+
+static void endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
+ grpc_closure* cb) {
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ GPR_ASSERT(tcp->read_cb == nullptr);
+ tcp->read_cb = cb;
+ tcp->read_slices = read_slices;
+ grpc_slice_buffer_reset_and_unref_internal(read_slices);
+ TCP_REF(tcp, "read");
+ grpc_resource_user_alloc_slices(&tcp->slice_allocator,
+ GRPC_TCP_DEFAULT_READ_SLICE_SIZE, 1,
+ tcp->read_slices);
+}
+
+static void custom_write_callback(grpc_custom_socket* socket,
+ grpc_error* error) {
+ grpc_core::ExecCtx exec_ctx;
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint;
+ grpc_closure* cb = tcp->write_cb;
+ tcp->write_cb = nullptr;
+ if (grpc_tcp_trace.enabled()) {
+ const char* str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp->socket, str);
+ }
+ TCP_UNREF(tcp, "write");
+ GRPC_CLOSURE_SCHED(cb, error);
+}
+
+static void endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* write_slices,
+ grpc_closure* cb) {
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+
+ if (grpc_tcp_trace.enabled()) {
+ size_t j;
+
+ for (j = 0; j < write_slices->count; j++) {
+ char* data = grpc_dump_slice(write_slices->slices[j],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp->socket,
+ tcp->peer_string, data);
+ gpr_free(data);
+ }
+ }
+
+ if (tcp->shutting_down) {
+ GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "TCP socket is shutting down"));
+ return;
+ }
+
+ GPR_ASSERT(tcp->write_cb == nullptr);
+ tcp->write_slices = write_slices;
+ GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
+ if (tcp->write_slices->count == 0) {
+ // No slices means we don't have to do anything,
+ // and libuv doesn't like empty writes
+ GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_NONE);
+ return;
+ }
+ tcp->write_cb = cb;
+ TCP_REF(tcp, "write");
+ grpc_custom_socket_vtable->write(tcp->socket, tcp->write_slices,
+ custom_write_callback);
+}
+
+static void endpoint_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) {
+ // No-op. We're ignoring pollsets currently
+ (void)ep;
+ (void)pollset;
+}
+
+static void endpoint_add_to_pollset_set(grpc_endpoint* ep,
+ grpc_pollset_set* pollset) {
+ // No-op. We're ignoring pollsets currently
+ (void)ep;
+ (void)pollset;
+}
+
+static void endpoint_delete_from_pollset_set(grpc_endpoint* ep,
+ grpc_pollset_set* pollset) {
+ // No-op. We're ignoring pollsets currently
+ (void)ep;
+ (void)pollset;
+}
+
+static void endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+ if (!tcp->shutting_down) {
+ if (grpc_tcp_trace.enabled()) {
+ const char* str = grpc_error_string(why);
+ gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->socket, str);
+ }
+ tcp->shutting_down = true;
+ // GRPC_CLOSURE_SCHED(tcp->read_cb, GRPC_ERROR_REF(why));
+ // GRPC_CLOSURE_SCHED(tcp->write_cb, GRPC_ERROR_REF(why));
+ // tcp->read_cb = nullptr;
+ // tcp->write_cb = nullptr;
+ grpc_resource_user_shutdown(tcp->resource_user);
+ grpc_custom_socket_vtable->shutdown(tcp->socket);
+ }
+ GRPC_ERROR_UNREF(why);
+}
+
+static void custom_close_callback(grpc_custom_socket* socket) {
+ socket->refs--;
+ if (socket->refs == 0) {
+ grpc_custom_socket_vtable->destroy(socket);
+ gpr_free(socket);
+ } else if (socket->endpoint) {
+ grpc_core::ExecCtx exec_ctx;
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint;
+ TCP_UNREF(tcp, "destroy");
+ }
+}
+
+static void endpoint_destroy(grpc_endpoint* ep) {
+ grpc_network_status_unregister_endpoint(ep);
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+ grpc_custom_socket_vtable->close(tcp->socket, custom_close_callback);
+}
+
+static char* endpoint_get_peer(grpc_endpoint* ep) {
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+ return gpr_strdup(tcp->peer_string);
+}
+
+static grpc_resource_user* endpoint_get_resource_user(grpc_endpoint* ep) {
+ custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep;
+ return tcp->resource_user;
+}
+
+static int endpoint_get_fd(grpc_endpoint* ep) { return -1; }
+
+static grpc_endpoint_vtable vtable = {endpoint_read,
+ endpoint_write,
+ endpoint_add_to_pollset,
+ endpoint_add_to_pollset_set,
+ endpoint_delete_from_pollset_set,
+ endpoint_shutdown,
+ endpoint_destroy,
+ endpoint_get_resource_user,
+ endpoint_get_peer,
+ endpoint_get_fd};
+
+grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket,
+ grpc_resource_quota* resource_quota,
+ char* peer_string) {
+ custom_tcp_endpoint* tcp =
+ (custom_tcp_endpoint*)gpr_malloc(sizeof(custom_tcp_endpoint));
+ grpc_core::ExecCtx exec_ctx;
+
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", socket);
+ }
+ memset(tcp, 0, sizeof(custom_tcp_endpoint));
+ socket->refs++;
+ socket->endpoint = (grpc_endpoint*)tcp;
+ tcp->socket = socket;
+ tcp->base.vtable = &vtable;
+ gpr_ref_init(&tcp->refcount, 1);
+ tcp->peer_string = gpr_strdup(peer_string);
+ tcp->shutting_down = false;
+ tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
+ grpc_resource_user_slice_allocator_init(
+ &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
+ /* Tell network status tracking code about the new endpoint */
+ grpc_network_status_register_endpoint(&tcp->base);
+
+ return &tcp->base;
+}
diff --git a/src/core/lib/iomgr/tcp_custom.h b/src/core/lib/iomgr/tcp_custom.h
new file mode 100644
index 0000000000..22caa149f8
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_custom.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+
+typedef struct grpc_tcp_listener grpc_tcp_listener;
+typedef struct grpc_custom_tcp_connect grpc_custom_tcp_connect;
+
+typedef struct grpc_custom_socket {
+ // Implementation defined
+ void* impl;
+ grpc_endpoint* endpoint;
+ grpc_tcp_listener* listener;
+ grpc_custom_tcp_connect* connector;
+ int refs;
+} grpc_custom_socket;
+
+typedef void (*grpc_custom_connect_callback)(grpc_custom_socket* socket,
+ grpc_error* error);
+typedef void (*grpc_custom_write_callback)(grpc_custom_socket* socket,
+ grpc_error* error);
+typedef void (*grpc_custom_read_callback)(grpc_custom_socket* socket,
+ size_t nread, grpc_error* error);
+typedef void (*grpc_custom_accept_callback)(grpc_custom_socket* socket,
+ grpc_custom_socket* client,
+ grpc_error* error);
+typedef void (*grpc_custom_close_callback)(grpc_custom_socket* socket);
+
+typedef struct grpc_socket_vtable {
+ grpc_error* (*init)(grpc_custom_socket* socket, int domain);
+ void (*connect)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
+ size_t len, grpc_custom_connect_callback cb);
+ void (*destroy)(grpc_custom_socket* socket);
+ void (*shutdown)(grpc_custom_socket* socket);
+ void (*close)(grpc_custom_socket* socket, grpc_custom_close_callback cb);
+ void (*write)(grpc_custom_socket* socket, grpc_slice_buffer* slices,
+ grpc_custom_write_callback cb);
+ void (*read)(grpc_custom_socket* socket, char* buffer, size_t length,
+ grpc_custom_read_callback cb);
+ grpc_error* (*getpeername)(grpc_custom_socket* socket,
+ const grpc_sockaddr* addr, int* len);
+ grpc_error* (*getsockname)(grpc_custom_socket* socket,
+ const grpc_sockaddr* addr, int* len);
+ grpc_error* (*setsockopt)(grpc_custom_socket* socket, int level, int optname,
+ const void* optval, uint32_t optlen);
+ grpc_error* (*bind)(grpc_custom_socket* socket, const grpc_sockaddr* addr,
+ size_t len, int flags);
+ grpc_error* (*listen)(grpc_custom_socket* socket);
+ void (*accept)(grpc_custom_socket* socket, grpc_custom_socket* client,
+ grpc_custom_accept_callback cb);
+} grpc_socket_vtable;
+
+/* Internal APIs */
+void grpc_custom_endpoint_init(grpc_socket_vtable* impl);
+
+void grpc_custom_close_server_callback(grpc_tcp_listener* listener);
+
+grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket,
+ grpc_resource_quota* resource_quota,
+ char* peer_string);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TCP_CUSTOM_H */
diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc
index ca0046b83b..205af22531 100644
--- a/src/core/lib/iomgr/tcp_posix.cc
+++ b/src/core/lib/iomgr/tcp_posix.cc
@@ -63,7 +63,7 @@ typedef GRPC_MSG_IOVLEN_TYPE msg_iovlen_type;
typedef size_t msg_iovlen_type;
#endif
-grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+extern grpc_core::TraceFlag grpc_tcp_trace;
namespace {
struct grpc_tcp {
diff --git a/src/core/lib/iomgr/tcp_server.cc b/src/core/lib/iomgr/tcp_server.cc
new file mode 100644
index 0000000000..ea745f266b
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server.cc
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/tcp_server.h"
+
+grpc_tcp_server_vtable* grpc_tcp_server_impl;
+
+grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
+ const grpc_channel_args* args,
+ grpc_tcp_server** server) {
+ return grpc_tcp_server_impl->create(shutdown_complete, args, server);
+}
+
+void grpc_tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets,
+ size_t pollset_count,
+ grpc_tcp_server_cb on_accept_cb, void* cb_arg) {
+ grpc_tcp_server_impl->start(server, pollsets, pollset_count, on_accept_cb,
+ cb_arg);
+}
+
+grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
+ const grpc_resolved_address* addr,
+ int* out_port) {
+ return grpc_tcp_server_impl->add_port(s, addr, out_port);
+}
+
+unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s,
+ unsigned port_index) {
+ return grpc_tcp_server_impl->port_fd_count(s, port_index);
+}
+
+int grpc_tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+ unsigned fd_index) {
+ return grpc_tcp_server_impl->port_fd(s, port_index, fd_index);
+}
+
+grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
+ return grpc_tcp_server_impl->ref(s);
+}
+
+void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+ grpc_closure* shutdown_starting) {
+ grpc_tcp_server_impl->shutdown_starting_add(s, shutdown_starting);
+}
+
+void grpc_tcp_server_unref(grpc_tcp_server* s) {
+ grpc_tcp_server_impl->unref(s);
+}
+
+void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {
+ grpc_tcp_server_impl->shutdown_listeners(s);
+}
+
+void grpc_set_tcp_server_impl(grpc_tcp_server_vtable* impl) {
+ grpc_tcp_server_impl = impl;
+}
diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h
index 965d97407f..8fcbb2f680 100644
--- a/src/core/lib/iomgr/tcp_server.h
+++ b/src/core/lib/iomgr/tcp_server.h
@@ -45,6 +45,24 @@ typedef void (*grpc_tcp_server_cb)(void* arg, grpc_endpoint* ep,
grpc_pollset* accepting_pollset,
grpc_tcp_server_acceptor* acceptor);
+typedef struct grpc_tcp_server_vtable {
+ grpc_error* (*create)(grpc_closure* shutdown_complete,
+ const grpc_channel_args* args,
+ grpc_tcp_server** server);
+ void (*start)(grpc_tcp_server* server, grpc_pollset** pollsets,
+ size_t pollset_count, grpc_tcp_server_cb on_accept_cb,
+ void* cb_arg);
+ grpc_error* (*add_port)(grpc_tcp_server* s, const grpc_resolved_address* addr,
+ int* out_port);
+ unsigned (*port_fd_count)(grpc_tcp_server* s, unsigned port_index);
+ int (*port_fd)(grpc_tcp_server* s, unsigned port_index, unsigned fd_index);
+ grpc_tcp_server* (*ref)(grpc_tcp_server* s);
+ void (*shutdown_starting_add)(grpc_tcp_server* s,
+ grpc_closure* shutdown_starting);
+ void (*unref)(grpc_tcp_server* s);
+ void (*shutdown_listeners)(grpc_tcp_server* s);
+} grpc_tcp_server_vtable;
+
/* Create a server, initially not bound to any ports. The caller owns one ref.
If shutdown_complete is not NULL, it will be used by
grpc_tcp_server_unref() when the ref count reaches zero. */
@@ -97,4 +115,8 @@ void grpc_tcp_server_unref(grpc_tcp_server* s);
/* Shutdown the fds of listeners. */
void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s);
+void grpc_tcp_server_global_init();
+
+void grpc_set_tcp_server_impl(grpc_tcp_server_vtable* impl);
+
#endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_H */
diff --git a/src/core/lib/iomgr/tcp_server_custom.cc b/src/core/lib/iomgr/tcp_server_custom.cc
new file mode 100644
index 0000000000..be92e61b62
--- /dev/null
+++ b/src/core/lib/iomgr/tcp_server_custom.cc
@@ -0,0 +1,479 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+
+extern grpc_core::TraceFlag grpc_tcp_trace;
+
+extern grpc_socket_vtable* grpc_custom_socket_vtable;
+
+/* one listening port */
+struct grpc_tcp_listener {
+ grpc_tcp_server* server;
+ unsigned port_index;
+ int port;
+
+ grpc_custom_socket* socket;
+
+ /* linked list */
+ struct grpc_tcp_listener* next;
+
+ bool closed;
+};
+
+struct grpc_tcp_server {
+ gpr_refcount refs;
+
+ /* Called whenever accept() succeeds on a server port. */
+ grpc_tcp_server_cb on_accept_cb;
+ void* on_accept_cb_arg;
+
+ int open_ports;
+
+ /* linked list of server ports */
+ grpc_tcp_listener* head;
+ grpc_tcp_listener* tail;
+
+ /* List of closures passed to shutdown_starting_add(). */
+ grpc_closure_list shutdown_starting;
+
+ /* shutdown callback */
+ grpc_closure* shutdown_complete;
+
+ bool shutdown;
+
+ grpc_resource_quota* resource_quota;
+};
+
+static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
+ const grpc_channel_args* args,
+ grpc_tcp_server** server) {
+ grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
+ s->resource_quota = grpc_resource_quota_create(nullptr);
+ for (size_t i = 0; i < (args == nullptr ? 0 : args->num_args); i++) {
+ if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
+ if (args->args[i].type == GRPC_ARG_POINTER) {
+ grpc_resource_quota_unref_internal(s->resource_quota);
+ s->resource_quota = grpc_resource_quota_ref_internal(
+ (grpc_resource_quota*)args->args[i].value.pointer.p);
+ } else {
+ grpc_resource_quota_unref_internal(s->resource_quota);
+ gpr_free(s);
+ return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
+ }
+ }
+ }
+ gpr_ref_init(&s->refs, 1);
+ s->on_accept_cb = nullptr;
+ s->on_accept_cb_arg = nullptr;
+ s->open_ports = 0;
+ s->head = nullptr;
+ s->tail = nullptr;
+ s->shutdown_starting.head = nullptr;
+ s->shutdown_starting.tail = nullptr;
+ s->shutdown_complete = shutdown_complete;
+ s->shutdown = false;
+ *server = s;
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_tcp_server* tcp_server_ref(grpc_tcp_server* s) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ gpr_ref(&s->refs);
+ return s;
+}
+
+static void tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+ grpc_closure* shutdown_starting) {
+ grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
+ GRPC_ERROR_NONE);
+}
+
+static void finish_shutdown(grpc_tcp_server* s) {
+ GPR_ASSERT(s->shutdown);
+ if (s->shutdown_complete != nullptr) {
+ GRPC_CLOSURE_SCHED(s->shutdown_complete, GRPC_ERROR_NONE);
+ }
+
+ while (s->head) {
+ grpc_tcp_listener* sp = s->head;
+ s->head = sp->next;
+ sp->next = nullptr;
+ gpr_free(sp);
+ }
+ grpc_resource_quota_unref_internal(s->resource_quota);
+ gpr_free(s);
+}
+
+static void custom_close_callback(grpc_custom_socket* socket) {
+ grpc_tcp_listener* sp = socket->listener;
+ if (sp) {
+ grpc_core::ExecCtx exec_ctx;
+ sp->server->open_ports--;
+ if (sp->server->open_ports == 0 && sp->server->shutdown) {
+ finish_shutdown(sp->server);
+ }
+ }
+ socket->refs--;
+ if (socket->refs == 0) {
+ grpc_custom_socket_vtable->destroy(socket);
+ gpr_free(socket);
+ }
+}
+
+void grpc_custom_close_server_callback(grpc_tcp_listener* sp) {
+ if (sp) {
+ grpc_core::ExecCtx exec_ctx;
+ sp->server->open_ports--;
+ if (sp->server->open_ports == 0 && sp->server->shutdown) {
+ finish_shutdown(sp->server);
+ }
+ }
+}
+
+static void close_listener(grpc_tcp_listener* sp) {
+ grpc_custom_socket* socket = sp->socket;
+ if (!sp->closed) {
+ sp->closed = true;
+ grpc_custom_socket_vtable->close(socket, custom_close_callback);
+ }
+}
+
+static void tcp_server_destroy(grpc_tcp_server* s) {
+ int immediately_done = 0;
+ grpc_tcp_listener* sp;
+
+ GPR_ASSERT(!s->shutdown);
+ s->shutdown = true;
+
+ if (s->open_ports == 0) {
+ immediately_done = 1;
+ }
+ for (sp = s->head; sp; sp = sp->next) {
+ close_listener(sp);
+ }
+
+ if (immediately_done) {
+ finish_shutdown(s);
+ }
+}
+
+static void tcp_server_unref(grpc_tcp_server* s) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ if (gpr_unref(&s->refs)) {
+ /* Complete shutdown_starting work before destroying. */
+ grpc_core::ExecCtx exec_ctx;
+ GRPC_CLOSURE_LIST_SCHED(&s->shutdown_starting);
+ grpc_core::ExecCtx::Get()->Flush();
+ tcp_server_destroy(s);
+ }
+}
+
+static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) {
+ grpc_tcp_server_acceptor* acceptor =
+ (grpc_tcp_server_acceptor*)gpr_malloc(sizeof(*acceptor));
+ grpc_endpoint* ep = nullptr;
+ grpc_resolved_address peer_name;
+ char* peer_name_string;
+ grpc_error* err;
+
+ peer_name_string = nullptr;
+ memset(&peer_name, 0, sizeof(grpc_resolved_address));
+ peer_name.len = GRPC_MAX_SOCKADDR_SIZE;
+ err = grpc_custom_socket_vtable->getpeername(
+ socket, (grpc_sockaddr*)&peer_name.addr, (int*)&peer_name.len);
+ if (err == GRPC_ERROR_NONE) {
+ peer_name_string = grpc_sockaddr_to_uri(&peer_name);
+ } else {
+ GRPC_LOG_IF_ERROR("getpeername error", err);
+ GRPC_ERROR_UNREF(err);
+ }
+ if (grpc_tcp_trace.enabled()) {
+ if (peer_name_string) {
+ gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s",
+ sp->server, peer_name_string);
+ } else {
+ gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server);
+ }
+ }
+ ep = custom_tcp_endpoint_create(socket, sp->server->resource_quota,
+ peer_name_string);
+ acceptor->from_server = sp->server;
+ acceptor->port_index = sp->port_index;
+ acceptor->fd_index = 0;
+ sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, nullptr, acceptor);
+ gpr_free(peer_name_string);
+}
+
+static void custom_accept_callback(grpc_custom_socket* socket,
+ grpc_custom_socket* client,
+ grpc_error* error);
+
+static void custom_accept_callback(grpc_custom_socket* socket,
+ grpc_custom_socket* client,
+ grpc_error* error) {
+ grpc_core::ExecCtx exec_ctx;
+ grpc_tcp_listener* sp = socket->listener;
+ if (error != GRPC_ERROR_NONE) {
+ if (!sp->closed) {
+ gpr_log(GPR_ERROR, "Accept failed: %s", grpc_error_string(error));
+ }
+ gpr_free(client);
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
+ finish_accept(sp, client);
+ if (!sp->closed) {
+ grpc_custom_socket* new_socket =
+ (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+ new_socket->endpoint = nullptr;
+ new_socket->listener = nullptr;
+ new_socket->connector = nullptr;
+ new_socket->refs = 1;
+ grpc_custom_socket_vtable->accept(sp->socket, new_socket,
+ custom_accept_callback);
+ }
+}
+
+static grpc_error* add_socket_to_server(grpc_tcp_server* s,
+ grpc_custom_socket* socket,
+ const grpc_resolved_address* addr,
+ unsigned port_index,
+ grpc_tcp_listener** listener) {
+ grpc_tcp_listener* sp = nullptr;
+ int port = -1;
+ grpc_error* error;
+ grpc_resolved_address sockname_temp;
+
+ // The last argument to uv_tcp_bind is flags
+ error = grpc_custom_socket_vtable->bind(socket, (grpc_sockaddr*)addr->addr,
+ addr->len, 0);
+ if (error != GRPC_ERROR_NONE) {
+ return error;
+ }
+
+ error = grpc_custom_socket_vtable->listen(socket);
+ if (error != GRPC_ERROR_NONE) {
+ return error;
+ }
+
+ sockname_temp.len = GRPC_MAX_SOCKADDR_SIZE;
+ error = grpc_custom_socket_vtable->getsockname(
+ socket, (grpc_sockaddr*)&sockname_temp.addr, (int*)&sockname_temp.len);
+ if (error != GRPC_ERROR_NONE) {
+ return error;
+ }
+
+ port = grpc_sockaddr_get_port(&sockname_temp);
+
+ GPR_ASSERT(port >= 0);
+ GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
+ sp = (grpc_tcp_listener*)gpr_zalloc(sizeof(grpc_tcp_listener));
+ sp->next = nullptr;
+ if (s->head == nullptr) {
+ s->head = sp;
+ } else {
+ s->tail->next = sp;
+ }
+ s->tail = sp;
+ sp->server = s;
+ sp->socket = socket;
+ sp->port = port;
+ sp->port_index = port_index;
+ sp->closed = false;
+ s->open_ports++;
+ *listener = sp;
+
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
+ const grpc_resolved_address* addr,
+ int* port) {
+ // This function is mostly copied from tcp_server_windows.c
+ grpc_tcp_listener* sp = nullptr;
+ grpc_custom_socket* socket;
+ grpc_resolved_address addr6_v4mapped;
+ grpc_resolved_address wildcard;
+ grpc_resolved_address* allocated_addr = nullptr;
+ grpc_resolved_address sockname_temp;
+ unsigned port_index = 0;
+ grpc_error* error = GRPC_ERROR_NONE;
+ int family;
+
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+
+ if (s->tail != nullptr) {
+ port_index = s->tail->port_index + 1;
+ }
+
+ /* Check if this is a wildcard port, and if so, try to keep the port the same
+ as some previously created listener. */
+ if (grpc_sockaddr_get_port(addr) == 0) {
+ for (sp = s->head; sp; sp = sp->next) {
+ socket = sp->socket;
+ sockname_temp.len = GRPC_MAX_SOCKADDR_SIZE;
+ if (nullptr == grpc_custom_socket_vtable->getsockname(
+ socket, (grpc_sockaddr*)&sockname_temp.addr,
+ (int*)&sockname_temp.len)) {
+ *port = grpc_sockaddr_get_port(&sockname_temp);
+ if (*port > 0) {
+ allocated_addr =
+ (grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address));
+ memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
+ grpc_sockaddr_set_port(allocated_addr, *port);
+ addr = allocated_addr;
+ break;
+ }
+ }
+ }
+ }
+
+ if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
+ addr = &addr6_v4mapped;
+ }
+
+ /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
+ if (grpc_sockaddr_is_wildcard(addr, port)) {
+ grpc_sockaddr_make_wildcard6(*port, &wildcard);
+
+ addr = &wildcard;
+ }
+
+ if (grpc_tcp_trace.enabled()) {
+ char* port_string;
+ grpc_sockaddr_to_string(&port_string, addr, 0);
+ const char* str = grpc_error_string(error);
+ if (port_string) {
+ gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str);
+ gpr_free(port_string);
+ } else {
+ gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str);
+ }
+ }
+
+ family = grpc_sockaddr_get_family(addr);
+ socket = (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+ socket->refs = 1;
+ socket->endpoint = nullptr;
+ socket->listener = nullptr;
+ socket->connector = nullptr;
+ grpc_custom_socket_vtable->init(socket, family);
+
+ if (error == GRPC_ERROR_NONE) {
+#if defined(GPR_LINUX) && defined(SO_REUSEPORT)
+ if (family == AF_INET || family == AF_INET6) {
+ int enable = 1;
+ grpc_custom_socket_vtable->setsockopt(socket, SOL_SOCKET, SO_REUSEPORT,
+ &enable, sizeof(enable));
+ }
+#endif /* GPR_LINUX && SO_REUSEPORT */
+ error = add_socket_to_server(s, socket, addr, port_index, &sp);
+ }
+ gpr_free(allocated_addr);
+
+ if (error != GRPC_ERROR_NONE) {
+ grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+ "Failed to add port to server", &error, 1);
+ GRPC_ERROR_UNREF(error);
+ error = error_out;
+ *port = -1;
+ } else {
+ GPR_ASSERT(sp != nullptr);
+ *port = sp->port;
+ }
+ socket->listener = sp;
+ return error;
+}
+
+static void tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets,
+ size_t pollset_count,
+ grpc_tcp_server_cb on_accept_cb, void* cb_arg) {
+ grpc_tcp_listener* sp;
+ (void)pollsets;
+ (void)pollset_count;
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ if (grpc_tcp_trace.enabled()) {
+ gpr_log(GPR_DEBUG, "SERVER_START %p", server);
+ }
+ GPR_ASSERT(on_accept_cb);
+ GPR_ASSERT(!server->on_accept_cb);
+ server->on_accept_cb = on_accept_cb;
+ server->on_accept_cb_arg = cb_arg;
+ for (sp = server->head; sp; sp = sp->next) {
+ grpc_custom_socket* new_socket =
+ (grpc_custom_socket*)gpr_malloc(sizeof(grpc_custom_socket));
+ new_socket->endpoint = nullptr;
+ new_socket->listener = nullptr;
+ new_socket->connector = nullptr;
+ new_socket->refs = 1;
+ grpc_custom_socket_vtable->accept(sp->socket, new_socket,
+ custom_accept_callback);
+ }
+}
+
+static unsigned tcp_server_port_fd_count(grpc_tcp_server* s,
+ unsigned port_index) {
+ return 0;
+}
+
+static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+ unsigned fd_index) {
+ return -1;
+}
+
+static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
+ for (grpc_tcp_listener* sp = s->head; sp; sp = sp->next) {
+ if (!sp->closed) {
+ sp->closed = true;
+ grpc_custom_socket_vtable->close(sp->socket, custom_close_callback);
+ }
+ }
+}
+
+grpc_tcp_server_vtable custom_tcp_server_vtable = {
+ tcp_server_create,
+ tcp_server_start,
+ tcp_server_add_port,
+ tcp_server_port_fd_count,
+ tcp_server_port_fd,
+ tcp_server_ref,
+ tcp_server_shutdown_starting_add,
+ tcp_server_unref,
+ tcp_server_shutdown_listeners};
+
+#ifdef GRPC_UV_TEST
+grpc_tcp_server_vtable* default_tcp_server_vtable = &custom_tcp_server_vtable;
+#endif
diff --git a/src/core/lib/iomgr/tcp_server_posix.cc b/src/core/lib/iomgr/tcp_server_posix.cc
index a609c09ea7..aba5d6cdb0 100644
--- a/src/core/lib/iomgr/tcp_server_posix.cc
+++ b/src/core/lib/iomgr/tcp_server_posix.cc
@@ -69,9 +69,9 @@ static void init(void) {
#endif
}
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
- const grpc_channel_args* args,
- grpc_tcp_server** server) {
+static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
+ const grpc_channel_args* args,
+ grpc_tcp_server** server) {
gpr_once_init(&check_init, init);
grpc_tcp_server* s =
@@ -392,9 +392,9 @@ static grpc_error* clone_port(grpc_tcp_listener* listener, unsigned count) {
return GRPC_ERROR_NONE;
}
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
- const grpc_resolved_address* addr,
- int* out_port) {
+static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
+ const grpc_resolved_address* addr,
+ int* out_port) {
grpc_tcp_listener* sp;
grpc_resolved_address sockname_temp;
grpc_resolved_address addr6_v4mapped;
@@ -415,7 +415,7 @@ grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
sockname_temp.len = sizeof(struct sockaddr_storage);
if (0 ==
getsockname(sp->fd,
- reinterpret_cast<struct sockaddr*>(&sockname_temp.addr),
+ reinterpret_cast<grpc_sockaddr*>(&sockname_temp.addr),
reinterpret_cast<socklen_t*>(&sockname_temp.len))) {
int used_port = grpc_sockaddr_get_port(&sockname_temp);
if (used_port > 0) {
@@ -458,8 +458,7 @@ static grpc_tcp_listener* get_port_index(grpc_tcp_server* s,
return nullptr;
}
-unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s,
- unsigned port_index) {
+unsigned tcp_server_port_fd_count(grpc_tcp_server* s, unsigned port_index) {
unsigned num_fds = 0;
gpr_mu_lock(&s->mu);
grpc_tcp_listener* sp = get_port_index(s, port_index);
@@ -470,8 +469,8 @@ unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s,
return num_fds;
}
-int grpc_tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
- unsigned fd_index) {
+static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+ unsigned fd_index) {
gpr_mu_lock(&s->mu);
grpc_tcp_listener* sp = get_port_index(s, port_index);
for (; sp; sp = sp->sibling, --fd_index) {
@@ -484,10 +483,10 @@ int grpc_tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
return -1;
}
-void grpc_tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollsets,
- size_t pollset_count,
- grpc_tcp_server_cb on_accept_cb,
- void* on_accept_cb_arg) {
+static void tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollsets,
+ size_t pollset_count,
+ grpc_tcp_server_cb on_accept_cb,
+ void* on_accept_cb_arg) {
size_t i;
grpc_tcp_listener* sp;
GPR_ASSERT(on_accept_cb);
@@ -526,20 +525,20 @@ void grpc_tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollsets,
gpr_mu_unlock(&s->mu);
}
-grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
+grpc_tcp_server* tcp_server_ref(grpc_tcp_server* s) {
gpr_ref_non_zero(&s->refs);
return s;
}
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
- grpc_closure* shutdown_starting) {
+static void tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+ grpc_closure* shutdown_starting) {
gpr_mu_lock(&s->mu);
grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
GRPC_ERROR_NONE);
gpr_mu_unlock(&s->mu);
}
-void grpc_tcp_server_unref(grpc_tcp_server* s) {
+static void tcp_server_unref(grpc_tcp_server* s) {
if (gpr_unref(&s->refs)) {
grpc_tcp_server_shutdown_listeners(s);
gpr_mu_lock(&s->mu);
@@ -549,7 +548,7 @@ void grpc_tcp_server_unref(grpc_tcp_server* s) {
}
}
-void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {
+static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {
gpr_mu_lock(&s->mu);
s->shutdown_listeners = true;
/* shutdown all fd's */
@@ -563,4 +562,14 @@ void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {
gpr_mu_unlock(&s->mu);
}
+grpc_tcp_server_vtable grpc_posix_tcp_server_vtable = {
+ tcp_server_create,
+ tcp_server_start,
+ tcp_server_add_port,
+ tcp_server_port_fd_count,
+ tcp_server_port_fd,
+ tcp_server_ref,
+ tcp_server_shutdown_starting_add,
+ tcp_server_unref,
+ tcp_server_shutdown_listeners};
#endif
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
index 846f9cccb7..76d3d62940 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
@@ -171,8 +171,7 @@ grpc_error* grpc_tcp_server_prepare_socket(int fd,
if (err != GRPC_ERROR_NONE) goto error;
GPR_ASSERT(addr->len < ~(socklen_t)0);
- if (bind(fd,
- reinterpret_cast<struct sockaddr*>(const_cast<char*>(addr->addr)),
+ if (bind(fd, reinterpret_cast<grpc_sockaddr*>(const_cast<char*>(addr->addr)),
static_cast<socklen_t>(addr->len)) < 0) {
err = GRPC_OS_ERROR(errno, "bind");
goto error;
@@ -185,7 +184,7 @@ grpc_error* grpc_tcp_server_prepare_socket(int fd,
sockname_temp.len = sizeof(struct sockaddr_storage);
- if (getsockname(fd, reinterpret_cast<struct sockaddr*>(sockname_temp.addr),
+ if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
reinterpret_cast<socklen_t*>(&sockname_temp.len)) < 0) {
err = GRPC_OS_ERROR(errno, "getsockname");
goto error;
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc b/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
index 308ff0f8a6..29ff9ecda1 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
@@ -68,13 +68,13 @@ static grpc_error* get_unused_port(int* port) {
if (dsmode == GRPC_DSMODE_IPV4) {
grpc_sockaddr_make_wildcard4(0, &wild);
}
- if (bind(fd, reinterpret_cast<const struct sockaddr*>(wild.addr),
+ if (bind(fd, reinterpret_cast<const grpc_sockaddr*>(wild.addr),
static_cast<socklen_t>(wild.len)) != 0) {
err = GRPC_OS_ERROR(errno, "bind");
close(fd);
return err;
}
- if (getsockname(fd, reinterpret_cast<struct sockaddr*>(wild.addr),
+ if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(wild.addr),
reinterpret_cast<socklen_t*>(&wild.len)) != 0) {
err = GRPC_OS_ERROR(errno, "getsockname");
close(fd);
@@ -119,9 +119,9 @@ grpc_error* grpc_tcp_server_add_all_local_addrs(grpc_tcp_server* s,
if (ifa_it->ifa_addr == nullptr) {
continue;
} else if (ifa_it->ifa_addr->sa_family == AF_INET) {
- addr.len = sizeof(struct sockaddr_in);
+ addr.len = sizeof(grpc_sockaddr_in);
} else if (ifa_it->ifa_addr->sa_family == AF_INET6) {
- addr.len = sizeof(struct sockaddr_in6);
+ addr.len = sizeof(grpc_sockaddr_in6);
} else {
continue;
}
diff --git a/src/core/lib/iomgr/tcp_server_uv.cc b/src/core/lib/iomgr/tcp_server_uv.cc
deleted file mode 100644
index aa423766c7..0000000000
--- a/src/core/lib/iomgr/tcp_server_uv.cc
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-
-#include <assert.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
-#include "src/core/lib/iomgr/sockaddr.h"
-#include "src/core/lib/iomgr/sockaddr_utils.h"
-#include "src/core/lib/iomgr/tcp_server.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
-
-/* one listening port */
-typedef struct grpc_tcp_listener grpc_tcp_listener;
-struct grpc_tcp_listener {
- uv_tcp_t* handle;
- grpc_tcp_server* server;
- unsigned port_index;
- int port;
- /* linked list */
- struct grpc_tcp_listener* next;
-
- bool closed;
-
- bool has_pending_connection;
-};
-
-struct grpc_tcp_server {
- gpr_refcount refs;
-
- /* Called whenever accept() succeeds on a server port. */
- grpc_tcp_server_cb on_accept_cb;
- void* on_accept_cb_arg;
-
- int open_ports;
-
- /* linked list of server ports */
- grpc_tcp_listener* head;
- grpc_tcp_listener* tail;
-
- /* List of closures passed to shutdown_starting_add(). */
- grpc_closure_list shutdown_starting;
-
- /* shutdown callback */
- grpc_closure* shutdown_complete;
-
- bool shutdown;
-
- grpc_resource_quota* resource_quota;
-};
-
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
- const grpc_channel_args* args,
- grpc_tcp_server** server) {
- grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
- s->resource_quota = grpc_resource_quota_create(NULL);
- for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
- if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
- if (args->args[i].type == GRPC_ARG_POINTER) {
- grpc_resource_quota_unref_internal(s->resource_quota);
- s->resource_quota = grpc_resource_quota_ref_internal(
- (grpc_resource_quota*)args->args[i].value.pointer.p);
- } else {
- grpc_resource_quota_unref_internal(s->resource_quota);
- gpr_free(s);
- return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
- }
- }
- }
- gpr_ref_init(&s->refs, 1);
- s->on_accept_cb = NULL;
- s->on_accept_cb_arg = NULL;
- s->open_ports = 0;
- s->head = NULL;
- s->tail = NULL;
- s->shutdown_starting.head = NULL;
- s->shutdown_starting.tail = NULL;
- s->shutdown_complete = shutdown_complete;
- s->shutdown = false;
- *server = s;
- return GRPC_ERROR_NONE;
-}
-
-grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
- GRPC_UV_ASSERT_SAME_THREAD();
- gpr_ref(&s->refs);
- return s;
-}
-
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
- grpc_closure* shutdown_starting) {
- grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
- GRPC_ERROR_NONE);
-}
-
-static void finish_shutdown(grpc_tcp_server* s) {
- GPR_ASSERT(s->shutdown);
- if (s->shutdown_complete != NULL) {
- GRPC_CLOSURE_SCHED(s->shutdown_complete, GRPC_ERROR_NONE);
- }
-
- while (s->head) {
- grpc_tcp_listener* sp = s->head;
- s->head = sp->next;
- sp->next = NULL;
- gpr_free(sp->handle);
- gpr_free(sp);
- }
- grpc_resource_quota_unref_internal(s->resource_quota);
- gpr_free(s);
-}
-
-static void handle_close_callback(uv_handle_t* handle) {
- grpc_tcp_listener* sp = (grpc_tcp_listener*)handle->data;
- grpc_core::ExecCtx exec_ctx;
- sp->server->open_ports--;
- if (sp->server->open_ports == 0 && sp->server->shutdown) {
- finish_shutdown(sp->server);
- }
-}
-
-static void close_listener(grpc_tcp_listener* sp) {
- if (!sp->closed) {
- sp->closed = true;
- uv_close((uv_handle_t*)sp->handle, handle_close_callback);
- }
-}
-
-static void tcp_server_destroy(grpc_tcp_server* s) {
- int immediately_done = 0;
- grpc_tcp_listener* sp;
-
- GPR_ASSERT(!s->shutdown);
- s->shutdown = true;
-
- if (s->open_ports == 0) {
- immediately_done = 1;
- }
- for (sp = s->head; sp; sp = sp->next) {
- close_listener(sp);
- }
-
- if (immediately_done) {
- finish_shutdown(s);
- }
-}
-
-void grpc_tcp_server_unref(grpc_tcp_server* s) {
- GRPC_UV_ASSERT_SAME_THREAD();
- if (gpr_unref(&s->refs)) {
- /* Complete shutdown_starting work before destroying. */
- grpc_core::ExecCtx exec_ctx;
- GRPC_CLOSURE_LIST_SCHED(&s->shutdown_starting);
- grpc_core::ExecCtx::Get()->Flush();
- tcp_server_destroy(s);
- }
-}
-
-static void finish_accept(grpc_tcp_listener* sp) {
- grpc_tcp_server_acceptor* acceptor =
- (grpc_tcp_server_acceptor*)gpr_malloc(sizeof(*acceptor));
- uv_tcp_t* client = NULL;
- grpc_endpoint* ep = NULL;
- grpc_resolved_address peer_name;
- char* peer_name_string;
- int err;
- uv_tcp_t* server = sp->handle;
-
- client = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
- uv_tcp_init(uv_default_loop(), client);
- // UV documentation says this is guaranteed to succeed
- uv_accept((uv_stream_t*)server, (uv_stream_t*)client);
- peer_name_string = NULL;
- memset(&peer_name, 0, sizeof(grpc_resolved_address));
- peer_name.len = sizeof(struct sockaddr_storage);
- err = uv_tcp_getpeername(client, (struct sockaddr*)&peer_name.addr,
- (int*)&peer_name.len);
- if (err == 0) {
- peer_name_string = grpc_sockaddr_to_uri(&peer_name);
- } else {
- gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(err));
- }
- if (grpc_tcp_trace.enabled()) {
- if (peer_name_string) {
- gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s",
- sp->server, peer_name_string);
- } else {
- gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection", sp->server);
- }
- }
- ep = grpc_tcp_create(client, sp->server->resource_quota, peer_name_string);
- acceptor->from_server = sp->server;
- acceptor->port_index = sp->port_index;
- acceptor->fd_index = 0;
- sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, NULL, acceptor);
- gpr_free(peer_name_string);
-}
-
-static void on_connect(uv_stream_t* server, int status) {
- grpc_tcp_listener* sp = (grpc_tcp_listener*)server->data;
- grpc_core::ExecCtx exec_ctx;
-
- if (status < 0) {
- switch (status) {
- case UV_EINTR:
- case UV_EAGAIN:
- return;
- default:
- close_listener(sp);
- return;
- }
- }
-
- GPR_ASSERT(!sp->has_pending_connection);
-
- if (grpc_tcp_trace.enabled()) {
- gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server);
- }
-
- // Create acceptor.
- if (sp->server->on_accept_cb) {
- finish_accept(sp);
- } else {
- sp->has_pending_connection = true;
- }
-}
-
-static grpc_error* add_addr_to_server(grpc_tcp_server* s,
- const grpc_resolved_address* addr,
- unsigned port_index,
- grpc_tcp_listener** listener) {
- grpc_tcp_listener* sp = NULL;
- int port = -1;
- int status;
- grpc_error* error;
- grpc_resolved_address sockname_temp;
- uv_tcp_t* handle = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
- int family = grpc_sockaddr_get_family(addr);
-
- status = uv_tcp_init_ex(uv_default_loop(), handle, (unsigned int)family);
-#if defined(GPR_LINUX) && defined(SO_REUSEPORT)
- if (family == AF_INET || family == AF_INET6) {
- int fd;
- uv_fileno((uv_handle_t*)handle, &fd);
- int enable = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
- }
-#endif /* GPR_LINUX && SO_REUSEPORT */
-
- if (status != 0) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Failed to initialize UV tcp handle");
- error =
- grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- return error;
- }
-
- // The last argument to uv_tcp_bind is flags
- status = uv_tcp_bind(handle, (struct sockaddr*)addr->addr, 0);
- if (status != 0) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to bind to port");
- error =
- grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- return error;
- }
-
- status = uv_listen((uv_stream_t*)handle, SOMAXCONN, on_connect);
- if (status != 0) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to listen to port");
- error =
- grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- return error;
- }
-
- sockname_temp.len = (int)sizeof(struct sockaddr_storage);
- status = uv_tcp_getsockname(handle, (struct sockaddr*)&sockname_temp.addr,
- (int*)&sockname_temp.len);
- if (status != 0) {
- error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("getsockname failed");
- error =
- grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- return error;
- }
-
- port = grpc_sockaddr_get_port(&sockname_temp);
-
- GPR_ASSERT(port >= 0);
- GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
- sp = (grpc_tcp_listener*)gpr_zalloc(sizeof(grpc_tcp_listener));
- sp->next = NULL;
- if (s->head == NULL) {
- s->head = sp;
- } else {
- s->tail->next = sp;
- }
- s->tail = sp;
- sp->server = s;
- sp->handle = handle;
- sp->port = port;
- sp->port_index = port_index;
- sp->closed = false;
- handle->data = sp;
- s->open_ports++;
- GPR_ASSERT(sp->handle);
- *listener = sp;
-
- return GRPC_ERROR_NONE;
-}
-
-static grpc_error* add_wildcard_addrs_to_server(grpc_tcp_server* s,
- unsigned port_index,
- int requested_port,
- grpc_tcp_listener** listener) {
- grpc_resolved_address wild4;
- grpc_resolved_address wild6;
- grpc_tcp_listener* sp = nullptr;
- grpc_tcp_listener* sp2 = nullptr;
- grpc_error* v6_err = GRPC_ERROR_NONE;
- grpc_error* v4_err = GRPC_ERROR_NONE;
-
- grpc_sockaddr_make_wildcards(requested_port, &wild4, &wild6);
- /* Try listening on IPv6 first. */
- if ((v6_err = add_addr_to_server(s, &wild6, port_index, &sp)) ==
- GRPC_ERROR_NONE) {
- *listener = sp;
- return GRPC_ERROR_NONE;
- }
-
- if ((v4_err = add_addr_to_server(s, &wild4, port_index, &sp2)) ==
- GRPC_ERROR_NONE) {
- *listener = sp2;
- return GRPC_ERROR_NONE;
- }
-
- grpc_error* root_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "Failed to add any wildcard listeners");
- root_err = grpc_error_add_child(root_err, v6_err);
- root_err = grpc_error_add_child(root_err, v4_err);
- return root_err;
-}
-
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
- const grpc_resolved_address* addr,
- int* port) {
- // This function is mostly copied from tcp_server_windows.c
- grpc_tcp_listener* sp = NULL;
- grpc_resolved_address addr6_v4mapped;
- grpc_resolved_address* allocated_addr = NULL;
- grpc_resolved_address sockname_temp;
- unsigned port_index = 0;
- grpc_error* error = GRPC_ERROR_NONE;
-
- GRPC_UV_ASSERT_SAME_THREAD();
-
- if (s->tail != NULL) {
- port_index = s->tail->port_index + 1;
- }
-
- /* Check if this is a wildcard port, and if so, try to keep the port the same
- as some previously created listener. */
- if (grpc_sockaddr_get_port(addr) == 0) {
- for (sp = s->head; sp; sp = sp->next) {
- sockname_temp.len = sizeof(struct sockaddr_storage);
- if (0 == uv_tcp_getsockname(sp->handle,
- (struct sockaddr*)&sockname_temp.addr,
- (int*)&sockname_temp.len)) {
- *port = grpc_sockaddr_get_port(&sockname_temp);
- if (*port > 0) {
- allocated_addr =
- (grpc_resolved_address*)gpr_malloc(sizeof(grpc_resolved_address));
- memcpy(allocated_addr, addr, sizeof(grpc_resolved_address));
- grpc_sockaddr_set_port(allocated_addr, *port);
- addr = allocated_addr;
- break;
- }
- }
- }
- }
-
- /* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
- if (grpc_sockaddr_is_wildcard(addr, port)) {
- error = add_wildcard_addrs_to_server(s, port_index, *port, &sp);
- } else {
- if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
- addr = &addr6_v4mapped;
- }
-
- error = add_addr_to_server(s, addr, port_index, &sp);
- }
-
- gpr_free(allocated_addr);
-
- if (grpc_tcp_trace.enabled()) {
- char* port_string;
- grpc_sockaddr_to_string(&port_string, addr, 0);
- const char* str = grpc_error_string(error);
- if (port_string) {
- gpr_log(GPR_DEBUG, "SERVER %p add_port %s error=%s", s, port_string, str);
- gpr_free(port_string);
- } else {
- gpr_log(GPR_DEBUG, "SERVER %p add_port error=%s", s, str);
- }
- }
-
- if (error != GRPC_ERROR_NONE) {
- grpc_error* error_out = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
- "Failed to add port to server", &error, 1);
- GRPC_ERROR_UNREF(error);
- error = error_out;
- *port = -1;
- } else {
- GPR_ASSERT(sp != NULL);
- *port = sp->port;
- }
- return error;
-}
-
-void grpc_tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets,
- size_t pollset_count,
- grpc_tcp_server_cb on_accept_cb, void* cb_arg) {
- grpc_tcp_listener* sp;
- (void)pollsets;
- (void)pollset_count;
- GRPC_UV_ASSERT_SAME_THREAD();
- if (grpc_tcp_trace.enabled()) {
- gpr_log(GPR_DEBUG, "SERVER_START %p", server);
- }
- GPR_ASSERT(on_accept_cb);
- GPR_ASSERT(!server->on_accept_cb);
- server->on_accept_cb = on_accept_cb;
- server->on_accept_cb_arg = cb_arg;
- for (sp = server->head; sp; sp = sp->next) {
- if (sp->has_pending_connection) {
- finish_accept(sp);
- sp->has_pending_connection = false;
- }
- }
-}
-
-void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {}
-
-#endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/tcp_server_windows.cc b/src/core/lib/iomgr/tcp_server_windows.cc
index 6d19c1c4d7..77f3811dca 100644
--- a/src/core/lib/iomgr/tcp_server_windows.cc
+++ b/src/core/lib/iomgr/tcp_server_windows.cc
@@ -50,7 +50,7 @@ typedef struct grpc_tcp_listener grpc_tcp_listener;
struct grpc_tcp_listener {
/* This seemingly magic number comes from AcceptEx's documentation. each
address buffer needs to have at least 16 more bytes at their end. */
- uint8_t addresses[(sizeof(struct sockaddr_in6) + 16) * 2];
+ uint8_t addresses[(sizeof(grpc_sockaddr_in6) + 16) * 2];
/* This will hold the socket for the next accept. */
SOCKET new_socket;
/* The listener winsocket. */
@@ -96,9 +96,9 @@ struct grpc_tcp_server {
/* Public function. Allocates the proper data structures to hold a
grpc_tcp_server. */
-grpc_error* grpc_tcp_server_create(grpc_closure* shutdown_complete,
- const grpc_channel_args* args,
- grpc_tcp_server** server) {
+static grpc_error* tcp_server_create(grpc_closure* shutdown_complete,
+ const grpc_channel_args* args,
+ grpc_tcp_server** server) {
grpc_tcp_server* s = (grpc_tcp_server*)gpr_malloc(sizeof(grpc_tcp_server));
s->channel_args = grpc_channel_args_copy(args);
gpr_ref_init(&s->refs, 1);
@@ -142,13 +142,13 @@ static void finish_shutdown_locked(grpc_tcp_server* s) {
GRPC_ERROR_NONE);
}
-grpc_tcp_server* grpc_tcp_server_ref(grpc_tcp_server* s) {
+static grpc_tcp_server* tcp_server_ref(grpc_tcp_server* s) {
gpr_ref_non_zero(&s->refs);
return s;
}
-void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server* s,
- grpc_closure* shutdown_starting) {
+static void tcp_server_shutdown_starting_add(grpc_tcp_server* s,
+ grpc_closure* shutdown_starting) {
gpr_mu_lock(&s->mu);
grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
GRPC_ERROR_NONE);
@@ -172,7 +172,7 @@ static void tcp_server_destroy(grpc_tcp_server* s) {
gpr_mu_unlock(&s->mu);
}
-void grpc_tcp_server_unref(grpc_tcp_server* s) {
+static void tcp_server_unref(grpc_tcp_server* s) {
if (gpr_unref(&s->refs)) {
grpc_tcp_server_shutdown_listeners(s);
gpr_mu_lock(&s->mu);
@@ -195,7 +195,7 @@ static grpc_error* prepare_socket(SOCKET sock,
goto failure;
}
- if (bind(sock, (const struct sockaddr*)addr->addr, (int)addr->len) ==
+ if (bind(sock, (const grpc_sockaddr*)addr->addr, (int)addr->len) ==
SOCKET_ERROR) {
error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
goto failure;
@@ -207,7 +207,7 @@ static grpc_error* prepare_socket(SOCKET sock,
}
sockname_temp_len = sizeof(struct sockaddr_storage);
- if (getsockname(sock, (struct sockaddr*)sockname_temp.addr,
+ if (getsockname(sock, (grpc_sockaddr*)sockname_temp.addr,
&sockname_temp_len) == SOCKET_ERROR) {
error = GRPC_WSA_ERROR(WSAGetLastError(), "getsockname");
goto failure;
@@ -245,7 +245,7 @@ static void decrement_active_ports_and_notify_locked(grpc_tcp_listener* sp) {
static grpc_error* start_accept_locked(grpc_tcp_listener* port) {
SOCKET sock = INVALID_SOCKET;
BOOL success;
- DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
+ DWORD addrlen = sizeof(grpc_sockaddr_in6) + 16;
DWORD bytes_received = 0;
grpc_error* error = GRPC_ERROR_NONE;
@@ -343,7 +343,7 @@ static void on_accept(void* arg, grpc_error* error) {
gpr_free(utf8_message);
}
int peer_name_len = (int)peer_name.len;
- err = getpeername(sock, (struct sockaddr*)peer_name.addr, &peer_name_len);
+ err = getpeername(sock, (grpc_sockaddr*)peer_name.addr, &peer_name_len);
peer_name.len = (size_t)peer_name_len;
if (!err) {
peer_name_string = grpc_sockaddr_to_uri(&peer_name);
@@ -442,9 +442,9 @@ static grpc_error* add_socket_to_server(grpc_tcp_server* s, SOCKET sock,
return GRPC_ERROR_NONE;
}
-grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
- const grpc_resolved_address* addr,
- int* port) {
+static grpc_error* tcp_server_add_port(grpc_tcp_server* s,
+ const grpc_resolved_address* addr,
+ int* port) {
grpc_tcp_listener* sp = NULL;
SOCKET sock;
grpc_resolved_address addr6_v4mapped;
@@ -464,7 +464,7 @@ grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s,
for (sp = s->head; sp; sp = sp->next) {
int sockname_temp_len = sizeof(struct sockaddr_storage);
if (0 == getsockname(sp->socket->socket,
- (struct sockaddr*)sockname_temp.addr,
+ (grpc_sockaddr*)sockname_temp.addr,
&sockname_temp_len)) {
sockname_temp.len = (size_t)sockname_temp_len;
*port = grpc_sockaddr_get_port(&sockname_temp);
@@ -516,10 +516,10 @@ done:
return error;
}
-void grpc_tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollset,
- size_t pollset_count,
- grpc_tcp_server_cb on_accept_cb,
- void* on_accept_cb_arg) {
+static void tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollset,
+ size_t pollset_count,
+ grpc_tcp_server_cb on_accept_cb,
+ void* on_accept_cb_arg) {
grpc_tcp_listener* sp;
GPR_ASSERT(on_accept_cb);
gpr_mu_lock(&s->mu);
@@ -534,6 +534,26 @@ void grpc_tcp_server_start(grpc_tcp_server* s, grpc_pollset** pollset,
gpr_mu_unlock(&s->mu);
}
-void grpc_tcp_server_shutdown_listeners(grpc_tcp_server* s) {}
+static unsigned tcp_server_port_fd_count(grpc_tcp_server* s,
+ unsigned port_index) {
+ return 0;
+}
+
+static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index,
+ unsigned fd_index) {
+ return -1;
+}
+static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {}
+
+grpc_tcp_server_vtable grpc_windows_tcp_server_vtable = {
+ tcp_server_create,
+ tcp_server_start,
+ tcp_server_add_port,
+ tcp_server_port_fd_count,
+ tcp_server_port_fd,
+ tcp_server_ref,
+ tcp_server_shutdown_starting_add,
+ tcp_server_unref,
+ tcp_server_shutdown_listeners};
#endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_uv.cc b/src/core/lib/iomgr/tcp_uv.cc
index 6db3217d6e..5e3166926b 100644
--- a/src/core/lib/iomgr/tcp_uv.cc
+++ b/src/core/lib/iomgr/tcp_uv.cc
@@ -21,7 +21,6 @@
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_UV
-
#include <limits.h>
#include <string.h>
@@ -33,393 +32,393 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
#include "src/core/lib/iomgr/network_status_tracker.h"
+#include "src/core/lib/iomgr/resolve_address_custom.h"
#include "src/core/lib/iomgr/resource_quota.h"
-#include "src/core/lib/iomgr/tcp_uv.h"
+#include "src/core/lib/iomgr/tcp_custom.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
-grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+#include <uv.h>
-typedef struct {
- grpc_endpoint base;
- gpr_refcount refcount;
+#define IGNORE_CONST(addr) ((grpc_sockaddr*)(uintptr_t)(addr))
+typedef struct uv_socket_t {
+ uv_connect_t connect_req;
uv_write_t write_req;
uv_shutdown_t shutdown_req;
-
uv_tcp_t* handle;
-
- grpc_closure* read_cb;
- grpc_closure* write_cb;
-
- grpc_slice_buffer* read_slices;
- grpc_slice_buffer* write_slices;
uv_buf_t* write_buffers;
- grpc_resource_user* resource_user;
- grpc_resource_user_slice_allocator slice_allocator;
-
- bool shutting_down;
+ char* read_buf;
+ size_t read_len;
- char* peer_string;
- grpc_pollset* pollset;
-} grpc_tcp;
+ bool pending_connection;
+ grpc_custom_socket* accept_socket;
+ grpc_error* accept_error;
-static grpc_error* tcp_annotate_error(grpc_error* src_error, grpc_tcp* tcp) {
- return grpc_error_set_str(
- grpc_error_set_int(
- src_error,
- /* All tcp errors are marked with UNAVAILABLE so that application may
- * choose to retry. */
- GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
- GRPC_ERROR_STR_TARGET_ADDRESS,
- grpc_slice_from_copied_string(tcp->peer_string));
-}
+ grpc_custom_connect_callback connect_cb;
+ grpc_custom_write_callback write_cb;
+ grpc_custom_read_callback read_cb;
+ grpc_custom_accept_callback accept_cb;
+ grpc_custom_close_callback close_cb;
-static void tcp_free(grpc_tcp* tcp) {
- grpc_resource_user_unref(tcp->resource_user);
- gpr_free(tcp->handle);
- gpr_free(tcp->peer_string);
- gpr_free(tcp);
-}
-
-#ifndef NDEBUG
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
-#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
-static void tcp_unref(grpc_tcp* tcp, const char* reason, const char* file,
- int line) {
- if (grpc_tcp_trace.enabled()) {
- gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
- val - 1);
- }
- if (gpr_unref(&tcp->refcount)) {
- tcp_free(tcp);
- }
-}
+} uv_socket_t;
-static void tcp_ref(grpc_tcp* tcp, const char* reason, const char* file,
- int line) {
- if (grpc_tcp_trace.enabled()) {
- gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
- val + 1);
- }
- gpr_ref(&tcp->refcount);
-}
-#else
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
-#define TCP_REF(tcp, reason) tcp_ref((tcp))
-static void tcp_unref(grpc_tcp* tcp) {
- if (gpr_unref(&tcp->refcount)) {
- tcp_free(tcp);
+static grpc_error* tcp_error_create(const char* desc, int status) {
+ if (status == 0) {
+ return GRPC_ERROR_NONE;
}
+ grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc);
+ /* All tcp errors are marked with UNAVAILABLE so that application may
+ * choose to retry. */
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
+ GRPC_STATUS_UNAVAILABLE);
+ return grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
+ grpc_slice_from_static_string(uv_strerror(status)));
}
-static void tcp_ref(grpc_tcp* tcp) { gpr_ref(&tcp->refcount); }
-#endif
-
-static void uv_close_callback(uv_handle_t* handle) {
- grpc_core::ExecCtx exec_ctx;
- grpc_tcp* tcp = (grpc_tcp*)handle->data;
- TCP_UNREF(tcp, "destroy");
+static void uv_socket_destroy(grpc_custom_socket* socket) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ gpr_free(uv_socket->handle);
+ gpr_free(uv_socket);
}
static void alloc_uv_buf(uv_handle_t* handle, size_t suggested_size,
uv_buf_t* buf) {
- grpc_core::ExecCtx exec_ctx;
- grpc_tcp* tcp = (grpc_tcp*)handle->data;
+ uv_socket_t* uv_socket =
+ (uv_socket_t*)((grpc_custom_socket*)handle->data)->impl;
(void)suggested_size;
- /* Before calling uv_read_start, we allocate a buffer with exactly one slice
- * to tcp->read_slices and wait for the callback indicating that the
- * allocation was successful. So slices[0] should always exist here */
- buf->base = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[0]);
- buf->len = GRPC_SLICE_LENGTH(tcp->read_slices->slices[0]);
-}
-
-static void call_read_cb(grpc_tcp* tcp, grpc_error* error) {
- grpc_closure* cb = tcp->read_cb;
- if (grpc_tcp_trace.enabled()) {
- gpr_log(GPR_DEBUG, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg);
- size_t i;
- const char* str = grpc_error_string(error);
- gpr_log(GPR_DEBUG, "read: error=%s", str);
-
- for (i = 0; i < tcp->read_slices->count; i++) {
- char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
- GPR_DUMP_HEX | GPR_DUMP_ASCII);
- gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump);
- gpr_free(dump);
- }
- }
- tcp->read_slices = NULL;
- tcp->read_cb = NULL;
- GRPC_CLOSURE_RUN(cb, error);
+ buf->base = uv_socket->read_buf;
+ buf->len = uv_socket->read_len;
}
-static void read_callback(uv_stream_t* stream, ssize_t nread,
- const uv_buf_t* buf) {
- grpc_error* error;
- grpc_core::ExecCtx exec_ctx;
- grpc_tcp* tcp = (grpc_tcp*)stream->data;
- grpc_slice_buffer garbage;
+static void uv_read_callback(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf) {
+ grpc_error* error = GRPC_ERROR_NONE;
if (nread == 0) {
// Nothing happened. Wait for the next callback
return;
}
- TCP_UNREF(tcp, "read");
// TODO(murgatroid99): figure out what the return value here means
uv_read_stop(stream);
if (nread == UV_EOF) {
- error =
- tcp_annotate_error(GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF"), tcp);
- grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
- } else if (nread > 0) {
- // Successful read
- error = GRPC_ERROR_NONE;
- if ((size_t)nread < tcp->read_slices->length) {
- /* TODO(murgatroid99): Instead of discarding the unused part of the read
- * buffer, reuse it as the next read buffer. */
- grpc_slice_buffer_init(&garbage);
- grpc_slice_buffer_trim_end(
- tcp->read_slices, tcp->read_slices->length - (size_t)nread, &garbage);
- grpc_slice_buffer_reset_and_unref_internal(&garbage);
- }
- } else {
- // nread < 0: Error
- error = tcp_annotate_error(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed"), tcp);
- grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF");
+ } else if (nread < 0) {
+ error = tcp_error_create("TCP Read failed", nread);
}
- call_read_cb(tcp, error);
+ grpc_custom_socket* socket = (grpc_custom_socket*)stream->data;
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ uv_socket->read_cb(socket, (size_t)nread, error);
}
-static void tcp_read_allocation_done(void* tcpp, grpc_error* error) {
- int status;
- grpc_tcp* tcp = (grpc_tcp*)tcpp;
- if (grpc_tcp_trace.enabled()) {
- gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp,
- grpc_error_string(error));
- }
- if (error == GRPC_ERROR_NONE) {
- status =
- uv_read_start((uv_stream_t*)tcp->handle, alloc_uv_buf, read_callback);
- if (status != 0) {
- error = tcp_annotate_error(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed at start"),
- tcp);
- error = grpc_error_set_str(
- error, GRPC_ERROR_STR_OS_ERROR,
- grpc_slice_from_static_string(uv_strerror(status)));
- }
- }
- if (error != GRPC_ERROR_NONE) {
- grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices);
- call_read_cb(tcp, GRPC_ERROR_REF(error));
- TCP_UNREF(tcp, "read");
+static void uv_close_callback(uv_handle_t* handle) {
+ grpc_custom_socket* socket = (grpc_custom_socket*)handle->data;
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ if (uv_socket->accept_socket) {
+ uv_socket->accept_cb(socket, uv_socket->accept_socket,
+ GRPC_ERROR_CREATE_FROM_STATIC_STRING("socket closed"));
}
- if (grpc_tcp_trace.enabled()) {
- const char* str = grpc_error_string(error);
- gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp, str);
+ uv_socket->close_cb(socket);
+}
+
+static void uv_socket_read(grpc_custom_socket* socket, char* buffer,
+ size_t length, grpc_custom_read_callback read_cb) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ int status;
+ grpc_error* error;
+ uv_socket->read_cb = read_cb;
+ uv_socket->read_buf = buffer;
+ uv_socket->read_len = length;
+ // TODO(murgatroid99): figure out what the return value here means
+ status =
+ uv_read_start((uv_stream_t*)uv_socket->handle, (uv_alloc_cb)alloc_uv_buf,
+ (uv_read_cb)uv_read_callback);
+ if (status != 0) {
+ error = tcp_error_create("TCP Read failed at start", status);
+ uv_socket->read_cb(socket, 0, error);
}
}
-static void uv_endpoint_read(grpc_endpoint* ep, grpc_slice_buffer* read_slices,
- grpc_closure* cb) {
- grpc_tcp* tcp = (grpc_tcp*)ep;
- GRPC_UV_ASSERT_SAME_THREAD();
- GPR_ASSERT(tcp->read_cb == NULL);
- tcp->read_cb = cb;
- tcp->read_slices = read_slices;
- grpc_slice_buffer_reset_and_unref_internal(read_slices);
- TCP_REF(tcp, "read");
- grpc_resource_user_alloc_slices(&tcp->slice_allocator,
- GRPC_TCP_DEFAULT_READ_SLICE_SIZE, 1,
- tcp->read_slices);
+static void uv_write_callback(uv_write_t* req, int status) {
+ grpc_custom_socket* socket = (grpc_custom_socket*)req->data;
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ gpr_free(uv_socket->write_buffers);
+ uv_socket->write_cb(socket, tcp_error_create("TCP Write failed", status));
}
-static void write_callback(uv_write_t* req, int status) {
- grpc_tcp* tcp = (grpc_tcp*)req->data;
- grpc_error* error;
- grpc_core::ExecCtx exec_ctx;
- grpc_closure* cb = tcp->write_cb;
- tcp->write_cb = NULL;
- TCP_UNREF(tcp, "write");
- if (status == 0) {
- error = GRPC_ERROR_NONE;
- } else {
- error = tcp_annotate_error(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Write failed"), tcp);
- }
- if (grpc_tcp_trace.enabled()) {
- const char* str = grpc_error_string(error);
- gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp, str);
+void uv_socket_write(grpc_custom_socket* socket,
+ grpc_slice_buffer* write_slices,
+ grpc_custom_write_callback write_cb) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ uv_socket->write_cb = write_cb;
+ uv_buf_t* uv_buffers;
+ uv_write_t* write_req;
+
+ uv_buffers = (uv_buf_t*)gpr_malloc(sizeof(uv_buf_t) * write_slices->count);
+ for (size_t i = 0; i < write_slices->count; i++) {
+ uv_buffers[i].base = (char*)GRPC_SLICE_START_PTR(write_slices->slices[i]);
+ uv_buffers[i].len = GRPC_SLICE_LENGTH(write_slices->slices[i]);
}
- gpr_free(tcp->write_buffers);
- GRPC_CLOSURE_SCHED(cb, error);
+
+ uv_socket->write_buffers = uv_buffers;
+ write_req = &uv_socket->write_req;
+ write_req->data = socket;
+ // TODO(murgatroid99): figure out what the return value here means
+ uv_write(write_req, (uv_stream_t*)uv_socket->handle, uv_buffers,
+ write_slices->count, uv_write_callback);
}
-static void uv_endpoint_write(grpc_endpoint* ep,
- grpc_slice_buffer* write_slices,
- grpc_closure* cb) {
- grpc_tcp* tcp = (grpc_tcp*)ep;
- uv_buf_t* buffers;
- unsigned int buffer_count;
- unsigned int i;
- grpc_slice* slice;
- uv_write_t* write_req;
- GRPC_UV_ASSERT_SAME_THREAD();
+static void shutdown_callback(uv_shutdown_t* req, int status) {}
- if (grpc_tcp_trace.enabled()) {
- size_t j;
+static void uv_socket_shutdown(grpc_custom_socket* socket) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ uv_shutdown_t* req = &uv_socket->shutdown_req;
+ uv_shutdown(req, (uv_stream_t*)uv_socket->handle, shutdown_callback);
+}
- for (j = 0; j < write_slices->count; j++) {
- char* data = grpc_dump_slice(write_slices->slices[j],
- GPR_DUMP_HEX | GPR_DUMP_ASCII);
- gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data);
- gpr_free(data);
- }
+static void uv_socket_close(grpc_custom_socket* socket,
+ grpc_custom_close_callback close_cb) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ uv_socket->close_cb = close_cb;
+ uv_close((uv_handle_t*)uv_socket->handle, uv_close_callback);
+}
+
+static grpc_error* uv_socket_init_helper(uv_socket_t* uv_socket, int domain) {
+ uv_tcp_t* tcp = (uv_tcp_t*)gpr_malloc(sizeof(uv_tcp_t));
+ uv_socket->handle = tcp;
+ int status = uv_tcp_init_ex(uv_default_loop(), tcp, (unsigned int)domain);
+ if (status != 0) {
+ return tcp_error_create("Failed to initialize UV tcp handle", status);
}
+ uv_socket->write_buffers = nullptr;
+ uv_socket->read_len = 0;
+ uv_tcp_nodelay(uv_socket->handle, 1);
+ uv_socket->pending_connection = false;
+ uv_socket->accept_socket = nullptr;
+ uv_socket->accept_error = GRPC_ERROR_NONE;
+ return GRPC_ERROR_NONE;
+}
- if (tcp->shutting_down) {
- GRPC_CLOSURE_SCHED(cb,
- tcp_annotate_error(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
- "TCP socket is shutting down"),
- tcp));
- return;
+static grpc_error* uv_socket_init(grpc_custom_socket* socket, int domain) {
+ uv_socket_t* uv_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t));
+ grpc_error* error = uv_socket_init_helper(uv_socket, domain);
+ if (error != GRPC_ERROR_NONE) {
+ return error;
}
+ uv_socket->handle->data = socket;
+ socket->impl = uv_socket;
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error* uv_socket_getpeername(grpc_custom_socket* socket,
+ const grpc_sockaddr* addr,
+ int* addr_len) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ int err = uv_tcp_getpeername(uv_socket->handle,
+ (struct sockaddr*)IGNORE_CONST(addr), addr_len);
+ return tcp_error_create("getpeername failed", err);
+}
+
+static grpc_error* uv_socket_getsockname(grpc_custom_socket* socket,
+ const grpc_sockaddr* addr,
+ int* addr_len) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ int err = uv_tcp_getsockname(uv_socket->handle,
+ (struct sockaddr*)IGNORE_CONST(addr), addr_len);
+ return tcp_error_create("getsockname failed", err);
+}
- GPR_ASSERT(tcp->write_cb == NULL);
- tcp->write_slices = write_slices;
- GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
- if (tcp->write_slices->count == 0) {
- // No slices means we don't have to do anything,
- // and libuv doesn't like empty writes
- GRPC_CLOSURE_SCHED(cb, GRPC_ERROR_NONE);
+static void accept_new_connection(grpc_custom_socket* socket) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ if (!uv_socket->pending_connection || !uv_socket->accept_socket) {
return;
}
+ grpc_custom_socket* new_socket = uv_socket->accept_socket;
+ grpc_error* error = uv_socket->accept_error;
+ uv_socket->accept_socket = nullptr;
+ uv_socket->accept_error = GRPC_ERROR_NONE;
+ uv_socket->pending_connection = false;
+ if (uv_socket->accept_error != GRPC_ERROR_NONE) {
+ uv_stream_t dummy_handle;
+ uv_accept((uv_stream_t*)uv_socket->handle, &dummy_handle);
+ uv_socket->accept_cb(socket, new_socket, error);
+ } else {
+ uv_socket_t* uv_new_socket = (uv_socket_t*)gpr_malloc(sizeof(uv_socket_t));
+ uv_socket_init_helper(uv_new_socket, AF_UNSPEC);
+ // UV documentation says this is guaranteed to succeed
+ GPR_ASSERT(uv_accept((uv_stream_t*)uv_socket->handle,
+ (uv_stream_t*)uv_new_socket->handle) == 0);
+ new_socket->impl = uv_new_socket;
+ uv_new_socket->handle->data = new_socket;
+ uv_socket->accept_cb(socket, new_socket, error);
+ }
+}
- tcp->write_cb = cb;
- buffer_count = (unsigned int)tcp->write_slices->count;
- buffers = (uv_buf_t*)gpr_malloc(sizeof(uv_buf_t) * buffer_count);
- for (i = 0; i < buffer_count; i++) {
- slice = &tcp->write_slices->slices[i];
- buffers[i].base = (char*)GRPC_SLICE_START_PTR(*slice);
- buffers[i].len = GRPC_SLICE_LENGTH(*slice);
+static void uv_on_connect(uv_stream_t* server, int status) {
+ grpc_custom_socket* socket = (grpc_custom_socket*)server->data;
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ GPR_ASSERT(!uv_socket->pending_connection);
+ uv_socket->pending_connection = true;
+ if (status < 0) {
+ switch (status) {
+ case UV_EINTR:
+ case UV_EAGAIN:
+ return;
+ default:
+ uv_socket->accept_error = tcp_error_create("accept failed", status);
+ }
}
- tcp->write_buffers = buffers;
- write_req = &tcp->write_req;
- write_req->data = tcp;
- TCP_REF(tcp, "write");
- // TODO(murgatroid99): figure out what the return value here means
- uv_write(write_req, (uv_stream_t*)tcp->handle, buffers, buffer_count,
- write_callback);
+ accept_new_connection(socket);
}
-static void uv_add_to_pollset(grpc_endpoint* ep, grpc_pollset* pollset) {
- // No-op. We're ignoring pollsets currently
- (void)ep;
- (void)pollset;
- grpc_tcp* tcp = (grpc_tcp*)ep;
- tcp->pollset = pollset;
+void uv_socket_accept(grpc_custom_socket* socket,
+ grpc_custom_socket* new_socket,
+ grpc_custom_accept_callback accept_cb) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ uv_socket->accept_cb = accept_cb;
+ GPR_ASSERT(uv_socket->accept_socket == nullptr);
+ uv_socket->accept_socket = new_socket;
+ accept_new_connection(socket);
}
-static void uv_add_to_pollset_set(grpc_endpoint* ep,
- grpc_pollset_set* pollset) {
- // No-op. We're ignoring pollsets currently
- (void)ep;
- (void)pollset;
+static grpc_error* uv_socket_bind(grpc_custom_socket* socket,
+ const grpc_sockaddr* addr, size_t len,
+ int flags) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ int status =
+ uv_tcp_bind((uv_tcp_t*)uv_socket->handle, (struct sockaddr*)addr, 0);
+ return tcp_error_create("Failed to bind to port", status);
}
-static void uv_delete_from_pollset_set(grpc_endpoint* ep,
- grpc_pollset_set* pollset) {
- // No-op. We're ignoring pollsets currently
- (void)ep;
- (void)pollset;
+static grpc_error* uv_socket_listen(grpc_custom_socket* socket) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ int status =
+ uv_listen((uv_stream_t*)uv_socket->handle, SOMAXCONN, uv_on_connect);
+ return tcp_error_create("Failed to listen to port", status);
}
-static void shutdown_callback(uv_shutdown_t* req, int status) {}
+static grpc_error* uv_socket_setsockopt(grpc_custom_socket* socket, int level,
+ int option_name, const void* optval,
+ socklen_t option_len) {
+ int fd;
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ uv_fileno((uv_handle_t*)uv_socket->handle, &fd);
+ // TODO Handle error here. Also, does this work on windows??
+ setsockopt(fd, level, option_name, &optval, (socklen_t)option_len);
+ return GRPC_ERROR_NONE;
+}
-static void uv_endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) {
- grpc_tcp* tcp = (grpc_tcp*)ep;
- if (!tcp->shutting_down) {
- if (grpc_tcp_trace.enabled()) {
- const char* str = grpc_error_string(why);
- gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->handle, str);
- }
- tcp->shutting_down = true;
- uv_shutdown_t* req = &tcp->shutdown_req;
- uv_shutdown(req, (uv_stream_t*)tcp->handle, shutdown_callback);
- grpc_resource_user_shutdown(tcp->resource_user);
+static void uv_tc_on_connect(uv_connect_t* req, int status) {
+ grpc_custom_socket* socket = (grpc_custom_socket*)req->data;
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ grpc_error* error;
+ if (status == UV_ECANCELED) {
+ // This should only happen if the handle is already closed
+ error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timeout occurred");
+ } else {
+ error = tcp_error_create("Failed to connect to remote host", status);
}
- GRPC_ERROR_UNREF(why);
+ uv_socket->connect_cb(socket, error);
}
-static void uv_destroy(grpc_endpoint* ep) {
- grpc_network_status_unregister_endpoint(ep);
- grpc_tcp* tcp = (grpc_tcp*)ep;
- uv_close((uv_handle_t*)tcp->handle, uv_close_callback);
+static void uv_socket_connect(grpc_custom_socket* socket,
+ const grpc_sockaddr* addr, size_t len,
+ grpc_custom_connect_callback connect_cb) {
+ uv_socket_t* uv_socket = (uv_socket_t*)socket->impl;
+ uv_socket->connect_cb = connect_cb;
+ uv_socket->connect_req.data = socket;
+ int status = uv_tcp_connect(&uv_socket->connect_req, uv_socket->handle,
+ (struct sockaddr*)addr, uv_tc_on_connect);
+ if (status != 0) {
+ // The callback will not be called
+ uv_socket->connect_cb(socket, tcp_error_create("connect failed", status));
+ }
+}
+
+static grpc_resolved_addresses* handle_addrinfo_result(
+ struct addrinfo* result) {
+ struct addrinfo* resp;
+ struct addrinfo* prev;
+ size_t i;
+ grpc_resolved_addresses* addresses =
+ (grpc_resolved_addresses*)gpr_malloc(sizeof(grpc_resolved_addresses));
+ addresses->naddrs = 0;
+ for (resp = result; resp != nullptr; resp = resp->ai_next) {
+ addresses->naddrs++;
+ }
+ addresses->addrs = (grpc_resolved_address*)gpr_malloc(
+ sizeof(grpc_resolved_address) * addresses->naddrs);
+ i = 0;
+ resp = result;
+ while (resp != nullptr) {
+ memcpy(&addresses->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
+ addresses->addrs[i].len = resp->ai_addrlen;
+ i++;
+ prev = resp;
+ resp = resp->ai_next;
+ gpr_free(prev);
+ }
+ return addresses;
}
-static char* uv_get_peer(grpc_endpoint* ep) {
- grpc_tcp* tcp = (grpc_tcp*)ep;
- return gpr_strdup(tcp->peer_string);
+static void uv_resolve_callback(uv_getaddrinfo_t* req, int status,
+ struct addrinfo* res) {
+ grpc_custom_resolver* r = (grpc_custom_resolver*)req->data;
+ gpr_free(req);
+ grpc_resolved_addresses* result = nullptr;
+ if (status == 0) {
+ result = handle_addrinfo_result(res);
+ }
+ grpc_custom_resolve_callback(r, result,
+ tcp_error_create("getaddrinfo failed", status));
}
-static grpc_resource_user* uv_get_resource_user(grpc_endpoint* ep) {
- grpc_tcp* tcp = (grpc_tcp*)ep;
- return tcp->resource_user;
+static grpc_error* uv_resolve(char* host, char* port,
+ grpc_resolved_addresses** result) {
+ int status;
+ uv_getaddrinfo_t req;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */
+ hints.ai_socktype = SOCK_STREAM; /* stream socket */
+ hints.ai_flags = AI_PASSIVE; /* for wildcard IP address */
+ status = uv_getaddrinfo(uv_default_loop(), &req, NULL, host, port, &hints);
+ if (status != 0) {
+ *result = nullptr;
+ } else {
+ *result = handle_addrinfo_result(req.addrinfo);
+ }
+ return tcp_error_create("getaddrinfo failed", status);
}
-static int uv_get_fd(grpc_endpoint* ep) { return -1; }
-
-static grpc_endpoint_vtable vtable = {uv_endpoint_read,
- uv_endpoint_write,
- uv_add_to_pollset,
- uv_add_to_pollset_set,
- uv_delete_from_pollset_set,
- uv_endpoint_shutdown,
- uv_destroy,
- uv_get_resource_user,
- uv_get_peer,
- uv_get_fd};
-
-grpc_endpoint* grpc_tcp_create(uv_tcp_t* handle,
- grpc_resource_quota* resource_quota,
- char* peer_string) {
- grpc_tcp* tcp = (grpc_tcp*)gpr_malloc(sizeof(grpc_tcp));
- grpc_core::ExecCtx exec_ctx;
-
- if (grpc_tcp_trace.enabled()) {
- gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", tcp);
+static void uv_resolve_async(grpc_custom_resolver* r, char* host, char* port) {
+ int status;
+ uv_getaddrinfo_t* req =
+ (uv_getaddrinfo_t*)gpr_malloc(sizeof(uv_getaddrinfo_t));
+ req->data = r;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = GRPC_AF_UNSPEC; /* ipv4 or ipv6 */
+ hints.ai_socktype = GRPC_SOCK_STREAM; /* stream socket */
+ hints.ai_flags = GRPC_AI_PASSIVE; /* for wildcard IP address */
+ status = uv_getaddrinfo(uv_default_loop(), req, uv_resolve_callback, host,
+ port, &hints);
+ if (status != 0) {
+ gpr_free(req);
+ grpc_error* error = tcp_error_create("getaddrinfo failed", status);
+ grpc_custom_resolve_callback(r, NULL, error);
}
+}
- /* Disable Nagle's Algorithm */
- uv_tcp_nodelay(handle, 1);
-
- memset(tcp, 0, sizeof(grpc_tcp));
- tcp->base.vtable = &vtable;
- tcp->handle = handle;
- handle->data = tcp;
- gpr_ref_init(&tcp->refcount, 1);
- tcp->peer_string = gpr_strdup(peer_string);
- tcp->shutting_down = false;
- tcp->read_slices = NULL;
- tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
- grpc_resource_user_slice_allocator_init(
- &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
- /* Tell network status tracking code about the new endpoint */
- grpc_network_status_register_endpoint(&tcp->base);
-
-#ifndef GRPC_UV_TCP_HOLD_LOOP
- uv_unref((uv_handle_t*)handle);
-#endif
+grpc_custom_resolver_vtable uv_resolver_vtable = {uv_resolve, uv_resolve_async};
- return &tcp->base;
-}
+grpc_socket_vtable grpc_uv_socket_vtable = {
+ uv_socket_init, uv_socket_connect, uv_socket_destroy,
+ uv_socket_shutdown, uv_socket_close, uv_socket_write,
+ uv_socket_read, uv_socket_getpeername, uv_socket_getsockname,
+ uv_socket_setsockopt, uv_socket_bind, uv_socket_listen,
+ uv_socket_accept};
-#endif /* GRPC_UV */
+#endif
diff --git a/src/core/lib/iomgr/tcp_uv.h b/src/core/lib/iomgr/tcp_uv.h
deleted file mode 100644
index 6b1a6f77c2..0000000000
--- a/src/core/lib/iomgr/tcp_uv.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *
- * Copyright 2016 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_LIB_IOMGR_TCP_UV_H
-#define GRPC_CORE_LIB_IOMGR_TCP_UV_H
-/*
- Low level TCP "bottom half" implementation, for use by transports built on
- top of a TCP connection.
-
- Note that this file does not (yet) include APIs for creating the socket in
- the first place.
-
- All calls passing slice transfer ownership of a slice refcount unless
- otherwise specified.
-*/
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/endpoint.h"
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_UV
-
-#include <uv.h>
-
-extern grpc_core::TraceFlag grpc_tcp_trace;
-
-#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
-
-grpc_endpoint* grpc_tcp_create(uv_tcp_t* handle,
- grpc_resource_quota* resource_quota,
- char* peer_string);
-
-#endif /* GRPC_UV */
-
-#endif /* GRPC_CORE_LIB_IOMGR_TCP_UV_H */
diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc
index aab8edc888..04e6f11eee 100644
--- a/src/core/lib/iomgr/tcp_windows.cc
+++ b/src/core/lib/iomgr/tcp_windows.cc
@@ -51,7 +51,7 @@
#define GRPC_FIONBIO FIONBIO
#endif
-grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
+extern grpc_core::TraceFlag grpc_tcp_trace;
static grpc_error* set_non_block(SOCKET sock) {
int status;
diff --git a/src/core/lib/iomgr/timer.cc b/src/core/lib/iomgr/timer.cc
new file mode 100644
index 0000000000..e647cdefa0
--- /dev/null
+++ b/src/core/lib/iomgr/timer.cc
@@ -0,0 +1,45 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_manager.h"
+
+grpc_timer_vtable* grpc_timer_impl;
+
+void grpc_set_timer_impl(grpc_timer_vtable* vtable) {
+ grpc_timer_impl = vtable;
+}
+
+void grpc_timer_init(grpc_timer* timer, grpc_millis deadline,
+ grpc_closure* closure) {
+ grpc_timer_impl->init(timer, deadline, closure);
+}
+
+void grpc_timer_cancel(grpc_timer* timer) { grpc_timer_impl->cancel(timer); }
+
+grpc_timer_check_result grpc_timer_check(grpc_millis* next) {
+ return grpc_timer_impl->check(next);
+}
+
+void grpc_timer_list_init() { grpc_timer_impl->list_init(); }
+
+void grpc_timer_list_shutdown() { grpc_timer_impl->list_shutdown(); }
+
+void grpc_timer_consume_kick() { grpc_timer_impl->consume_kick(); }
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
index 67f1b1b3f9..5ff10d3aee 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -23,17 +23,41 @@
#include "src/core/lib/iomgr/port.h"
-#ifdef GRPC_UV
-#include "src/core/lib/iomgr/timer_uv.h"
-#else
-#include "src/core/lib/iomgr/timer_generic.h"
-#endif /* GRPC_UV */
-
#include <grpc/support/time.h>
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/iomgr.h"
-typedef struct grpc_timer grpc_timer;
+typedef struct grpc_timer {
+ gpr_atm deadline;
+ uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
+ bool pending;
+ struct grpc_timer* next;
+ struct grpc_timer* prev;
+ grpc_closure* closure;
+#ifndef NDEBUG
+ struct grpc_timer* hash_table_next;
+#endif
+
+ // Optional field used by custom timers
+ void* custom_timer;
+} grpc_timer;
+
+typedef enum {
+ GRPC_TIMERS_NOT_CHECKED,
+ GRPC_TIMERS_CHECKED_AND_EMPTY,
+ GRPC_TIMERS_FIRED,
+} grpc_timer_check_result;
+
+typedef struct grpc_timer_vtable {
+ void (*init)(grpc_timer* timer, grpc_millis, grpc_closure* closure);
+ void (*cancel)(grpc_timer* timer);
+
+ /* Internal API */
+ grpc_timer_check_result (*check)(grpc_millis* next);
+ void (*list_init)();
+ void (*list_shutdown)(void);
+ void (*consume_kick)(void);
+} grpc_timer_vtable;
/* Initialize *timer. When expired or canceled, closure will be called with
error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled
@@ -78,12 +102,6 @@ void grpc_timer_cancel(grpc_timer* timer);
/* iomgr internal api for dealing with timers */
-typedef enum {
- GRPC_TIMERS_NOT_CHECKED,
- GRPC_TIMERS_CHECKED_AND_EMPTY,
- GRPC_TIMERS_FIRED,
-} grpc_timer_check_result;
-
/* Check for timers to be run, and run them.
Return true if timer callbacks were executed.
If next is non-null, TRY to update *next with the next running timer
@@ -99,7 +117,9 @@ void grpc_timer_list_shutdown();
void grpc_timer_consume_kick(void);
/* the following must be implemented by each iomgr implementation */
-
void grpc_kick_poller(void);
+/* Sets the timer implementation */
+void grpc_set_timer_impl(grpc_timer_vtable* vtable);
+
#endif /* GRPC_CORE_LIB_IOMGR_TIMER_H */
diff --git a/src/core/lib/iomgr/timer_custom.cc b/src/core/lib/iomgr/timer_custom.cc
new file mode 100644
index 0000000000..71d825ff9f
--- /dev/null
+++ b/src/core/lib/iomgr/timer_custom.cc
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
+#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_custom.h"
+
+static grpc_custom_timer_vtable* custom_timer_impl;
+
+void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ grpc_core::ExecCtx exec_ctx;
+ grpc_timer* timer = t->original;
+ GPR_ASSERT(timer->pending);
+ timer->pending = 0;
+ GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_NONE);
+ custom_timer_impl->stop(t);
+ gpr_free(t);
+}
+
+static void timer_init(grpc_timer* timer, grpc_millis deadline,
+ grpc_closure* closure) {
+ uint64_t timeout;
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ grpc_millis now = grpc_core::ExecCtx::Get()->Now();
+ if (deadline <= grpc_core::ExecCtx::Get()->Now()) {
+ GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE);
+ timer->pending = false;
+ return;
+ } else {
+ timeout = deadline - now;
+ }
+ timer->pending = true;
+ timer->closure = closure;
+ grpc_custom_timer* timer_wrapper =
+ (grpc_custom_timer*)gpr_malloc(sizeof(grpc_custom_timer));
+ timer_wrapper->timeout_ms = timeout;
+ timer->custom_timer = (void*)timer_wrapper;
+ timer_wrapper->original = timer;
+ custom_timer_impl->start(timer_wrapper);
+}
+
+static void timer_cancel(grpc_timer* timer) {
+ GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD();
+ grpc_custom_timer* tw = (grpc_custom_timer*)timer->custom_timer;
+ if (timer->pending) {
+ timer->pending = 0;
+ GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_CANCELLED);
+ custom_timer_impl->stop(tw);
+ gpr_free(tw);
+ }
+}
+
+static grpc_timer_check_result timer_check(grpc_millis* next) {
+ return GRPC_TIMERS_NOT_CHECKED;
+}
+
+static void timer_list_init() {}
+static void timer_list_shutdown() {}
+
+static void timer_consume_kick(void) {}
+
+static grpc_timer_vtable custom_timer_vtable = {
+ timer_init, timer_cancel, timer_check,
+ timer_list_init, timer_list_shutdown, timer_consume_kick};
+
+void grpc_custom_timer_init(grpc_custom_timer_vtable* impl) {
+ custom_timer_impl = impl;
+ grpc_set_timer_impl(&custom_timer_vtable);
+}
diff --git a/src/core/lib/iomgr/timer_custom.h b/src/core/lib/iomgr/timer_custom.h
new file mode 100644
index 0000000000..bfea8bafa6
--- /dev/null
+++ b/src/core/lib/iomgr/timer_custom.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H
+#define GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/timer.h"
+
+typedef struct grpc_custom_timer {
+ // Implementation defined
+ void* timer;
+ uint64_t timeout_ms;
+
+ grpc_timer* original;
+} grpc_custom_timer;
+
+typedef struct grpc_custom_timer_vtable {
+ void (*start)(grpc_custom_timer* t);
+ void (*stop)(grpc_custom_timer* t);
+} grpc_custom_timer_vtable;
+
+void grpc_custom_timer_init(grpc_custom_timer_vtable* impl);
+
+void grpc_custom_timer_callback(grpc_custom_timer* t, grpc_error* error);
+
+#endif /* GRPC_CORE_LIB_IOMGR_TIMER_CUSTOM_H */
diff --git a/src/core/lib/iomgr/timer_generic.cc b/src/core/lib/iomgr/timer_generic.cc
index 52a571f425..93e654b7fa 100644
--- a/src/core/lib/iomgr/timer_generic.cc
+++ b/src/core/lib/iomgr/timer_generic.cc
@@ -22,8 +22,6 @@
#include <inttypes.h>
-#ifdef GRPC_TIMER_USE_GENERIC
-
#include "src/core/lib/iomgr/timer.h"
#include <grpc/support/alloc.h>
@@ -238,7 +236,7 @@ static gpr_atm compute_min_deadline(timer_shard* shard) {
: grpc_timer_heap_top(&shard->heap)->deadline;
}
-void grpc_timer_list_init() {
+static void timer_list_init() {
uint32_t i;
g_num_shards = GPR_MIN(1, 2 * gpr_cpu_num_cores());
@@ -270,7 +268,7 @@ void grpc_timer_list_init() {
INIT_TIMER_HASH_TABLE();
}
-void grpc_timer_list_shutdown() {
+static void timer_list_shutdown() {
size_t i;
run_some_expired_timers(
GPR_ATM_MAX, nullptr,
@@ -326,8 +324,8 @@ static void note_deadline_change(timer_shard* shard) {
void grpc_timer_init_unset(grpc_timer* timer) { timer->pending = false; }
-void grpc_timer_init(grpc_timer* timer, grpc_millis deadline,
- grpc_closure* closure) {
+static void timer_init(grpc_timer* timer, grpc_millis deadline,
+ grpc_closure* closure) {
int is_first_timer = 0;
timer_shard* shard = &g_shards[GPR_HASH_POINTER(timer, g_num_shards)];
timer->closure = closure;
@@ -412,12 +410,12 @@ void grpc_timer_init(grpc_timer* timer, grpc_millis deadline,
}
}
-void grpc_timer_consume_kick(void) {
+static void timer_consume_kick(void) {
/* force re-evaluation of last seeen min */
gpr_tls_set(&g_last_seen_min_timer, 0);
}
-void grpc_timer_cancel(grpc_timer* timer) {
+static void timer_cancel(grpc_timer* timer) {
if (!g_shared_mutables.initialized) {
/* must have already been cancelled, also the shard mutex is invalid */
return;
@@ -604,7 +602,7 @@ static grpc_timer_check_result run_some_expired_timers(gpr_atm now,
return result;
}
-grpc_timer_check_result grpc_timer_check(grpc_millis* next) {
+static grpc_timer_check_result timer_check(grpc_millis* next) {
// prelude
grpc_millis now = grpc_core::ExecCtx::Get()->Now();
@@ -660,4 +658,6 @@ grpc_timer_check_result grpc_timer_check(grpc_millis* next) {
return r;
}
-#endif /* GRPC_TIMER_USE_GENERIC */
+grpc_timer_vtable grpc_generic_timer_vtable = {
+ timer_init, timer_cancel, timer_check,
+ timer_list_init, timer_list_shutdown, timer_consume_kick};
diff --git a/src/core/lib/iomgr/timer_heap.cc b/src/core/lib/iomgr/timer_heap.cc
index e5b5abfc97..0c17d607eb 100644
--- a/src/core/lib/iomgr/timer_heap.cc
+++ b/src/core/lib/iomgr/timer_heap.cc
@@ -20,8 +20,6 @@
#include "src/core/lib/iomgr/port.h"
-#ifdef GRPC_TIMER_USE_GENERIC
-
#include "src/core/lib/iomgr/timer_heap.h"
#include <string.h>
@@ -135,5 +133,3 @@ grpc_timer* grpc_timer_heap_top(grpc_timer_heap* heap) {
void grpc_timer_heap_pop(grpc_timer_heap* heap) {
grpc_timer_heap_remove(heap, grpc_timer_heap_top(heap));
}
-
-#endif /* GRPC_TIMER_USE_GENERIC */
diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc
index 0210e70015..94f288af27 100644
--- a/src/core/lib/iomgr/timer_manager.cc
+++ b/src/core/lib/iomgr/timer_manager.cc
@@ -18,21 +18,20 @@
#include <grpc/support/port_platform.h>
-#include "src/core/lib/iomgr/timer_manager.h"
+#include <inttypes.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <inttypes.h>
-
#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_manager.h"
-typedef struct completed_thread {
- gpr_thd_id t;
- struct completed_thread* next;
-} completed_thread;
+struct completed_thread {
+ grpc_core::Thread thd;
+ completed_thread* next;
+};
extern grpc_core::TraceFlag grpc_timer_check_trace;
@@ -68,7 +67,7 @@ static void gc_completed_threads(void) {
g_completed_threads = nullptr;
gpr_mu_unlock(&g_mu);
while (to_gc != nullptr) {
- gpr_thd_join(to_gc->t);
+ to_gc->thd.Join();
completed_thread* next = to_gc->next;
gpr_free(to_gc);
to_gc = next;
@@ -85,18 +84,10 @@ static void start_timer_thread_and_unlock(void) {
if (grpc_timer_check_trace.enabled()) {
gpr_log(GPR_DEBUG, "Spawn timer thread");
}
- gpr_thd_options opt = gpr_thd_options_default();
- gpr_thd_options_set_joinable(&opt);
completed_thread* ct =
static_cast<completed_thread*>(gpr_malloc(sizeof(*ct)));
- // The call to gpr_thd_new() has to be under the same lock used by
- // gc_completed_threads(), particularly due to ct->t, which is written here
- // (internally by gpr_thd_new) and read there. Otherwise it's possible for ct
- // to leak through g_completed_threads and be freed in gc_completed_threads()
- // before "&ct->t" is written to, causing a use-after-free.
- gpr_mu_lock(&g_mu);
- gpr_thd_new(&ct->t, "grpc_global_timer", timer_thread, ct, &opt);
- gpr_mu_unlock(&g_mu);
+ ct->thd = grpc_core::Thread("grpc_global_timer", timer_thread, ct);
+ ct->thd.Start();
}
void grpc_timer_manager_tick() {
diff --git a/src/core/lib/iomgr/timer_uv.cc b/src/core/lib/iomgr/timer_uv.cc
index 6f28f553c5..dadeb960b2 100644
--- a/src/core/lib/iomgr/timer_uv.cc
+++ b/src/core/lib/iomgr/timer_uv.cc
@@ -20,20 +20,18 @@
#include "src/core/lib/iomgr/port.h"
-#if GRPC_UV
+#ifdef GRPC_UV
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/debug/trace.h"
-#include "src/core/lib/iomgr/iomgr_uv.h"
+#include "src/core/lib/iomgr/iomgr_custom.h"
#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/iomgr/timer_custom.h"
#include <uv.h>
-grpc_core::TraceFlag grpc_timer_trace(false, "timer");
-grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check");
-
static void timer_close_callback(uv_handle_t* handle) { gpr_free(handle); }
static void stop_uv_timer(uv_timer_t* handle) {
@@ -43,57 +41,23 @@ static void stop_uv_timer(uv_timer_t* handle) {
}
void run_expired_timer(uv_timer_t* handle) {
- grpc_timer* timer = (grpc_timer*)handle->data;
- grpc_core::ExecCtx exec_ctx;
- GRPC_UV_ASSERT_SAME_THREAD();
- GPR_ASSERT(timer->pending);
- timer->pending = 0;
- GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_NONE);
- stop_uv_timer(handle);
+ grpc_custom_timer* timer_wrapper = (grpc_custom_timer*)handle->data;
+ grpc_custom_timer_callback(timer_wrapper, GRPC_ERROR_NONE);
}
-void grpc_timer_init(grpc_timer* timer, grpc_millis deadline,
- grpc_closure* closure) {
- uint64_t timeout;
+static void timer_start(grpc_custom_timer* t) {
uv_timer_t* uv_timer;
- GRPC_UV_ASSERT_SAME_THREAD();
- timer->closure = closure;
- if (deadline <= grpc_core::ExecCtx::Get()->Now()) {
- timer->pending = 0;
- GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_NONE);
- return;
- }
- timer->pending = 1;
- timeout = (uint64_t)(deadline - grpc_core::ExecCtx::Get()->Now());
uv_timer = (uv_timer_t*)gpr_malloc(sizeof(uv_timer_t));
uv_timer_init(uv_default_loop(), uv_timer);
- uv_timer->data = timer;
- timer->uv_timer = uv_timer;
- uv_timer_start(uv_timer, run_expired_timer, timeout, 0);
- /* We assume that gRPC timers are only used alongside other active gRPC
- objects, and that there will therefore always be something else keeping
- the uv loop alive whenever there is a timer */
- uv_unref((uv_handle_t*)uv_timer);
+ uv_timer->data = t;
+ t->timer = (void*)uv_timer;
+ uv_timer_start(uv_timer, run_expired_timer, t->timeout_ms, 0);
}
-void grpc_timer_init_unset(grpc_timer* timer) { timer->pending = 0; }
-
-void grpc_timer_cancel(grpc_timer* timer) {
- GRPC_UV_ASSERT_SAME_THREAD();
- if (timer->pending) {
- timer->pending = 0;
- GRPC_CLOSURE_SCHED(timer->closure, GRPC_ERROR_CANCELLED);
- stop_uv_timer((uv_timer_t*)timer->uv_timer);
- }
+static void timer_stop(grpc_custom_timer* t) {
+ stop_uv_timer((uv_timer_t*)t->timer);
}
-grpc_timer_check_result grpc_timer_check(grpc_millis* next) {
- return GRPC_TIMERS_NOT_CHECKED;
-}
-
-void grpc_timer_list_init() {}
-void grpc_timer_list_shutdown() {}
-
-void grpc_timer_consume_kick(void) {}
+grpc_custom_timer_vtable uv_timer_vtable = {timer_start, timer_stop};
-#endif /* GRPC_UV */
+#endif
diff --git a/src/core/lib/iomgr/udp_server.cc b/src/core/lib/iomgr/udp_server.cc
index ec65497d79..15a242abe2 100644
--- a/src/core/lib/iomgr/udp_server.cc
+++ b/src/core/lib/iomgr/udp_server.cc
@@ -52,6 +52,8 @@
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/executor.h"
@@ -62,41 +64,102 @@
#include "src/core/lib/iomgr/socket_utils_posix.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
-/* one listening port */
-typedef struct grpc_udp_listener grpc_udp_listener;
-struct grpc_udp_listener {
- int fd;
- grpc_fd* emfd;
- grpc_udp_server* server;
- grpc_resolved_address addr;
- grpc_closure read_closure;
- grpc_closure write_closure;
+/* A listener which implements basic features of Listening on a port for
+ * I/O events*/
+class GrpcUdpListener {
+ public:
+ GrpcUdpListener(grpc_udp_server* server, int fd,
+ const grpc_resolved_address* addr);
+ ~GrpcUdpListener();
+
+ /* Called when grpc server starts to listening on the grpc_fd. */
+ void StartListening(grpc_pollset** pollsets, size_t pollset_count,
+ GrpcUdpHandlerFactory* handler_factory);
+
+ /* Called when data is available to read from the socket.
+ * Return true if there is more data to read from fd. */
+ void OnRead(grpc_error* error, void* do_read_arg);
+
+ /* Called when the socket is writeable. The given closure should be scheduled
+ * when the socket becomes blocked next time. */
+ void OnCanWrite(grpc_error* error, void* do_write_arg);
+
+ /* Called when the grpc_fd is about to be orphaned (and the FD closed). */
+ void OnFdAboutToOrphan();
+
+ /* Called to orphan fd of this listener.*/
+ void OrphanFd();
+
+ /* Called when this listener is going to be destroyed. */
+ void OnDestroy();
+
+ int fd() const { return fd_; }
+
+ protected:
+ grpc_fd* emfd() const { return emfd_; }
+
+ gpr_mu* mutex() { return &mutex_; }
+
+ private:
+ /* event manager callback when reads are ready */
+ static void on_read(void* arg, grpc_error* error);
+ static void on_write(void* arg, grpc_error* error);
+
+ static void do_read(void* arg, grpc_error* error);
+ static void do_write(void* arg, grpc_error* error);
+ // Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback
+ // interface.
+ static void fd_notify_on_write_wrapper(void* arg, grpc_error* error);
+
+ static void shutdown_fd(void* args, grpc_error* error);
+
+ int fd_;
+ grpc_fd* emfd_;
+ grpc_udp_server* server_;
+ grpc_resolved_address addr_;
+ grpc_closure read_closure_;
+ grpc_closure write_closure_;
// To be called when corresponding QuicGrpcServer closes all active
// connections.
- grpc_closure orphan_fd_closure;
- grpc_closure destroyed_closure;
- grpc_udp_server_read_cb read_cb;
- grpc_udp_server_write_cb write_cb;
- grpc_udp_server_orphan_cb orphan_cb;
- grpc_udp_server_start_cb start_cb;
+ grpc_closure orphan_fd_closure_;
+ grpc_closure destroyed_closure_;
// To be scheduled on another thread to actually read/write.
- grpc_closure do_read_closure;
- grpc_closure do_write_closure;
- grpc_closure notify_on_write_closure;
+ grpc_closure do_read_closure_;
+ grpc_closure do_write_closure_;
+ grpc_closure notify_on_write_closure_;
// True if orphan_cb is trigered.
- bool orphan_notified;
+ bool orphan_notified_;
// True if grpc_fd_notify_on_write() is called after on_write() call.
- bool notify_on_write_armed;
+ bool notify_on_write_armed_;
// True if fd has been shutdown.
- bool already_shutdown;
-
- struct grpc_udp_listener* next;
+ bool already_shutdown_;
+ // Object actually handles I/O events. Assigned in StartListening().
+ GrpcUdpHandler* udp_handler_ = nullptr;
+ // To be notified on destruction.
+ GrpcUdpHandlerFactory* handler_factory_ = nullptr;
+ // Required to access above fields.
+ gpr_mu mutex_;
};
-struct shutdown_fd_args {
- grpc_udp_listener* sp;
- gpr_mu* server_mu;
-};
+GrpcUdpListener::GrpcUdpListener(grpc_udp_server* server, int fd,
+ const grpc_resolved_address* addr)
+ : fd_(fd),
+ server_(server),
+ orphan_notified_(false),
+ already_shutdown_(false) {
+ char* addr_str;
+ char* name;
+ grpc_sockaddr_to_string(&addr_str, addr, 1);
+ gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
+ gpr_free(addr_str);
+ emfd_ = grpc_fd_create(fd, name);
+ memcpy(&addr_, addr, sizeof(grpc_resolved_address));
+ GPR_ASSERT(emfd_);
+ gpr_free(name);
+ gpr_mu_init(&mutex_);
+}
+
+GrpcUdpListener::~GrpcUdpListener() { gpr_mu_destroy(&mutex_); }
/* the overall server */
struct grpc_udp_server {
@@ -113,10 +176,11 @@ struct grpc_udp_server {
/* is this server shutting down? (boolean) */
int shutdown;
- /* linked list of server ports */
- grpc_udp_listener* head;
- grpc_udp_listener* tail;
- unsigned nports;
+ /* An array of listeners */
+ grpc_core::InlinedVector<GrpcUdpListener, 16> listeners;
+
+ /* factory for use to create udp listeners */
+ GrpcUdpHandlerFactory* handler_factory;
/* shutdown callback */
grpc_closure* shutdown_complete;
@@ -141,8 +205,7 @@ static grpc_socket_factory* get_socket_factory(const grpc_channel_args* args) {
}
grpc_udp_server* grpc_udp_server_create(const grpc_channel_args* args) {
- grpc_udp_server* s =
- static_cast<grpc_udp_server*>(gpr_malloc(sizeof(grpc_udp_server)));
+ grpc_udp_server* s = grpc_core::New<grpc_udp_server>();
gpr_mu_init(&s->mu);
s->socket_factory = get_socket_factory(args);
if (s->socket_factory) {
@@ -151,33 +214,27 @@ grpc_udp_server* grpc_udp_server_create(const grpc_channel_args* args) {
s->active_ports = 0;
s->destroyed_ports = 0;
s->shutdown = 0;
- s->head = nullptr;
- s->tail = nullptr;
- s->nports = 0;
-
return s;
}
-static void shutdown_fd(void* args, grpc_error* error) {
- struct shutdown_fd_args* shutdown_args =
- static_cast<struct shutdown_fd_args*>(args);
- grpc_udp_listener* sp = shutdown_args->sp;
- gpr_log(GPR_DEBUG, "shutdown fd %d", sp->fd);
- gpr_mu_lock(shutdown_args->server_mu);
- grpc_fd_shutdown(sp->emfd, GRPC_ERROR_REF(error));
- sp->already_shutdown = true;
- if (!sp->notify_on_write_armed) {
+// static
+void GrpcUdpListener::shutdown_fd(void* args, grpc_error* error) {
+ if (args == nullptr) {
+ // No-op if shutdown args are null.
+ return;
+ }
+ auto sp = static_cast<GrpcUdpListener*>(args);
+ gpr_mu_lock(sp->mutex());
+ gpr_log(GPR_DEBUG, "shutdown fd %d", sp->fd_);
+ grpc_fd_shutdown(sp->emfd_, GRPC_ERROR_REF(error));
+ sp->already_shutdown_ = true;
+ if (!sp->notify_on_write_armed_) {
// Re-arm write notification to notify listener with error. This is
// necessary to decrement active_ports.
- sp->notify_on_write_armed = true;
- grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
+ sp->notify_on_write_armed_ = true;
+ grpc_fd_notify_on_write(sp->emfd_, &sp->write_closure_);
}
- gpr_mu_unlock(shutdown_args->server_mu);
- gpr_free(shutdown_args);
-}
-
-static void dummy_cb(void* arg, grpc_error* error) {
- // No-op.
+ gpr_mu_unlock(sp->mutex());
}
static void finish_shutdown(grpc_udp_server* s) {
@@ -188,24 +245,22 @@ static void finish_shutdown(grpc_udp_server* s) {
gpr_mu_destroy(&s->mu);
gpr_log(GPR_DEBUG, "Destroy all listeners.");
- while (s->head) {
- grpc_udp_listener* sp = s->head;
- s->head = sp->next;
- gpr_free(sp);
+ for (size_t i = 0; i < s->listeners.size(); ++i) {
+ s->listeners[i].OnDestroy();
}
if (s->socket_factory) {
grpc_socket_factory_unref(s->socket_factory);
}
- gpr_free(s);
+ grpc_core::Delete(s);
}
static void destroyed_port(void* server, grpc_error* error) {
grpc_udp_server* s = static_cast<grpc_udp_server*>(server);
gpr_mu_lock(&s->mu);
s->destroyed_ports++;
- if (s->destroyed_ports == s->nports) {
+ if (s->destroyed_ports == s->listeners.size()) {
gpr_mu_unlock(&s->mu);
finish_shutdown(s);
} else {
@@ -222,35 +277,30 @@ static void deactivated_all_ports(grpc_udp_server* s) {
GPR_ASSERT(s->shutdown);
- if (s->head) {
- grpc_udp_listener* sp;
- for (sp = s->head; sp; sp = sp->next) {
- grpc_unlink_if_unix_domain_socket(&sp->addr);
-
- GRPC_CLOSURE_INIT(&sp->destroyed_closure, destroyed_port, s,
- grpc_schedule_on_exec_ctx);
- if (!sp->orphan_notified) {
- /* Call the orphan_cb to signal that the FD is about to be closed and
- * should no longer be used. Because at this point, all listening ports
- * have been shutdown already, no need to shutdown again.*/
- GRPC_CLOSURE_INIT(&sp->orphan_fd_closure, dummy_cb, sp,
- grpc_schedule_on_exec_ctx);
- GPR_ASSERT(sp->orphan_cb);
- gpr_log(GPR_DEBUG, "Orphan fd %d", sp->fd);
- sp->orphan_cb(sp->emfd, &sp->orphan_fd_closure, sp->server->user_data);
- }
- grpc_fd_orphan(sp->emfd, &sp->destroyed_closure, nullptr,
- false /* already_closed */, "udp_listener_shutdown");
- }
- gpr_mu_unlock(&s->mu);
- } else {
+ if (s->listeners.size() == 0) {
gpr_mu_unlock(&s->mu);
finish_shutdown(s);
+ return;
}
+ for (size_t i = 0; i < s->listeners.size(); ++i) {
+ s->listeners[i].OrphanFd();
+ }
+ gpr_mu_unlock(&s->mu);
+}
+
+void GrpcUdpListener::OrphanFd() {
+ gpr_log(GPR_DEBUG, "Orphan fd %d, emfd %p", fd_, emfd_);
+ grpc_unlink_if_unix_domain_socket(&addr_);
+
+ GRPC_CLOSURE_INIT(&destroyed_closure_, destroyed_port, server_,
+ grpc_schedule_on_exec_ctx);
+ /* Because at this point, all listening sockets have been shutdown already, no
+ * need to call OnFdAboutToOrphan() to notify the handler again. */
+ grpc_fd_orphan(emfd_, &destroyed_closure_, nullptr,
+ false /* already_closed */, "udp_listener_shutdown");
}
void grpc_udp_server_destroy(grpc_udp_server* s, grpc_closure* on_done) {
- grpc_udp_listener* sp;
gpr_mu_lock(&s->mu);
GPR_ASSERT(!s->shutdown);
@@ -261,16 +311,9 @@ void grpc_udp_server_destroy(grpc_udp_server* s, grpc_closure* on_done) {
gpr_log(GPR_DEBUG, "start to destroy udp_server");
/* shutdown all fd's */
if (s->active_ports) {
- for (sp = s->head; sp; sp = sp->next) {
- GPR_ASSERT(sp->orphan_cb);
- struct shutdown_fd_args* args =
- static_cast<struct shutdown_fd_args*>(gpr_malloc(sizeof(*args)));
- args->sp = sp;
- args->server_mu = &s->mu;
- GRPC_CLOSURE_INIT(&sp->orphan_fd_closure, shutdown_fd, args,
- grpc_schedule_on_exec_ctx);
- sp->orphan_cb(sp->emfd, &sp->orphan_fd_closure, sp->server->user_data);
- sp->orphan_notified = true;
+ for (size_t i = 0; i < s->listeners.size(); ++i) {
+ GrpcUdpListener* sp = &s->listeners[i];
+ sp->OnFdAboutToOrphan();
}
gpr_mu_unlock(&s->mu);
} else {
@@ -279,12 +322,30 @@ void grpc_udp_server_destroy(grpc_udp_server* s, grpc_closure* on_done) {
}
}
+void GrpcUdpListener::OnFdAboutToOrphan() {
+ gpr_mu_lock(&mutex_);
+ grpc_unlink_if_unix_domain_socket(&addr_);
+
+ GRPC_CLOSURE_INIT(&destroyed_closure_, destroyed_port, server_,
+ grpc_schedule_on_exec_ctx);
+ if (!orphan_notified_ && udp_handler_ != nullptr) {
+ /* Singals udp_handler that the FD is about to be closed and
+ * should no longer be used. */
+ GRPC_CLOSURE_INIT(&orphan_fd_closure_, shutdown_fd, this,
+ grpc_schedule_on_exec_ctx);
+ gpr_log(GPR_DEBUG, "fd %d about to be orphaned", fd_);
+ udp_handler_->OnFdAboutToOrphan(&orphan_fd_closure_, server_->user_data);
+ orphan_notified_ = true;
+ }
+ gpr_mu_unlock(&mutex_);
+}
+
static int bind_socket(grpc_socket_factory* socket_factory, int sockfd,
const grpc_resolved_address* addr) {
return (socket_factory != nullptr)
? grpc_socket_factory_bind(socket_factory, sockfd, addr)
: bind(sockfd,
- reinterpret_cast<struct sockaddr*>(
+ reinterpret_cast<grpc_sockaddr*>(
const_cast<char*>(addr->addr)),
static_cast<socklen_t>(addr->len));
}
@@ -294,8 +355,8 @@ static int prepare_socket(grpc_socket_factory* socket_factory, int fd,
const grpc_resolved_address* addr, int rcv_buf_size,
int snd_buf_size) {
grpc_resolved_address sockname_temp;
- struct sockaddr* addr_ptr =
- reinterpret_cast<struct sockaddr*>(const_cast<char*>(addr->addr));
+ grpc_sockaddr* addr_ptr =
+ reinterpret_cast<grpc_sockaddr*>(const_cast<char*>(addr->addr));
if (fd < 0) {
goto error;
@@ -331,7 +392,7 @@ static int prepare_socket(grpc_socket_factory* socket_factory, int fd,
sockname_temp.len = sizeof(struct sockaddr_storage);
- if (getsockname(fd, reinterpret_cast<struct sockaddr*>(sockname_temp.addr),
+ if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
reinterpret_cast<socklen_t*>(&sockname_temp.len)) < 0) {
goto error;
}
@@ -364,163 +425,140 @@ error:
return -1;
}
-static void do_read(void* arg, grpc_error* error) {
- grpc_udp_listener* sp = reinterpret_cast<grpc_udp_listener*>(arg);
- GPR_ASSERT(sp->read_cb && error == GRPC_ERROR_NONE);
+// static
+void GrpcUdpListener::do_read(void* arg, grpc_error* error) {
+ GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
/* TODO: the reason we hold server->mu here is merely to prevent fd
* shutdown while we are reading. However, it blocks do_write(). Switch to
* read lock if available. */
- gpr_mu_lock(&sp->server->mu);
+ gpr_mu_lock(sp->mutex());
/* Tell the registered callback that data is available to read. */
- if (!sp->already_shutdown && sp->read_cb(sp->emfd)) {
+ if (!sp->already_shutdown_ && sp->udp_handler_->Read()) {
/* There maybe more packets to read. Schedule read_more_cb_ closure to run
* after finishing this event loop. */
- GRPC_CLOSURE_SCHED(&sp->do_read_closure, GRPC_ERROR_NONE);
+ GRPC_CLOSURE_SCHED(&sp->do_read_closure_, GRPC_ERROR_NONE);
} else {
/* Finish reading all the packets, re-arm the notification event so we can
* get another chance to read. Or fd already shutdown, re-arm to get a
* notification with shutdown error. */
- grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
+ grpc_fd_notify_on_read(sp->emfd_, &sp->read_closure_);
}
- gpr_mu_unlock(&sp->server->mu);
+ gpr_mu_unlock(sp->mutex());
}
-/* event manager callback when reads are ready */
-static void on_read(void* arg, grpc_error* error) {
- grpc_udp_listener* sp = static_cast<grpc_udp_listener*>(arg);
+// static
+void GrpcUdpListener::on_read(void* arg, grpc_error* error) {
+ GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+ sp->OnRead(error, arg);
+}
- gpr_mu_lock(&sp->server->mu);
+void GrpcUdpListener::OnRead(grpc_error* error, void* do_read_arg) {
if (error != GRPC_ERROR_NONE) {
- if (0 == --sp->server->active_ports && sp->server->shutdown) {
- gpr_mu_unlock(&sp->server->mu);
- deactivated_all_ports(sp->server);
+ gpr_mu_lock(&server_->mu);
+ if (0 == --server_->active_ports && server_->shutdown) {
+ gpr_mu_unlock(&server_->mu);
+ deactivated_all_ports(server_);
} else {
- gpr_mu_unlock(&sp->server->mu);
+ gpr_mu_unlock(&server_->mu);
}
return;
}
+
/* Read once. If there is more data to read, off load the work to another
* thread to finish. */
- GPR_ASSERT(sp->read_cb);
- if (sp->read_cb(sp->emfd)) {
+ if (udp_handler_->Read()) {
/* There maybe more packets to read. Schedule read_more_cb_ closure to run
* after finishing this event loop. */
- GRPC_CLOSURE_INIT(&sp->do_read_closure, do_read, arg,
+ GRPC_CLOSURE_INIT(&do_read_closure_, do_read, do_read_arg,
grpc_executor_scheduler(GRPC_EXECUTOR_LONG));
- GRPC_CLOSURE_SCHED(&sp->do_read_closure, GRPC_ERROR_NONE);
+ GRPC_CLOSURE_SCHED(&do_read_closure_, GRPC_ERROR_NONE);
} else {
/* Finish reading all the packets, re-arm the notification event so we can
* get another chance to read. Or fd already shutdown, re-arm to get a
* notification with shutdown error. */
- grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
+ grpc_fd_notify_on_read(emfd_, &read_closure_);
}
- gpr_mu_unlock(&sp->server->mu);
}
+// static
// Wrapper of grpc_fd_notify_on_write() with a grpc_closure callback interface.
-void fd_notify_on_write_wrapper(void* arg, grpc_error* error) {
- grpc_udp_listener* sp = reinterpret_cast<grpc_udp_listener*>(arg);
- gpr_mu_lock(&sp->server->mu);
- if (!sp->notify_on_write_armed) {
- grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
- sp->notify_on_write_armed = true;
- }
- gpr_mu_unlock(&sp->server->mu);
+void GrpcUdpListener::fd_notify_on_write_wrapper(void* arg, grpc_error* error) {
+ GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+ gpr_mu_lock(sp->mutex());
+ if (!sp->notify_on_write_armed_) {
+ grpc_fd_notify_on_write(sp->emfd_, &sp->write_closure_);
+ sp->notify_on_write_armed_ = true;
+ }
+ gpr_mu_unlock(sp->mutex());
}
-static void do_write(void* arg, grpc_error* error) {
- grpc_udp_listener* sp = reinterpret_cast<grpc_udp_listener*>(arg);
- gpr_mu_lock(&sp->server->mu);
- if (sp->already_shutdown) {
+// static
+void GrpcUdpListener::do_write(void* arg, grpc_error* error) {
+ GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+ gpr_mu_lock(sp->mutex());
+ if (sp->already_shutdown_) {
// If fd has been shutdown, don't write any more and re-arm notification.
- grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
+ grpc_fd_notify_on_write(sp->emfd_, &sp->write_closure_);
} else {
- sp->notify_on_write_armed = false;
+ sp->notify_on_write_armed_ = false;
/* Tell the registered callback that the socket is writeable. */
- GPR_ASSERT(sp->write_cb && error == GRPC_ERROR_NONE);
- GRPC_CLOSURE_INIT(&sp->notify_on_write_closure, fd_notify_on_write_wrapper,
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ GRPC_CLOSURE_INIT(&sp->notify_on_write_closure_, fd_notify_on_write_wrapper,
arg, grpc_schedule_on_exec_ctx);
- sp->write_cb(sp->emfd, sp->server->user_data, &sp->notify_on_write_closure);
+ sp->udp_handler_->OnCanWrite(sp->server_->user_data,
+ &sp->notify_on_write_closure_);
}
- gpr_mu_unlock(&sp->server->mu);
+ gpr_mu_unlock(sp->mutex());
}
-static void on_write(void* arg, grpc_error* error) {
- grpc_udp_listener* sp = static_cast<grpc_udp_listener*>(arg);
+// static
+void GrpcUdpListener::on_write(void* arg, grpc_error* error) {
+ GrpcUdpListener* sp = static_cast<GrpcUdpListener*>(arg);
+ sp->OnCanWrite(error, arg);
+}
- gpr_mu_lock(&sp->server->mu);
+void GrpcUdpListener::OnCanWrite(grpc_error* error, void* do_write_arg) {
if (error != GRPC_ERROR_NONE) {
- if (0 == --sp->server->active_ports && sp->server->shutdown) {
- gpr_mu_unlock(&sp->server->mu);
- deactivated_all_ports(sp->server);
+ gpr_mu_lock(&server_->mu);
+ if (0 == --server_->active_ports && server_->shutdown) {
+ gpr_mu_unlock(&server_->mu);
+ deactivated_all_ports(server_);
} else {
- gpr_mu_unlock(&sp->server->mu);
+ gpr_mu_unlock(&server_->mu);
}
return;
}
/* Schedule actual write in another thread. */
- GRPC_CLOSURE_INIT(&sp->do_write_closure, do_write, arg,
+ GRPC_CLOSURE_INIT(&do_write_closure_, do_write, do_write_arg,
grpc_executor_scheduler(GRPC_EXECUTOR_LONG));
- GRPC_CLOSURE_SCHED(&sp->do_write_closure, GRPC_ERROR_NONE);
- gpr_mu_unlock(&sp->server->mu);
+ GRPC_CLOSURE_SCHED(&do_write_closure_, GRPC_ERROR_NONE);
}
static int add_socket_to_server(grpc_udp_server* s, int fd,
const grpc_resolved_address* addr,
- int rcv_buf_size, int snd_buf_size,
- grpc_udp_server_start_cb start_cb,
- grpc_udp_server_read_cb read_cb,
- grpc_udp_server_write_cb write_cb,
- grpc_udp_server_orphan_cb orphan_cb) {
- grpc_udp_listener* sp;
- int port;
- char* addr_str;
- char* name;
+ int rcv_buf_size, int snd_buf_size) {
+ gpr_log(GPR_DEBUG, "add socket %d to server", fd);
- port =
+ int port =
prepare_socket(s->socket_factory, fd, addr, rcv_buf_size, snd_buf_size);
if (port >= 0) {
- grpc_sockaddr_to_string(&addr_str, addr, 1);
- gpr_asprintf(&name, "udp-server-listener:%s", addr_str);
- gpr_free(addr_str);
gpr_mu_lock(&s->mu);
- s->nports++;
- sp = static_cast<grpc_udp_listener*>(gpr_malloc(sizeof(grpc_udp_listener)));
- sp->next = nullptr;
- if (s->head == nullptr) {
- s->head = sp;
- } else {
- s->tail->next = sp;
- }
- s->tail = sp;
- sp->server = s;
- sp->fd = fd;
- sp->emfd = grpc_fd_create(fd, name);
- memcpy(&sp->addr, addr, sizeof(grpc_resolved_address));
- sp->read_cb = read_cb;
- sp->write_cb = write_cb;
- sp->orphan_cb = orphan_cb;
- sp->start_cb = start_cb;
- sp->orphan_notified = false;
- sp->already_shutdown = false;
- GPR_ASSERT(sp->emfd);
+ s->listeners.emplace_back(s, fd, addr);
+ gpr_log(GPR_DEBUG,
+ "add socket %d to server for port %d, %zu listener(s) in total", fd,
+ port, s->listeners.size());
gpr_mu_unlock(&s->mu);
- gpr_free(name);
}
-
return port;
}
int grpc_udp_server_add_port(grpc_udp_server* s,
const grpc_resolved_address* addr,
int rcv_buf_size, int snd_buf_size,
- grpc_udp_server_start_cb start_cb,
- grpc_udp_server_read_cb read_cb,
- grpc_udp_server_write_cb write_cb,
- grpc_udp_server_orphan_cb orphan_cb) {
- grpc_udp_listener* sp;
+ GrpcUdpHandlerFactory* handler_factory) {
int allocated_port1 = -1;
int allocated_port2 = -1;
int fd;
@@ -536,12 +574,11 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
/* Check if this is a wildcard port, and if so, try to keep the port the same
as some previously created listener. */
if (grpc_sockaddr_get_port(addr) == 0) {
- for (sp = s->head; sp; sp = sp->next) {
+ for (size_t i = 0; i < s->listeners.size(); ++i) {
sockname_temp.len = sizeof(struct sockaddr_storage);
- if (0 ==
- getsockname(sp->fd,
- reinterpret_cast<struct sockaddr*>(sockname_temp.addr),
- reinterpret_cast<socklen_t*>(&sockname_temp.len))) {
+ if (0 == getsockname(s->listeners[i].fd(),
+ reinterpret_cast<grpc_sockaddr*>(sockname_temp.addr),
+ reinterpret_cast<socklen_t*>(&sockname_temp.len))) {
port = grpc_sockaddr_get_port(&sockname_temp);
if (port > 0) {
allocated_addr = static_cast<grpc_resolved_address*>(
@@ -559,6 +596,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
addr = &addr6_v4mapped;
}
+ s->handler_factory = handler_factory;
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
if (grpc_sockaddr_is_wildcard(addr, &port)) {
grpc_sockaddr_make_wildcards(port, &wild4, &wild6);
@@ -569,8 +607,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
GRPC_ERROR_UNREF(grpc_create_dualstack_socket_using_factory(
s->socket_factory, addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd));
allocated_port1 =
- add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size, start_cb,
- read_cb, write_cb, orphan_cb);
+ add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
}
@@ -593,8 +630,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s,
addr = &addr4_copy;
}
allocated_port2 =
- add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size, start_cb,
- read_cb, write_cb, orphan_cb);
+ add_socket_to_server(s, fd, addr, rcv_buf_size, snd_buf_size);
done:
gpr_free(allocated_addr);
@@ -602,52 +638,55 @@ done:
}
int grpc_udp_server_get_fd(grpc_udp_server* s, unsigned port_index) {
- grpc_udp_listener* sp;
- if (port_index >= s->nports) {
+ if (port_index >= s->listeners.size()) {
return -1;
}
- for (sp = s->head; sp && port_index != 0; sp = sp->next) {
- --port_index;
- }
- GPR_ASSERT(sp); // if this fails, our check earlier was bogus
- return sp->fd;
+ return s->listeners[port_index].fd();
}
void grpc_udp_server_start(grpc_udp_server* s, grpc_pollset** pollsets,
size_t pollset_count, void* user_data) {
gpr_log(GPR_DEBUG, "grpc_udp_server_start");
- size_t i;
gpr_mu_lock(&s->mu);
- grpc_udp_listener* sp;
GPR_ASSERT(s->active_ports == 0);
s->pollsets = pollsets;
s->user_data = user_data;
- sp = s->head;
- while (sp != nullptr) {
- sp->start_cb(sp->emfd, sp->server->user_data);
- for (i = 0; i < pollset_count; i++) {
- grpc_pollset_add_fd(pollsets[i], sp->emfd);
- }
- GRPC_CLOSURE_INIT(&sp->read_closure, on_read, sp,
- grpc_schedule_on_exec_ctx);
- grpc_fd_notify_on_read(sp->emfd, &sp->read_closure);
+ for (size_t i = 0; i < s->listeners.size(); ++i) {
+ s->listeners[i].StartListening(pollsets, pollset_count, s->handler_factory);
+ }
- GRPC_CLOSURE_INIT(&sp->write_closure, on_write, sp,
- grpc_schedule_on_exec_ctx);
- sp->notify_on_write_armed = true;
- grpc_fd_notify_on_write(sp->emfd, &sp->write_closure);
+ gpr_mu_unlock(&s->mu);
+}
- /* Registered for both read and write callbacks: increment active_ports
- * twice to account for this, and delay free-ing of memory until both
- * on_read and on_write have fired. */
- s->active_ports += 2;
+void GrpcUdpListener::StartListening(grpc_pollset** pollsets,
+ size_t pollset_count,
+ GrpcUdpHandlerFactory* handler_factory) {
+ gpr_mu_lock(&mutex_);
+ handler_factory_ = handler_factory;
+ udp_handler_ = handler_factory->CreateUdpHandler(emfd_, server_->user_data);
+ for (size_t i = 0; i < pollset_count; i++) {
+ grpc_pollset_add_fd(pollsets[i], emfd_);
+ }
+ GRPC_CLOSURE_INIT(&read_closure_, on_read, this, grpc_schedule_on_exec_ctx);
+ grpc_fd_notify_on_read(emfd_, &read_closure_);
+
+ GRPC_CLOSURE_INIT(&write_closure_, on_write, this, grpc_schedule_on_exec_ctx);
+ notify_on_write_armed_ = true;
+ grpc_fd_notify_on_write(emfd_, &write_closure_);
+
+ /* Registered for both read and write callbacks: increment active_ports
+ * twice to account for this, and delay free-ing of memory until both
+ * on_read and on_write have fired. */
+ server_->active_ports += 2;
+ gpr_mu_unlock(&mutex_);
+}
- sp = sp->next;
+void GrpcUdpListener::OnDestroy() {
+ if (udp_handler_ != nullptr) {
+ handler_factory_->DestroyUdpHandler(udp_handler_);
}
-
- gpr_mu_unlock(&s->mu);
}
#endif
diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h
index 1be4d04dbb..4e384d2cdf 100644
--- a/src/core/lib/iomgr/udp_server.h
+++ b/src/core/lib/iomgr/udp_server.h
@@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
+#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/resolve_address.h"
@@ -32,22 +33,46 @@ struct grpc_server;
/* Forward decl of grpc_udp_server */
typedef struct grpc_udp_server grpc_udp_server;
-/* Called when grpc server starts to listening on the grpc_fd. */
-typedef void (*grpc_udp_server_start_cb)(grpc_fd* emfd, void* user_data);
-
-/* Called when data is available to read from the socket.
- * Return true if there is more data to read from fd. */
-typedef bool (*grpc_udp_server_read_cb)(grpc_fd* emfd);
-
-/* Called when the socket is writeable. The given closure should be scheduled
- * when the socket becomes blocked next time. */
-typedef void (*grpc_udp_server_write_cb)(grpc_fd* emfd, void* user_data,
- grpc_closure* notify_on_write_closure);
-
-/* Called when the grpc_fd is about to be orphaned (and the FD closed). */
-typedef void (*grpc_udp_server_orphan_cb)(grpc_fd* emfd,
- grpc_closure* shutdown_fd_callback,
- void* user_data);
+/* An interface associated with a socket. udp server delivers I/O event on that
+ * socket to the subclass of this interface which is created through
+ * GrpcUdpHandlerFactory.
+ * Its implementation should do the real IO work, e.g. read packet and write. */
+class GrpcUdpHandler {
+ public:
+ GrpcUdpHandler(grpc_fd* emfd, void* user_data) {}
+ virtual ~GrpcUdpHandler() {}
+
+ // Interfaces to be implemented by subclasses to do the actual setup/tear down
+ // or I/O.
+
+ // Called when data is available to read from the socket. Returns true if
+ // there is more data to read after this call.
+ virtual bool Read() GRPC_ABSTRACT;
+ // Called when socket becomes write unblocked. The given closure should be
+ // scheduled when the socket becomes blocked next time.
+ virtual void OnCanWrite(void* user_data,
+ grpc_closure* notify_on_write_closure) GRPC_ABSTRACT;
+ // Called before the gRPC FD is orphaned. Notify udp server to continue
+ // orphaning fd by scheduling the given closure, afterwards the associated fd
+ // will be closed.
+ virtual void OnFdAboutToOrphan(grpc_closure* orphan_fd_closure,
+ void* user_data) GRPC_ABSTRACT;
+
+ GRPC_ABSTRACT_BASE_CLASS
+};
+
+class GrpcUdpHandlerFactory {
+ public:
+ virtual ~GrpcUdpHandlerFactory() {}
+ /* Called when start to listen on a socket.
+ * Return an instance of the implementation of GrpcUdpHandler interface which
+ * will process I/O events for this socket from now on. */
+ virtual GrpcUdpHandler* CreateUdpHandler(grpc_fd* emfd,
+ void* user_data) GRPC_ABSTRACT;
+ virtual void DestroyUdpHandler(GrpcUdpHandler* handler) GRPC_ABSTRACT;
+
+ GRPC_ABSTRACT_BASE_CLASS
+};
/* Create a server, initially not bound to any ports */
grpc_udp_server* grpc_udp_server_create(const grpc_channel_args* args);
@@ -71,10 +96,7 @@ int grpc_udp_server_get_fd(grpc_udp_server* s, unsigned port_index);
int grpc_udp_server_add_port(grpc_udp_server* s,
const grpc_resolved_address* addr,
int rcv_buf_size, int snd_buf_size,
- grpc_udp_server_start_cb start_cb,
- grpc_udp_server_read_cb read_cb,
- grpc_udp_server_write_cb write_cb,
- grpc_udp_server_orphan_cb orphan_cb);
+ GrpcUdpHandlerFactory* handler_factory);
void grpc_udp_server_destroy(grpc_udp_server* server, grpc_closure* on_done);
diff --git a/src/core/lib/iomgr/unix_sockets_posix.cc b/src/core/lib/iomgr/unix_sockets_posix.cc
index 8d252fd331..5d09b4a9b1 100644
--- a/src/core/lib/iomgr/unix_sockets_posix.cc
+++ b/src/core/lib/iomgr/unix_sockets_posix.cc
@@ -66,15 +66,15 @@ grpc_error* grpc_resolve_unix_domain_address(const char* name,
}
int grpc_is_unix_socket(const grpc_resolved_address* resolved_addr) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
return addr->sa_family == AF_UNIX;
}
void grpc_unlink_if_unix_domain_socket(
const grpc_resolved_address* resolved_addr) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
if (addr->sa_family != AF_UNIX) {
return;
}
@@ -89,8 +89,8 @@ void grpc_unlink_if_unix_domain_socket(
char* grpc_sockaddr_to_uri_unix_if_possible(
const grpc_resolved_address* resolved_addr) {
- const struct sockaddr* addr =
- reinterpret_cast<const struct sockaddr*>(resolved_addr->addr);
+ const grpc_sockaddr* addr =
+ reinterpret_cast<const grpc_sockaddr*>(resolved_addr->addr);
if (addr->sa_family != AF_UNIX) {
return nullptr;
}
diff --git a/src/core/lib/iomgr/wakeup_fd_cv.cc b/src/core/lib/iomgr/wakeup_fd_cv.cc
index ee322105ae..74faa6379e 100644
--- a/src/core/lib/iomgr/wakeup_fd_cv.cc
+++ b/src/core/lib/iomgr/wakeup_fd_cv.cc
@@ -32,8 +32,8 @@
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
-#include "src/core/lib/gpr/thd.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/thd.h"
#define MAX_TABLE_RESIZE 256
diff --git a/src/core/lib/profiling/basic_timers.cc b/src/core/lib/profiling/basic_timers.cc
index ca6705a6b3..43384fd0ca 100644
--- a/src/core/lib/profiling/basic_timers.cc
+++ b/src/core/lib/profiling/basic_timers.cc
@@ -30,7 +30,7 @@
#include <string.h>
#include "src/core/lib/gpr/env.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type;
@@ -68,7 +68,7 @@ static pthread_cond_t g_cv;
static gpr_timer_log_list g_in_progress_logs;
static gpr_timer_log_list g_done_logs;
static int g_shutdown;
-static gpr_thd_id g_writing_thread;
+static grpc_core::Thread* g_writing_thread;
static __thread int g_thread_id;
static int g_next_thread_id;
static int g_writing_enabled = 1;
@@ -182,7 +182,8 @@ static void finish_writing(void) {
g_shutdown = 1;
pthread_cond_signal(&g_cv);
pthread_mutex_unlock(&g_mu);
- gpr_thd_join(g_writing_thread);
+ g_writing_thread->Join();
+ grpc_core::Delete(g_writing_thread);
gpr_log(GPR_INFO, "flushing logs");
@@ -201,10 +202,8 @@ void gpr_timers_set_log_filename(const char* filename) {
}
static void init_output() {
- gpr_thd_options options = gpr_thd_options_default();
- gpr_thd_options_set_joinable(&options);
- GPR_ASSERT(gpr_thd_new(&g_writing_thread, "timer_output_thread",
- writing_thread, NULL, &options));
+ g_writing_thread = grpc_core::New<grpc_core::Thread>("timer_output_thread",
+ writing_thread, nullptr);
atexit(finish_writing);
}
diff --git a/src/core/lib/security/credentials/alts/alts_credentials.cc b/src/core/lib/security/credentials/alts/alts_credentials.cc
new file mode 100644
index 0000000000..fa05d901bf
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/alts_credentials.cc
@@ -0,0 +1,119 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/credentials/alts/alts_credentials.h"
+
+#include <cstring>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+#include "src/core/lib/security/security_connector/alts_security_connector.h"
+
+#define GRPC_CREDENTIALS_TYPE_ALTS "Alts"
+#define GRPC_ALTS_HANDSHAKER_SERVICE_URL "metadata.google.internal:8080"
+
+static void alts_credentials_destruct(grpc_channel_credentials* creds) {
+ grpc_alts_credentials* alts_creds =
+ reinterpret_cast<grpc_alts_credentials*>(creds);
+ grpc_alts_credentials_options_destroy(alts_creds->options);
+ gpr_free(alts_creds->handshaker_service_url);
+}
+
+static void alts_server_credentials_destruct(grpc_server_credentials* creds) {
+ grpc_alts_server_credentials* alts_creds =
+ reinterpret_cast<grpc_alts_server_credentials*>(creds);
+ grpc_alts_credentials_options_destroy(alts_creds->options);
+ gpr_free(alts_creds->handshaker_service_url);
+}
+
+static grpc_security_status alts_create_security_connector(
+ grpc_channel_credentials* creds,
+ grpc_call_credentials* request_metadata_creds, const char* target_name,
+ const grpc_channel_args* args, grpc_channel_security_connector** sc,
+ grpc_channel_args** new_args) {
+ return grpc_alts_channel_security_connector_create(
+ creds, request_metadata_creds, target_name, sc);
+}
+
+static grpc_security_status alts_server_create_security_connector(
+ grpc_server_credentials* creds, grpc_server_security_connector** sc) {
+ return grpc_alts_server_security_connector_create(creds, sc);
+}
+
+static const grpc_channel_credentials_vtable alts_credentials_vtable = {
+ alts_credentials_destruct, alts_create_security_connector,
+ /*duplicate_without_call_credentials=*/nullptr};
+
+static const grpc_server_credentials_vtable alts_server_credentials_vtable = {
+ alts_server_credentials_destruct, alts_server_create_security_connector};
+
+grpc_channel_credentials* grpc_alts_credentials_create_customized(
+ const grpc_alts_credentials_options* options,
+ const char* handshaker_service_url, bool enable_untrusted_alts) {
+ if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) {
+ return nullptr;
+ }
+ auto creds = static_cast<grpc_alts_credentials*>(
+ gpr_zalloc(sizeof(grpc_alts_credentials)));
+ creds->options = grpc_alts_credentials_options_copy(options);
+ creds->handshaker_service_url =
+ handshaker_service_url == nullptr
+ ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
+ : gpr_strdup(handshaker_service_url);
+ creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS;
+ creds->base.vtable = &alts_credentials_vtable;
+ gpr_ref_init(&creds->base.refcount, 1);
+ return &creds->base;
+}
+
+grpc_server_credentials* grpc_alts_server_credentials_create_customized(
+ const grpc_alts_credentials_options* options,
+ const char* handshaker_service_url, bool enable_untrusted_alts) {
+ if (!enable_untrusted_alts && !grpc_alts_is_running_on_gcp()) {
+ return nullptr;
+ }
+ auto creds = static_cast<grpc_alts_server_credentials*>(
+ gpr_zalloc(sizeof(grpc_alts_server_credentials)));
+ creds->options = grpc_alts_credentials_options_copy(options);
+ creds->handshaker_service_url =
+ handshaker_service_url == nullptr
+ ? gpr_strdup(GRPC_ALTS_HANDSHAKER_SERVICE_URL)
+ : gpr_strdup(handshaker_service_url);
+ creds->base.type = GRPC_CREDENTIALS_TYPE_ALTS;
+ creds->base.vtable = &alts_server_credentials_vtable;
+ gpr_ref_init(&creds->base.refcount, 1);
+ return &creds->base;
+}
+
+grpc_channel_credentials* grpc_alts_credentials_create(
+ const grpc_alts_credentials_options* options) {
+ return grpc_alts_credentials_create_customized(
+ options, GRPC_ALTS_HANDSHAKER_SERVICE_URL, false);
+}
+
+grpc_server_credentials* grpc_alts_server_credentials_create(
+ const grpc_alts_credentials_options* options) {
+ return grpc_alts_server_credentials_create_customized(
+ options, GRPC_ALTS_HANDSHAKER_SERVICE_URL, false);
+}
diff --git a/src/core/lib/security/credentials/alts/alts_credentials.h b/src/core/lib/security/credentials/alts/alts_credentials.h
new file mode 100644
index 0000000000..621789cf65
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/alts_credentials.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H
+#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/grpc_security.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+#include "src/core/lib/security/credentials/credentials.h"
+
+/* Main struct for grpc ALTS channel credential. */
+typedef struct grpc_alts_credentials {
+ grpc_channel_credentials base;
+ grpc_alts_credentials_options* options;
+ char* handshaker_service_url;
+} grpc_alts_credentials;
+
+/* Main struct for grpc ALTS server credential. */
+typedef struct grpc_alts_server_credentials {
+ grpc_server_credentials base;
+ grpc_alts_credentials_options* options;
+ char* handshaker_service_url;
+} grpc_alts_server_credentials;
+
+/**
+ * This method creates an ALTS channel credential object.
+ *
+ * - options: grpc ALTS credentials options instance for client.
+ *
+ * It returns the created ALTS channel credential object.
+ */
+grpc_channel_credentials* grpc_alts_credentials_create(
+ const grpc_alts_credentials_options* options);
+
+/**
+ * This method creates an ALTS server credential object.
+ *
+ * - options: grpc ALTS credentials options instance for server.
+ *
+ * It returns the created ALTS server credential object.
+ */
+grpc_server_credentials* grpc_alts_server_credentials_create(
+ const grpc_alts_credentials_options* options);
+
+/**
+ * This method creates an ALTS channel credential object with customized
+ * information provided by caller.
+ *
+ * - options: grpc ALTS credentials options instance for client.
+ * - handshaker_service_url: address of ALTS handshaker service in the format of
+ * "host:port". If it's nullptr, the address of default metadata server will
+ * be used.
+ * - enable_untrusted_alts: a boolean flag used to enable ALTS in untrusted
+ * mode. This mode can be enabled when we are sure ALTS is running on GCP or
+ * for testing purpose.
+ *
+ * It returns nullptr if the flag is disabled AND ALTS is not running on GCP.
+ * Otherwise, it returns the created credential object.
+ */
+
+grpc_channel_credentials* grpc_alts_credentials_create_customized(
+ const grpc_alts_credentials_options* options,
+ const char* handshaker_service_url, bool enable_untrusted_alts);
+
+/**
+ * This method creates an ALTS server credential object with customized
+ * information provided by caller.
+ *
+ * - options: grpc ALTS credentials options instance for server.
+ * - handshaker_service_url: address of ALTS handshaker service in the format of
+ * "host:port". If it's nullptr, the address of default metadata server will
+ * be used.
+ * - enable_untrusted_alts: a boolean flag used to enable ALTS in untrusted
+ * mode. This mode can be enabled when we are sure ALTS is running on GCP or
+ * for testing purpose.
+ *
+ * It returns nullptr if the flag is disabled and ALTS is not running on GCP.
+ * Otherwise, it returns the created credential object.
+ */
+grpc_server_credentials* grpc_alts_server_credentials_create_customized(
+ const grpc_alts_credentials_options* options,
+ const char* handshaker_service_url, bool enable_untrusted_alts);
+
+#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_ALTS_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment.cc b/src/core/lib/security/credentials/alts/check_gcp_environment.cc
new file mode 100644
index 0000000000..96807876cf
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment.cc
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+const size_t kBiosDataBufferSize = 256;
+
+static char* trim(const char* src) {
+ if (src == nullptr) {
+ return nullptr;
+ }
+ char* des = nullptr;
+ size_t start = 0, end = strlen(src) - 1;
+ /* find the last character that is not a whitespace. */
+ while (end != 0 && isspace(src[end])) {
+ end--;
+ }
+ /* find the first character that is not a whitespace. */
+ while (start < strlen(src) && isspace(src[start])) {
+ start++;
+ }
+ if (start <= end) {
+ des = static_cast<char*>(
+ gpr_zalloc(sizeof(char) * (end - start + 2 /* '\0' */)));
+ memcpy(des, src + start, end - start + 1);
+ }
+ return des;
+}
+
+namespace grpc_core {
+namespace internal {
+
+char* read_bios_file(const char* bios_file) {
+ FILE* fp = fopen(bios_file, "r");
+ if (!fp) {
+ gpr_log(GPR_ERROR, "BIOS data file cannot be opened.");
+ return nullptr;
+ }
+ char buf[kBiosDataBufferSize + 1];
+ size_t ret = fread(buf, sizeof(char), kBiosDataBufferSize, fp);
+ buf[ret] = '\0';
+ char* trimmed_buf = trim(buf);
+ fclose(fp);
+ return trimmed_buf;
+}
+
+} // namespace internal
+} // namespace grpc_core
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment.h b/src/core/lib/security/credentials/alts/check_gcp_environment.h
new file mode 100644
index 0000000000..aea4cea643
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H
+#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H
+
+namespace grpc_core {
+namespace internal {
+
+/**
+ * This method is a helper function that reads a file containing system bios
+ * data. Exposed for testing only.
+ *
+ * - bios_file: a file containing BIOS data used to determine GCE tenancy
+ * information.
+ *
+ * It returns a buffer containing the data read from the file.
+ */
+char* read_bios_file(const char* bios_file);
+
+/**
+ * This method checks if system BIOS data contains Google-specific phrases.
+ * Exposed for testing only.
+ *
+ * - bios_data: a buffer containing system BIOS data.
+ *
+ * It returns true if the BIOS data contains Google-specific phrases, and false
+ * otherwise.
+ */
+bool check_bios_data(const char* bios_data);
+
+} // namespace internal
+} // namespace grpc_core
+
+/**
+ * This method checks if a VM (Windows or Linux) is running within Google
+ * compute Engine (GCE) or not. It returns true if the VM is running in GCE and
+ * false otherwise.
+ */
+bool grpc_alts_is_running_on_gcp();
+
+#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_CHECK_GCP_ENVIRONMENT_H */
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc b/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
new file mode 100644
index 0000000000..7c4d7a71cd
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_LINUX
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/sync.h>
+
+#include <string.h>
+
+#define GRPC_ALTS_EXPECT_NAME_GOOGLE "Google"
+#define GRPC_ALTS_EXPECT_NAME_GCE "Google Compute Engine"
+#define GRPC_ALTS_PRODUCT_NAME_FILE "/sys/class/dmi/id/product_name"
+
+static bool g_compute_engine_detection_done = false;
+static bool g_is_on_compute_engine = false;
+static gpr_mu g_mu;
+static gpr_once g_once = GPR_ONCE_INIT;
+
+namespace grpc_core {
+namespace internal {
+
+bool check_bios_data(const char* bios_data_file) {
+ char* bios_data = read_bios_file(bios_data_file);
+ bool result = (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE)) ||
+ (!strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GCE));
+ gpr_free(bios_data);
+ return result;
+}
+
+} // namespace internal
+} // namespace grpc_core
+
+static void init_mu(void) { gpr_mu_init(&g_mu); }
+
+bool grpc_alts_is_running_on_gcp() {
+ gpr_once_init(&g_once, init_mu);
+ gpr_mu_lock(&g_mu);
+ if (!g_compute_engine_detection_done) {
+ g_is_on_compute_engine =
+ grpc_core::internal::check_bios_data(GRPC_ALTS_PRODUCT_NAME_FILE);
+ g_compute_engine_detection_done = true;
+ }
+ gpr_mu_unlock(&g_mu);
+ return g_is_on_compute_engine;
+}
+
+#endif // GPR_LINUX
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc b/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
new file mode 100644
index 0000000000..d97681b86d
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#if !defined(GPR_LINUX) && !defined(GPR_WINDOWS)
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <grpc/support/log.h>
+
+bool grpc_alts_is_running_on_gcp() {
+ gpr_log(GPR_ERROR,
+ "Platforms other than Linux and Windows are not supported");
+ return false;
+}
+
+#endif // !defined(LINUX) && !defined(GPR_WINDOWS)
diff --git a/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc b/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
new file mode 100644
index 0000000000..55efe0e9dd
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
@@ -0,0 +1,114 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINDOWS
+
+#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
+
+#include <shellapi.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <windows.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#define GRPC_ALTS_EXPECT_NAME_GOOGLE "Google"
+#define GRPC_ALTS_WINDOWS_CHECK_COMMAND "powershell.exe"
+#define GRPC_ALTS_WINDOWS_CHECK_COMMAND_ARGS \
+ "(Get-WmiObject -Class Win32_BIOS).Manufacturer"
+#define GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE "windows_bios.data"
+
+const size_t kBiosDataBufferSize = 256;
+
+static bool g_compute_engine_detection_done = false;
+static bool g_is_on_compute_engine = false;
+static gpr_mu g_mu;
+static gpr_once g_once = GPR_ONCE_INIT;
+
+namespace grpc_core {
+namespace internal {
+
+bool check_bios_data(const char* bios_data_file) {
+ char* bios_data = read_bios_file(bios_data_file);
+ bool result = !strcmp(bios_data, GRPC_ALTS_EXPECT_NAME_GOOGLE);
+ remove(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE);
+ gpr_free(bios_data);
+ return result;
+}
+
+} // namespace internal
+} // namespace grpc_core
+
+static void init_mu(void) { gpr_mu_init(&g_mu); }
+
+static bool run_powershell() {
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+ HANDLE h = CreateFile(_T(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE), GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ gpr_log(GPR_ERROR, "CreateFile failed (%d).", GetLastError());
+ return false;
+ }
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ DWORD flags = CREATE_NO_WINDOW;
+ ZeroMemory(&pi, sizeof(pi));
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ si.hStdInput = NULL;
+ si.hStdError = h;
+ si.hStdOutput = h;
+ TCHAR cmd[kBiosDataBufferSize];
+ _sntprintf(cmd, kBiosDataBufferSize, _T("%s %s"),
+ _T(GRPC_ALTS_WINDOWS_CHECK_COMMAND),
+ _T(GRPC_ALTS_WINDOWS_CHECK_COMMAND_ARGS));
+ if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si,
+ &pi)) {
+ gpr_log(GPR_ERROR, "CreateProcess failed (%d).\n", GetLastError());
+ return false;
+ }
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ CloseHandle(h);
+ return true;
+}
+
+bool grpc_alts_is_running_on_gcp() {
+ gpr_once_init(&g_once, init_mu);
+ gpr_mu_lock(&g_mu);
+ if (!g_compute_engine_detection_done) {
+ g_is_on_compute_engine =
+ run_powershell() &&
+ grpc_core::internal::check_bios_data(GRPC_ALTS_WINDOWS_CHECK_BIOS_FILE);
+ g_compute_engine_detection_done = true;
+ }
+ gpr_mu_unlock(&g_mu);
+ return g_is_on_compute_engine;
+}
+
+#endif // GPR_WINDOWS
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
new file mode 100644
index 0000000000..7d54e8346f
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
@@ -0,0 +1,126 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+static grpc_alts_credentials_options* alts_client_options_copy(
+ const grpc_alts_credentials_options* options);
+
+static void alts_client_options_destroy(grpc_alts_credentials_options* options);
+
+static target_service_account* target_service_account_create(
+ const char* service_account) {
+ if (service_account == nullptr) {
+ return nullptr;
+ }
+ auto* sa = static_cast<target_service_account*>(
+ gpr_zalloc(sizeof(target_service_account)));
+ sa->data = gpr_strdup(service_account);
+ return sa;
+}
+
+bool grpc_alts_credentials_client_options_add_target_service_account(
+ grpc_alts_credentials_client_options* options,
+ const char* service_account) {
+ if (options == nullptr || service_account == nullptr) {
+ gpr_log(
+ GPR_ERROR,
+ "Invalid nullptr arguments to "
+ "grpc_alts_credentials_client_options_add_target_service_account()");
+ return false;
+ }
+ target_service_account* node = target_service_account_create(service_account);
+ node->next = options->target_account_list_head;
+ options->target_account_list_head = node;
+ return true;
+}
+
+static void target_service_account_destroy(
+ target_service_account* service_account) {
+ if (service_account == nullptr) {
+ return;
+ }
+ gpr_free(service_account->data);
+ gpr_free(service_account);
+}
+
+static const grpc_alts_credentials_options_vtable vtable = {
+ alts_client_options_copy, alts_client_options_destroy};
+
+grpc_alts_credentials_options* grpc_alts_credentials_client_options_create() {
+ auto client_options = static_cast<grpc_alts_credentials_client_options*>(
+ gpr_zalloc(sizeof(grpc_alts_credentials_client_options)));
+ client_options->base.vtable = &vtable;
+ return &client_options->base;
+}
+
+static grpc_alts_credentials_options* alts_client_options_copy(
+ const grpc_alts_credentials_options* options) {
+ if (options == nullptr) {
+ return nullptr;
+ }
+ grpc_alts_credentials_options* new_options =
+ grpc_alts_credentials_client_options_create();
+ auto new_client_options =
+ reinterpret_cast<grpc_alts_credentials_client_options*>(new_options);
+ /* Copy target service accounts. */
+ target_service_account* prev = nullptr;
+ auto node =
+ (reinterpret_cast<const grpc_alts_credentials_client_options*>(options))
+ ->target_account_list_head;
+ while (node != nullptr) {
+ target_service_account* new_node =
+ target_service_account_create(node->data);
+ if (prev == nullptr) {
+ new_client_options->target_account_list_head = new_node;
+ } else {
+ prev->next = new_node;
+ }
+ prev = new_node;
+ node = node->next;
+ }
+ /* Copy rpc protocol versions. */
+ grpc_gcp_rpc_protocol_versions_copy(&options->rpc_versions,
+ &new_options->rpc_versions);
+ return new_options;
+}
+
+static void alts_client_options_destroy(
+ grpc_alts_credentials_options* options) {
+ if (options == nullptr) {
+ return;
+ }
+ auto* client_options =
+ reinterpret_cast<grpc_alts_credentials_client_options*>(options);
+ target_service_account* node = client_options->target_account_list_head;
+ while (node != nullptr) {
+ target_service_account* next_node = node->next;
+ target_service_account_destroy(node);
+ node = next_node;
+ }
+}
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
new file mode 100644
index 0000000000..d428171540
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+grpc_alts_credentials_options* grpc_alts_credentials_options_copy(
+ const grpc_alts_credentials_options* options) {
+ if (options != nullptr && options->vtable != nullptr &&
+ options->vtable->copy != nullptr) {
+ return options->vtable->copy(options);
+ }
+ /* An error occurred. */
+ gpr_log(GPR_ERROR,
+ "Invalid arguments to grpc_alts_credentials_options_copy()");
+ return nullptr;
+}
+
+void grpc_alts_credentials_options_destroy(
+ grpc_alts_credentials_options* options) {
+ if (options != nullptr) {
+ if (options->vtable != nullptr && options->vtable->destruct != nullptr) {
+ options->vtable->destruct(options);
+ }
+ gpr_free(options);
+ }
+}
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
new file mode 100644
index 0000000000..4e46d9f2de
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
@@ -0,0 +1,112 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H
+#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H
+
+#include <grpc/support/port_platform.h>
+
+#include <stdbool.h>
+
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+/**
+ * Main interface for ALTS credentials options. The options will contain
+ * information that will be passed from grpc to TSI layer such as RPC protocol
+ * versions. ALTS client (channel) and server credentials will have their own
+ * implementation of this interface. The APIs listed in this header are
+ * thread-compatible.
+ */
+typedef struct grpc_alts_credentials_options grpc_alts_credentials_options;
+
+/* V-table for grpc_alts_credentials_options */
+typedef struct grpc_alts_credentials_options_vtable {
+ grpc_alts_credentials_options* (*copy)(
+ const grpc_alts_credentials_options* options);
+ void (*destruct)(grpc_alts_credentials_options* options);
+} grpc_alts_credentials_options_vtable;
+
+struct grpc_alts_credentials_options {
+ const struct grpc_alts_credentials_options_vtable* vtable;
+ grpc_gcp_rpc_protocol_versions rpc_versions;
+};
+
+typedef struct target_service_account {
+ struct target_service_account* next;
+ char* data;
+} target_service_account;
+
+/**
+ * Main struct for ALTS client credentials options. The options contain a
+ * a list of target service accounts (if specified) used for secure naming
+ * check.
+ */
+typedef struct grpc_alts_credentials_client_options {
+ grpc_alts_credentials_options base;
+ target_service_account* target_account_list_head;
+} grpc_alts_credentials_client_options;
+
+/**
+ * Main struct for ALTS server credentials options. The options currently
+ * do not contain any server-specific fields.
+ */
+typedef struct grpc_alts_credentials_server_options {
+ grpc_alts_credentials_options base;
+} grpc_alts_credentials_server_options;
+
+/**
+ * This method performs a deep copy on grpc_alts_credentials_options instance.
+ *
+ * - options: a grpc_alts_credentials_options instance that needs to be copied.
+ *
+ * It returns a new grpc_alts_credentials_options instance on success and NULL
+ * on failure.
+ */
+grpc_alts_credentials_options* grpc_alts_credentials_options_copy(
+ const grpc_alts_credentials_options* options);
+
+/**
+ * This method destroys a grpc_alts_credentials_options instance by
+ * de-allocating all of its occupied memory.
+ *
+ * - options: a grpc_alts_credentials_options instance that needs to be
+ * destroyed.
+ */
+void grpc_alts_credentials_options_destroy(
+ grpc_alts_credentials_options* options);
+
+/* This method creates a grpc ALTS credentials client options instance. */
+grpc_alts_credentials_options* grpc_alts_credentials_client_options_create();
+
+/* This method creates a grpc ALTS credentials server options instance. */
+grpc_alts_credentials_options* grpc_alts_credentials_server_options_create();
+
+/**
+ * This method adds a target service account to grpc ALTS credentials client
+ * options instance.
+ *
+ * - options: grpc ALTS credentials client options instance.
+ * - service_account: service account of target endpoint.
+ *
+ * It returns true on success and false on failure.
+ */
+bool grpc_alts_credentials_client_options_add_target_service_account(
+ grpc_alts_credentials_client_options* options, const char* service_account);
+
+#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_ALTS_GRPC_ALTS_CREDENTIALS_OPTIONS_H \
+ */
diff --git a/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
new file mode 100644
index 0000000000..62aa7a620a
--- /dev/null
+++ b/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+#include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
+
+static grpc_alts_credentials_options* alts_server_options_copy(
+ const grpc_alts_credentials_options* options);
+
+static void alts_server_options_destroy(
+ grpc_alts_credentials_options* options) {}
+
+static const grpc_alts_credentials_options_vtable vtable = {
+ alts_server_options_copy, alts_server_options_destroy};
+
+grpc_alts_credentials_options* grpc_alts_credentials_server_options_create() {
+ grpc_alts_credentials_server_options* server_options =
+ static_cast<grpc_alts_credentials_server_options*>(
+ gpr_zalloc(sizeof(*server_options)));
+ server_options->base.vtable = &vtable;
+ return &server_options->base;
+}
+
+static grpc_alts_credentials_options* alts_server_options_copy(
+ const grpc_alts_credentials_options* options) {
+ if (options == nullptr) {
+ return nullptr;
+ }
+ grpc_alts_credentials_options* new_options =
+ grpc_alts_credentials_server_options_create();
+ /* Copy rpc protocol versions. */
+ grpc_gcp_rpc_protocol_versions_copy(&options->rpc_versions,
+ &new_options->rpc_versions);
+ return new_options;
+}
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.cc b/src/core/lib/security/credentials/fake/fake_credentials.cc
index 46311fa122..858ab6b41b 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.cc
+++ b/src/core/lib/security/credentials/fake/fake_credentials.cc
@@ -32,9 +32,6 @@
/* -- Fake transport security credentials. -- */
-#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
- "grpc.fake_security.expected_targets"
-
static grpc_security_status fake_transport_security_create_security_connector(
grpc_channel_credentials* c, grpc_call_credentials* call_creds,
const char* target, const grpc_channel_args* args,
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.h b/src/core/lib/security/credentials/fake/fake_credentials.h
index 5166e43167..e89e6e24cc 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.h
+++ b/src/core/lib/security/credentials/fake/fake_credentials.h
@@ -23,6 +23,9 @@
#include "src/core/lib/security/credentials/credentials.h"
+#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
+ "grpc.fake_security.expected_targets"
+
/* -- Fake transport security credentials. -- */
/* Creates a fake transport security credentials object for testing. */
diff --git a/src/core/lib/security/security_connector/alts_security_connector.cc b/src/core/lib/security/security_connector/alts_security_connector.cc
new file mode 100644
index 0000000000..5ff7d7938b
--- /dev/null
+++ b/src/core/lib/security/security_connector/alts_security_connector.cc
@@ -0,0 +1,287 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/security_connector/alts_security_connector.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/security/credentials/alts/alts_credentials.h"
+#include "src/core/lib/security/transport/security_handshaker.h"
+#include "src/core/lib/transport/transport.h"
+#include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
+
+typedef struct {
+ grpc_channel_security_connector base;
+ char* target_name;
+} grpc_alts_channel_security_connector;
+
+typedef struct {
+ grpc_server_security_connector base;
+} grpc_alts_server_security_connector;
+
+static void alts_channel_destroy(grpc_security_connector* sc) {
+ if (sc == nullptr) {
+ return;
+ }
+ auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
+ grpc_call_credentials_unref(c->base.request_metadata_creds);
+ grpc_channel_credentials_unref(c->base.channel_creds);
+ gpr_free(c->target_name);
+ gpr_free(sc);
+}
+
+static void alts_server_destroy(grpc_security_connector* sc) {
+ if (sc == nullptr) {
+ return;
+ }
+ auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
+ grpc_server_credentials_unref(c->base.server_creds);
+ gpr_free(sc);
+}
+
+static void alts_channel_add_handshakers(
+ grpc_channel_security_connector* sc,
+ grpc_handshake_manager* handshake_manager) {
+ tsi_handshaker* handshaker = nullptr;
+ auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
+ grpc_alts_credentials* creds =
+ reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
+ GPR_ASSERT(alts_tsi_handshaker_create(creds->options, c->target_name,
+ creds->handshaker_service_url, true,
+ &handshaker) == TSI_OK);
+ grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
+ handshaker, &sc->base));
+}
+
+static void alts_server_add_handshakers(
+ grpc_server_security_connector* sc,
+ grpc_handshake_manager* handshake_manager) {
+ tsi_handshaker* handshaker = nullptr;
+ auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
+ grpc_alts_server_credentials* creds =
+ reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
+ GPR_ASSERT(alts_tsi_handshaker_create(creds->options, nullptr,
+ creds->handshaker_service_url, false,
+ &handshaker) == TSI_OK);
+ grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
+ handshaker, &sc->base));
+}
+
+static void alts_set_rpc_protocol_versions(
+ grpc_gcp_rpc_protocol_versions* rpc_versions) {
+ grpc_gcp_rpc_protocol_versions_set_max(rpc_versions,
+ GRPC_PROTOCOL_VERSION_MAX_MAJOR,
+ GRPC_PROTOCOL_VERSION_MAX_MINOR);
+ grpc_gcp_rpc_protocol_versions_set_min(rpc_versions,
+ GRPC_PROTOCOL_VERSION_MIN_MAJOR,
+ GRPC_PROTOCOL_VERSION_MIN_MINOR);
+}
+
+namespace grpc_core {
+namespace internal {
+
+grpc_security_status grpc_alts_auth_context_from_tsi_peer(
+ const tsi_peer* peer, grpc_auth_context** ctx) {
+ if (peer == nullptr || ctx == nullptr) {
+ gpr_log(GPR_ERROR,
+ "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
+ return GRPC_SECURITY_ERROR;
+ }
+ *ctx = nullptr;
+ /* Validate certificate type. */
+ const tsi_peer_property* cert_type_prop =
+ tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
+ if (cert_type_prop == nullptr ||
+ strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
+ cert_type_prop->value.length) != 0) {
+ gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
+ return GRPC_SECURITY_ERROR;
+ }
+ /* Validate RPC protocol versions. */
+ const tsi_peer_property* rpc_versions_prop =
+ tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
+ if (rpc_versions_prop == nullptr) {
+ gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
+ return GRPC_SECURITY_ERROR;
+ }
+ grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
+ alts_set_rpc_protocol_versions(&local_versions);
+ grpc_slice slice = grpc_slice_from_copied_buffer(
+ rpc_versions_prop->value.data, rpc_versions_prop->value.length);
+ bool decode_result =
+ grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions);
+ grpc_slice_unref(slice);
+ if (!decode_result) {
+ gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
+ return GRPC_SECURITY_ERROR;
+ }
+ /* TODO: Pass highest common rpc protocol version to grpc caller. */
+ bool check_result = grpc_gcp_rpc_protocol_versions_check(
+ &local_versions, &peer_versions, nullptr);
+ if (!check_result) {
+ gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
+ return GRPC_SECURITY_ERROR;
+ }
+ /* Create auth context. */
+ *ctx = grpc_auth_context_create(nullptr);
+ grpc_auth_context_add_cstring_property(
+ *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+ GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
+ size_t i = 0;
+ for (i = 0; i < peer->property_count; i++) {
+ const tsi_peer_property* tsi_prop = &peer->properties[i];
+ /* Add service account to auth context. */
+ if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
+ grpc_auth_context_add_property(
+ *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, tsi_prop->value.data,
+ tsi_prop->value.length);
+ GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
+ *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
+ }
+ }
+ if (!grpc_auth_context_peer_is_authenticated(*ctx)) {
+ gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
+ GRPC_AUTH_CONTEXT_UNREF(*ctx, "test");
+ *ctx = nullptr;
+ return GRPC_SECURITY_ERROR;
+ }
+ return GRPC_SECURITY_OK;
+}
+
+} // namespace internal
+} // namespace grpc_core
+
+static void alts_check_peer(grpc_security_connector* sc, tsi_peer peer,
+ grpc_auth_context** auth_context,
+ grpc_closure* on_peer_checked) {
+ grpc_security_status status;
+ status = grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(
+ &peer, auth_context);
+ tsi_peer_destruct(&peer);
+ grpc_error* error =
+ status == GRPC_SECURITY_OK
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "Could not get ALTS auth context from TSI peer");
+ GRPC_CLOSURE_SCHED(on_peer_checked, error);
+}
+
+static int alts_channel_cmp(grpc_security_connector* sc1,
+ grpc_security_connector* sc2) {
+ grpc_alts_channel_security_connector* c1 =
+ reinterpret_cast<grpc_alts_channel_security_connector*>(sc1);
+ grpc_alts_channel_security_connector* c2 =
+ reinterpret_cast<grpc_alts_channel_security_connector*>(sc2);
+ int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
+ if (c != 0) return c;
+ return strcmp(c1->target_name, c2->target_name);
+}
+
+static int alts_server_cmp(grpc_security_connector* sc1,
+ grpc_security_connector* sc2) {
+ grpc_alts_server_security_connector* c1 =
+ reinterpret_cast<grpc_alts_server_security_connector*>(sc1);
+ grpc_alts_server_security_connector* c2 =
+ reinterpret_cast<grpc_alts_server_security_connector*>(sc2);
+ return grpc_server_security_connector_cmp(&c1->base, &c2->base);
+}
+
+static grpc_security_connector_vtable alts_channel_vtable = {
+ alts_channel_destroy, alts_check_peer, alts_channel_cmp};
+
+static grpc_security_connector_vtable alts_server_vtable = {
+ alts_server_destroy, alts_check_peer, alts_server_cmp};
+
+static bool alts_check_call_host(grpc_channel_security_connector* sc,
+ const char* host,
+ grpc_auth_context* auth_context,
+ grpc_closure* on_call_host_checked,
+ grpc_error** error) {
+ grpc_alts_channel_security_connector* alts_sc =
+ reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
+ if (host == nullptr || alts_sc == nullptr ||
+ strcmp(host, alts_sc->target_name) != 0) {
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
+ "ALTS call host does not match target name");
+ }
+ return true;
+}
+
+static void alts_cancel_check_call_host(grpc_channel_security_connector* sc,
+ grpc_closure* on_call_host_checked,
+ grpc_error* error) {
+ GRPC_ERROR_UNREF(error);
+}
+
+grpc_security_status grpc_alts_channel_security_connector_create(
+ grpc_channel_credentials* channel_creds,
+ grpc_call_credentials* request_metadata_creds, const char* target_name,
+ grpc_channel_security_connector** sc) {
+ if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) {
+ gpr_log(
+ GPR_ERROR,
+ "Invalid arguments to grpc_alts_channel_security_connector_create()");
+ return GRPC_SECURITY_ERROR;
+ }
+ auto c = static_cast<grpc_alts_channel_security_connector*>(
+ gpr_zalloc(sizeof(grpc_alts_channel_security_connector)));
+ gpr_ref_init(&c->base.base.refcount, 1);
+ c->base.base.vtable = &alts_channel_vtable;
+ c->base.add_handshakers = alts_channel_add_handshakers;
+ c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
+ c->base.request_metadata_creds =
+ grpc_call_credentials_ref(request_metadata_creds);
+ c->base.check_call_host = alts_check_call_host;
+ c->base.cancel_check_call_host = alts_cancel_check_call_host;
+ grpc_alts_credentials* creds =
+ reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
+ alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
+ c->target_name = gpr_strdup(target_name);
+ *sc = &c->base;
+ return GRPC_SECURITY_OK;
+}
+
+grpc_security_status grpc_alts_server_security_connector_create(
+ grpc_server_credentials* server_creds,
+ grpc_server_security_connector** sc) {
+ if (server_creds == nullptr || sc == nullptr) {
+ gpr_log(
+ GPR_ERROR,
+ "Invalid arguments to grpc_alts_server_security_connector_create()");
+ return GRPC_SECURITY_ERROR;
+ }
+ auto c = static_cast<grpc_alts_server_security_connector*>(
+ gpr_zalloc(sizeof(grpc_alts_server_security_connector)));
+ gpr_ref_init(&c->base.base.refcount, 1);
+ c->base.base.vtable = &alts_server_vtable;
+ c->base.server_creds = grpc_server_credentials_ref(server_creds);
+ c->base.add_handshakers = alts_server_add_handshakers;
+ grpc_alts_server_credentials* creds =
+ reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
+ alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
+ *sc = &c->base;
+ return GRPC_SECURITY_OK;
+}
diff --git a/src/core/lib/security/security_connector/alts_security_connector.h b/src/core/lib/security/security_connector/alts_security_connector.h
new file mode 100644
index 0000000000..e7e4cffe2a
--- /dev/null
+++ b/src/core/lib/security/security_connector/alts_security_connector.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H
+#define GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h"
+
+#define GRPC_ALTS_TRANSPORT_SECURITY_TYPE "alts"
+
+/**
+ * This method creates an ALTS channel security connector.
+ *
+ * - channel_creds: channel credential instance.
+ * - request_metadata_creds: credential object which will be sent with each
+ * request. This parameter can be nullptr.
+ * - target_name: the name of the endpoint that the channel is connecting to.
+ * - sc: address of ALTS channel security connector instance to be returned from
+ * the method.
+ *
+ * It returns GRPC_SECURITY_OK on success, and an error stauts code on failure.
+ */
+grpc_security_status grpc_alts_channel_security_connector_create(
+ grpc_channel_credentials* channel_creds,
+ grpc_call_credentials* request_metadata_creds, const char* target_name,
+ grpc_channel_security_connector** sc);
+
+/**
+ * This method creates an ALTS server security connector.
+ *
+ * - server_creds: server credential instance.
+ * - sc: address of ALTS server security connector instance to be returned from
+ * the method.
+ *
+ * It returns GRPC_SECURITY_OK on success, and an error status code on failure.
+ */
+grpc_security_status grpc_alts_server_security_connector_create(
+ grpc_server_credentials* server_creds, grpc_server_security_connector** sc);
+
+namespace grpc_core {
+namespace internal {
+
+/* Exposed only for testing. */
+grpc_security_status grpc_alts_auth_context_from_tsi_peer(
+ const tsi_peer* peer, grpc_auth_context** ctx);
+
+} // namespace internal
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_ALTS_SECURITY_CONNECTOR_H \
+ */
diff --git a/src/core/lib/security/security_connector/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc
index b01fd6f769..3cc151bec7 100644
--- a/src/core/lib/security/security_connector/security_connector.cc
+++ b/src/core/lib/security/security_connector/security_connector.cc
@@ -39,9 +39,9 @@
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
-#include "src/core/lib/security/transport/lb_targets_info.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/security_handshaker.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
#include "src/core/tsi/fake_transport_security.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security_adapter.h"
@@ -463,6 +463,15 @@ static bool fake_channel_check_call_host(grpc_channel_security_connector* sc,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) {
+ grpc_fake_channel_security_connector* c =
+ reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
+ if (c->is_lb_channel) {
+ // TODO(dgq): verify that the host (ie, authority header) matches that of
+ // the LB, as opposed to that of the backends.
+ } else {
+ // TODO(dgq): verify that the host (ie, authority header) matches that of
+ // the backend, not the LB's.
+ }
return true;
}
@@ -514,7 +523,7 @@ grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
c->target = gpr_strdup(target);
const char* expected_targets = grpc_fake_transport_get_expected_targets(args);
c->expected_targets = gpr_strdup(expected_targets);
- c->is_lb_channel = (grpc_lb_targets_info_find_in_args(args) != nullptr);
+ c->is_lb_channel = grpc_core::FindTargetAuthorityTableInArgs(args) != nullptr;
return &c->base;
}
diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc
index d6ca8ee8f8..048e390a71 100644
--- a/src/core/lib/security/transport/client_auth_filter.cc
+++ b/src/core/lib/security/transport/client_auth_filter.cc
@@ -45,8 +45,6 @@ struct call_data {
grpc_call_stack* owning_call;
grpc_call_combiner* call_combiner;
grpc_call_credentials* creds;
- bool have_host;
- bool have_method;
grpc_slice host;
grpc_slice method;
/* pollset{_set} bound to this call; if we need to make external
@@ -294,27 +292,15 @@ static void auth_start_transport_stream_op_batch(
}
if (batch->send_initial_metadata) {
- for (grpc_linked_mdelem* l = batch->payload->send_initial_metadata
- .send_initial_metadata->list.head;
- l != nullptr; l = l->next) {
- grpc_mdelem md = l->md;
- /* Pointer comparison is OK for md_elems created from the same context.
- */
- if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_AUTHORITY)) {
- if (calld->have_host) {
- grpc_slice_unref_internal(calld->host);
- }
- calld->host = grpc_slice_ref_internal(GRPC_MDVALUE(md));
- calld->have_host = true;
- } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_PATH)) {
- if (calld->have_method) {
- grpc_slice_unref_internal(calld->method);
- }
- calld->method = grpc_slice_ref_internal(GRPC_MDVALUE(md));
- calld->have_method = true;
- }
+ grpc_metadata_batch* metadata =
+ batch->payload->send_initial_metadata.send_initial_metadata;
+ if (metadata->idx.named.path != nullptr) {
+ calld->method =
+ grpc_slice_ref_internal(GRPC_MDVALUE(metadata->idx.named.path->md));
}
- if (calld->have_host) {
+ if (metadata->idx.named.authority != nullptr) {
+ calld->host = grpc_slice_ref_internal(
+ GRPC_MDVALUE(metadata->idx.named.authority->md));
batch->handler_private.extra_arg = elem;
GRPC_CALL_STACK_REF(calld->owning_call, "check_call_host");
GRPC_CLOSURE_INIT(&calld->async_result_closure, on_host_checked, batch,
@@ -351,6 +337,8 @@ static grpc_error* init_call_elem(grpc_call_element* elem,
call_data* calld = static_cast<call_data*>(elem->call_data);
calld->owning_call = args->call_stack;
calld->call_combiner = args->call_combiner;
+ calld->host = grpc_empty_slice();
+ calld->method = grpc_empty_slice();
return GRPC_ERROR_NONE;
}
@@ -367,12 +355,8 @@ static void destroy_call_elem(grpc_call_element* elem,
call_data* calld = static_cast<call_data*>(elem->call_data);
grpc_credentials_mdelem_array_destroy(&calld->md_array);
grpc_call_credentials_unref(calld->creds);
- if (calld->have_host) {
- grpc_slice_unref_internal(calld->host);
- }
- if (calld->have_method) {
- grpc_slice_unref_internal(calld->method);
- }
+ grpc_slice_unref_internal(calld->host);
+ grpc_slice_unref_internal(calld->method);
grpc_auth_metadata_context_reset(&calld->auth_md_context);
}
diff --git a/src/core/lib/security/transport/lb_targets_info.cc b/src/core/lib/security/transport/lb_targets_info.cc
deleted file mode 100644
index 155a91e556..0000000000
--- a/src/core/lib/security/transport/lb_targets_info.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/port_platform.h>
-
-#include <grpc/support/log.h>
-
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/security/transport/lb_targets_info.h"
-
-/* Channel arg key for the mapping of LB server addresses to their names for
- * secure naming purposes. */
-#define GRPC_ARG_LB_SECURE_NAMING_MAP "grpc.lb_secure_naming_map"
-
-static void* targets_info_copy(void* p) {
- return grpc_slice_hash_table_ref(static_cast<grpc_slice_hash_table*>(p));
-}
-static void targets_info_destroy(void* p) {
- grpc_slice_hash_table_unref(static_cast<grpc_slice_hash_table*>(p));
-}
-static int targets_info_cmp(void* a, void* b) {
- return grpc_slice_hash_table_cmp(
- static_cast<const grpc_slice_hash_table*>(a),
- static_cast<const grpc_slice_hash_table*>(b));
-}
-static const grpc_arg_pointer_vtable server_to_balancer_names_vtable = {
- targets_info_copy, targets_info_destroy, targets_info_cmp};
-
-grpc_arg grpc_lb_targets_info_create_channel_arg(
- grpc_slice_hash_table* targets_info) {
- return grpc_channel_arg_pointer_create((char*)GRPC_ARG_LB_SECURE_NAMING_MAP,
- targets_info,
- &server_to_balancer_names_vtable);
-}
-
-grpc_slice_hash_table* grpc_lb_targets_info_find_in_args(
- const grpc_channel_args* args) {
- const grpc_arg* targets_info_arg =
- grpc_channel_args_find(args, GRPC_ARG_LB_SECURE_NAMING_MAP);
- if (targets_info_arg != nullptr) {
- GPR_ASSERT(targets_info_arg->type == GRPC_ARG_POINTER);
- return static_cast<grpc_slice_hash_table*>(
- targets_info_arg->value.pointer.p);
- }
- return nullptr;
-}
diff --git a/src/core/lib/security/transport/target_authority_table.cc b/src/core/lib/security/transport/target_authority_table.cc
new file mode 100644
index 0000000000..1eeb557f6a
--- /dev/null
+++ b/src/core/lib/security/transport/target_authority_table.cc
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/transport/target_authority_table.h"
+
+// Channel arg key for the mapping of target addresses to their authorities.
+#define GRPC_ARG_TARGET_AUTHORITY_TABLE "grpc.target_authority_table"
+
+namespace grpc_core {
+namespace {
+
+void* target_authority_table_copy(void* p) {
+ TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p);
+ // TODO(roth): When channel_args are converted to C++, pass the
+ // RefCountedPtr<> directly instead of managing the ref manually.
+ table->Ref().release();
+ return p;
+}
+void target_authority_table_destroy(void* p) {
+ TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p);
+ table->Unref();
+}
+int target_authority_table_cmp(void* a, void* b) {
+ return TargetAuthorityTable::Cmp(
+ *static_cast<const TargetAuthorityTable*>(a),
+ *static_cast<const TargetAuthorityTable*>(b));
+}
+const grpc_arg_pointer_vtable target_authority_table_arg_vtable = {
+ target_authority_table_copy, target_authority_table_destroy,
+ target_authority_table_cmp};
+
+} // namespace
+
+grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table) {
+ return grpc_channel_arg_pointer_create((char*)GRPC_ARG_TARGET_AUTHORITY_TABLE,
+ table,
+ &target_authority_table_arg_vtable);
+}
+
+TargetAuthorityTable* FindTargetAuthorityTableInArgs(
+ const grpc_channel_args* args) {
+ const grpc_arg* arg =
+ grpc_channel_args_find(args, GRPC_ARG_TARGET_AUTHORITY_TABLE);
+ if (arg != nullptr) {
+ if (arg->type == GRPC_ARG_POINTER) {
+ return static_cast<TargetAuthorityTable*>(arg->value.pointer.p);
+ } else {
+ gpr_log(GPR_ERROR, "value of " GRPC_ARG_TARGET_AUTHORITY_TABLE
+ " channel arg was not pointer type; ignoring");
+ }
+ }
+ return nullptr;
+}
+
+} // namespace grpc_core
diff --git a/src/core/lib/security/transport/lb_targets_info.h b/src/core/lib/security/transport/target_authority_table.h
index 7e816c5222..a2e7dc6ac2 100644
--- a/src/core/lib/security/transport/lb_targets_info.h
+++ b/src/core/lib/security/transport/target_authority_table.h
@@ -16,19 +16,25 @@
*
*/
-#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
-#define GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
+#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H
+#define GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/slice/slice_hash_table.h"
-/** Return a channel argument containing \a targets_info. */
-grpc_arg grpc_lb_targets_info_create_channel_arg(
- grpc_slice_hash_table* targets_info);
+namespace grpc_core {
-/** Return the instance of targets info in \a args or NULL */
-grpc_slice_hash_table* grpc_lb_targets_info_find_in_args(
+/// A hash table mapping target addresses to authorities.
+typedef SliceHashTable<UniquePtr<char>> TargetAuthorityTable;
+
+/// Returns a channel argument containing \a table.
+grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table);
+
+/// Returns the target authority table from \a args or nullptr.
+TargetAuthorityTable* FindTargetAuthorityTableInArgs(
const grpc_channel_args* args);
-#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H */
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H */
diff --git a/src/core/lib/slice/slice_hash_table.cc b/src/core/lib/slice/slice_hash_table.cc
deleted file mode 100644
index 9e32321636..0000000000
--- a/src/core/lib/slice/slice_hash_table.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-//
-// Copyright 2016 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include <grpc/support/port_platform.h>
-
-#include "src/core/lib/slice/slice_hash_table.h"
-
-#include <stdbool.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/slice/slice_internal.h"
-#include "src/core/lib/transport/metadata.h"
-
-struct grpc_slice_hash_table {
- gpr_refcount refs;
- void (*destroy_value)(void* value);
- int (*value_cmp)(void* a, void* b);
- size_t size;
- size_t max_num_probes;
- grpc_slice_hash_table_entry* entries;
-};
-
-static bool is_empty(grpc_slice_hash_table_entry* entry) {
- return entry->value == nullptr;
-}
-
-static void grpc_slice_hash_table_add(grpc_slice_hash_table* table,
- grpc_slice key, void* value) {
- GPR_ASSERT(value != nullptr);
- const size_t hash = grpc_slice_hash(key);
- for (size_t offset = 0; offset < table->size; ++offset) {
- const size_t idx = (hash + offset) % table->size;
- if (is_empty(&table->entries[idx])) {
- table->entries[idx].key = key;
- table->entries[idx].value = value;
- // Keep track of the maximum number of probes needed, since this
- // provides an upper bound for lookups.
- if (offset > table->max_num_probes) table->max_num_probes = offset;
- return;
- }
- }
- GPR_ASSERT(false); // Table should never be full.
-}
-
-grpc_slice_hash_table* grpc_slice_hash_table_create(
- size_t num_entries, grpc_slice_hash_table_entry* entries,
- void (*destroy_value)(void* value), int (*value_cmp)(void* a, void* b)) {
- grpc_slice_hash_table* table =
- static_cast<grpc_slice_hash_table*>(gpr_zalloc(sizeof(*table)));
- gpr_ref_init(&table->refs, 1);
- table->destroy_value = destroy_value;
- table->value_cmp = value_cmp;
- // Keep load factor low to improve performance of lookups.
- table->size = num_entries * 2;
- const size_t entry_size = sizeof(grpc_slice_hash_table_entry) * table->size;
- table->entries =
- static_cast<grpc_slice_hash_table_entry*>(gpr_zalloc(entry_size));
- for (size_t i = 0; i < num_entries; ++i) {
- grpc_slice_hash_table_entry* entry = &entries[i];
- grpc_slice_hash_table_add(table, entry->key, entry->value);
- }
- return table;
-}
-
-grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) {
- if (table != nullptr) gpr_ref(&table->refs);
- return table;
-}
-
-void grpc_slice_hash_table_unref(grpc_slice_hash_table* table) {
- if (table != nullptr && gpr_unref(&table->refs)) {
- for (size_t i = 0; i < table->size; ++i) {
- grpc_slice_hash_table_entry* entry = &table->entries[i];
- if (!is_empty(entry)) {
- grpc_slice_unref_internal(entry->key);
- table->destroy_value(entry->value);
- }
- }
- gpr_free(table->entries);
- gpr_free(table);
- }
-}
-
-void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
- const grpc_slice key) {
- const size_t hash = grpc_slice_hash(key);
- // We cap the number of probes at the max number recorded when
- // populating the table.
- for (size_t offset = 0; offset <= table->max_num_probes; ++offset) {
- const size_t idx = (hash + offset) % table->size;
- if (is_empty(&table->entries[idx])) break;
- if (grpc_slice_eq(table->entries[idx].key, key)) {
- return table->entries[idx].value;
- }
- }
- return nullptr; // Not found.
-}
-
-static int pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
-int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a,
- const grpc_slice_hash_table* b) {
- int (*const value_cmp_fn_a)(void* a, void* b) =
- a->value_cmp != nullptr ? a->value_cmp : pointer_cmp;
- int (*const value_cmp_fn_b)(void* a, void* b) =
- b->value_cmp != nullptr ? b->value_cmp : pointer_cmp;
- // Compare value_fns
- const int value_fns_cmp =
- GPR_ICMP((void*)value_cmp_fn_a, (void*)value_cmp_fn_b);
- if (value_fns_cmp != 0) return value_fns_cmp;
- // Compare sizes
- if (a->size < b->size) return -1;
- if (a->size > b->size) return 1;
- // Compare rows.
- for (size_t i = 0; i < a->size; ++i) {
- if (is_empty(&a->entries[i])) {
- if (!is_empty(&b->entries[i])) {
- return -1; // a empty but b non-empty
- }
- continue; // both empty, no need to check key or value
- } else if (is_empty(&b->entries[i])) {
- return 1; // a non-empty but b empty
- }
- // neither entry is empty
- const int key_cmp = grpc_slice_cmp(a->entries[i].key, b->entries[i].key);
- if (key_cmp != 0) return key_cmp;
- const int value_cmp =
- value_cmp_fn_a(a->entries[i].value, b->entries[i].value);
- if (value_cmp != 0) return value_cmp;
- }
- return 0;
-}
diff --git a/src/core/lib/slice/slice_hash_table.h b/src/core/lib/slice/slice_hash_table.h
index 819bb3b5bc..fbe9cc58e8 100644
--- a/src/core/lib/slice/slice_hash_table.h
+++ b/src/core/lib/slice/slice_hash_table.h
@@ -19,52 +19,183 @@
#include <grpc/support/port_platform.h>
-#include "src/core/lib/transport/metadata.h"
+#include <string.h>
-/** Hash table implementation.
- *
- * This implementation uses open addressing
- * (https://en.wikipedia.org/wiki/Open_addressing) with linear
- * probing (https://en.wikipedia.org/wiki/Linear_probing).
- *
- * The keys are \a grpc_slice objects. The values are arbitrary pointers
- * with a common destroy function.
- *
- * Hash tables are intentionally immutable, to avoid the need for locking.
- */
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/slice/slice_internal.h"
+
+/// Hash table implementation.
+///
+/// This implementation uses open addressing
+/// (https://en.wikipedia.org/wiki/Open_addressing) with linear
+/// probing (https://en.wikipedia.org/wiki/Linear_probing).
+///
+/// The keys are \a grpc_slice objects. The values can be any type.
+///
+/// Hash tables are intentionally immutable, to avoid the need for locking.
+
+namespace grpc_core {
+
+template <typename T>
+class SliceHashTable : public RefCounted<SliceHashTable<T>> {
+ public:
+ struct Entry {
+ grpc_slice key;
+ T value;
+ bool is_set;
+ };
+
+ // Function for comparing values.
+ // TODO(roth): Eliminate this and the Cmp() method from this API once
+ // grpc_channel_args is redesigned to require that keys are unique.
+ typedef int (*ValueCmp)(const T&, const T&);
+
+ /// Creates a new hash table containing \a entries, which is an array
+ /// of length \a num_entries. Takes ownership of all keys and values in \a
+ /// entries. If not null, \a value_cmp will be used to compare values in
+ /// the context of \a Cmp(). If null, raw pointer (\a GPR_ICMP) comparison
+ /// will be used.
+ static RefCountedPtr<SliceHashTable> Create(size_t num_entries,
+ Entry* entries,
+ ValueCmp value_cmp);
+
+ /// Returns the value from the table associated with \a key.
+ /// Returns null if \a key is not found.
+ const T* Get(const grpc_slice& key) const;
+
+ /// Compares \a a vs. \a b.
+ /// A table is considered "smaller" (resp. "greater") if:
+ /// - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1),
+ /// - else, it contains fewer (resp. more) entries,
+ /// - else, if strcmp(a_key, b_key) < 1 (resp. > 1),
+ /// - else, if value_cmp(a_value, b_value) < 1 (resp. > 1).
+ static int Cmp(const SliceHashTable& a, const SliceHashTable& b);
+
+ private:
+ // So New() can call our private ctor.
+ template <typename T2, typename... Args>
+ friend T2* New(Args&&... args);
+
+ SliceHashTable(size_t num_entries, Entry* entries, ValueCmp value_cmp);
+ virtual ~SliceHashTable();
+
+ void Add(grpc_slice key, T& value);
+
+ // Default value comparison function, if none specified by caller.
+ static int DefaultValueCmp(const T& a, const T& b) { return GPR_ICMP(a, b); }
+
+ const ValueCmp value_cmp_;
+ const size_t size_;
+ size_t max_num_probes_;
+ Entry* entries_;
+};
+
+//
+// implementation -- no user-serviceable parts below
+//
+
+template <typename T>
+RefCountedPtr<SliceHashTable<T>> SliceHashTable<T>::Create(size_t num_entries,
+ Entry* entries,
+ ValueCmp value_cmp) {
+ return MakeRefCounted<SliceHashTable<T>>(num_entries, entries, value_cmp);
+}
+
+template <typename T>
+SliceHashTable<T>::SliceHashTable(size_t num_entries, Entry* entries,
+ ValueCmp value_cmp)
+ : value_cmp_(value_cmp),
+ // Keep load factor low to improve performance of lookups.
+ size_(num_entries * 2),
+ max_num_probes_(0) {
+ entries_ = static_cast<Entry*>(gpr_zalloc(sizeof(Entry) * size_));
+ for (size_t i = 0; i < num_entries; ++i) {
+ Entry* entry = &entries[i];
+ Add(entry->key, entry->value);
+ }
+}
+
+template <typename T>
+SliceHashTable<T>::~SliceHashTable() {
+ for (size_t i = 0; i < size_; ++i) {
+ Entry& entry = entries_[i];
+ if (entry.is_set) {
+ grpc_slice_unref_internal(entry.key);
+ entry.value.~T();
+ }
+ }
+ gpr_free(entries_);
+}
+
+template <typename T>
+void SliceHashTable<T>::Add(grpc_slice key, T& value) {
+ const size_t hash = grpc_slice_hash(key);
+ for (size_t offset = 0; offset < size_; ++offset) {
+ const size_t idx = (hash + offset) % size_;
+ if (!entries_[idx].is_set) {
+ entries_[idx].is_set = true;
+ entries_[idx].key = key;
+ entries_[idx].value = std::move(value);
+ // Keep track of the maximum number of probes needed, since this
+ // provides an upper bound for lookups.
+ if (offset > max_num_probes_) max_num_probes_ = offset;
+ return;
+ }
+ }
+ GPR_ASSERT(false); // Table should never be full.
+}
+
+template <typename T>
+const T* SliceHashTable<T>::Get(const grpc_slice& key) const {
+ const size_t hash = grpc_slice_hash(key);
+ // We cap the number of probes at the max number recorded when
+ // populating the table.
+ for (size_t offset = 0; offset <= max_num_probes_; ++offset) {
+ const size_t idx = (hash + offset) % size_;
+ if (!entries_[idx].is_set) break;
+ if (grpc_slice_eq(entries_[idx].key, key)) {
+ return &entries_[idx].value;
+ }
+ }
+ return nullptr; // Not found.
+}
+
+template <typename T>
+int SliceHashTable<T>::Cmp(const SliceHashTable& a, const SliceHashTable& b) {
+ ValueCmp value_cmp_a =
+ a.value_cmp_ != nullptr ? a.value_cmp_ : DefaultValueCmp;
+ ValueCmp value_cmp_b =
+ b.value_cmp_ != nullptr ? b.value_cmp_ : DefaultValueCmp;
+ // Compare value_fns
+ const int value_fns_cmp = GPR_ICMP((void*)value_cmp_a, (void*)value_cmp_b);
+ if (value_fns_cmp != 0) return value_fns_cmp;
+ // Compare sizes
+ if (a.size_ < b.size_) return -1;
+ if (a.size_ > b.size_) return 1;
+ // Compare rows.
+ for (size_t i = 0; i < a.size_; ++i) {
+ if (!a.entries_[i].is_set) {
+ if (b.entries_[i].is_set) {
+ return -1; // a empty but b non-empty
+ }
+ continue; // both empty, no need to check key or value
+ } else if (!b.entries_[i].is_set) {
+ return 1; // a non-empty but b empty
+ }
+ // neither entry is empty
+ const int key_cmp = grpc_slice_cmp(a.entries_[i].key, b.entries_[i].key);
+ if (key_cmp != 0) return key_cmp;
+ const int value_cmp = value_cmp_a(a.entries_[i].value, b.entries_[i].value);
+ if (value_cmp != 0) return value_cmp;
+ }
+ return 0;
+}
-typedef struct grpc_slice_hash_table grpc_slice_hash_table;
-
-typedef struct grpc_slice_hash_table_entry {
- grpc_slice key;
- void* value; /* Must not be NULL. */
-} grpc_slice_hash_table_entry;
-
-/** Creates a new hash table of containing \a entries, which is an array
- of length \a num_entries. Takes ownership of all keys and values in \a
- entries. Values will be cleaned up via \a destroy_value(). If not NULL, \a
- value_cmp will be used to compare values in the context of \a
- grpc_slice_hash_table_cmp. If NULL, raw pointer (\a GPR_ICMP) comparison
- will be used. */
-grpc_slice_hash_table* grpc_slice_hash_table_create(
- size_t num_entries, grpc_slice_hash_table_entry* entries,
- void (*destroy_value)(void* value), int (*value_cmp)(void* a, void* b));
-
-grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table);
-void grpc_slice_hash_table_unref(grpc_slice_hash_table* table);
-
-/** Returns the value from \a table associated with \a key.
- Returns NULL if \a key is not found. */
-void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
- const grpc_slice key);
-
-/** Compares \a a vs. \a b.
- * A table is considered "smaller" (resp. "greater") if:
- * - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1),
- * - else, it contains fewer (resp. more) entries,
- * - else, if strcmp(a_key, b_key) < 1 (resp. > 1),
- * - else, if value_cmp(a_value, b_value) < 1 (resp. > 1). */
-int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a,
- const grpc_slice_hash_table* b);
+} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H */
diff --git a/src/core/lib/slice/slice_weak_hash_table.h b/src/core/lib/slice/slice_weak_hash_table.h
new file mode 100644
index 0000000000..9d0ddfc2d2
--- /dev/null
+++ b/src/core/lib/slice/slice_weak_hash_table.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H
+#define GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/gprpp/memory.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/slice/slice_internal.h"
+
+/// Weak hash table implementation.
+///
+/// This entries in this table are weak: an entry may be removed at any time due
+/// to a number of reasons: memory pressure, hash collisions, etc.
+///
+/// The keys are \a grpc_slice objects. The values are of arbitrary type.
+///
+/// This class is thread unsafe. It's the caller's responsibility to ensure
+/// proper locking when accessing its methods.
+
+namespace grpc_core {
+
+template <typename T, size_t Size>
+class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
+ public:
+ /// Creates a new table of at most \a size entries.
+ static RefCountedPtr<SliceWeakHashTable> Create() {
+ return MakeRefCounted<SliceWeakHashTable<T, Size>>();
+ }
+
+ /// Add a mapping from \a key to \a value, taking ownership of \a key. This
+ /// operation will always succeed. It may discard older entries.
+ void Add(grpc_slice key, T value) {
+ const size_t idx = grpc_slice_hash(key) % Size;
+ entries_[idx].Set(key, std::move(value));
+ return;
+ }
+
+ /// Returns the value from the table associated with / \a key or null if not
+ /// found.
+ const T* Get(const grpc_slice key) const {
+ const size_t idx = grpc_slice_hash(key) % Size;
+ const auto& entry = entries_[idx];
+ return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr;
+ }
+
+ private:
+ // So New() can call our private ctor.
+ template <typename T2, typename... Args>
+ friend T2* New(Args&&... args);
+
+ SliceWeakHashTable() = default;
+ ~SliceWeakHashTable() = default;
+
+ /// The type of the table "rows".
+ class Entry {
+ public:
+ Entry() = default;
+ ~Entry() {
+ if (is_set_) grpc_slice_unref_internal(key_);
+ }
+ grpc_slice key() const { return key_; }
+
+ /// Return the entry's value, or null if unset.
+ const T* value() const {
+ if (!is_set_) return nullptr;
+ return &value_;
+ }
+
+ /// Set the \a key and \a value (which is moved) for the entry.
+ void Set(grpc_slice key, T&& value) {
+ if (is_set_) grpc_slice_unref_internal(key_);
+ key_ = key;
+ value_ = std::move(value);
+ is_set_ = true;
+ }
+
+ private:
+ grpc_slice key_;
+ T value_;
+ bool is_set_ = false;
+ };
+
+ Entry entries_[Size];
+};
+
+} // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H */
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index 3df745652a..c683cc02de 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -37,6 +37,7 @@
#include "src/core/lib/gpr/arena.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
@@ -50,6 +51,7 @@
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/status_metadata.h"
#include "src/core/lib/transport/transport.h"
/** The maximum number of concurrent batches possible.
@@ -220,9 +222,9 @@ struct grpc_call {
int send_extra_metadata_count;
grpc_millis send_deadline;
- grpc_slice_buffer_stream sending_stream;
+ grpc_core::ManualConstructor<grpc_core::SliceBufferByteStream> sending_stream;
- grpc_byte_stream* receiving_stream;
+ grpc_core::OrphanablePtr<grpc_core::ByteStream> receiving_stream;
grpc_byte_buffer** receiving_buffer;
grpc_slice receiving_slice;
grpc_closure receiving_slice_ready;
@@ -378,7 +380,7 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
bool immediately_cancel = false;
if (args->parent != nullptr) {
- child_call* cc = call->child =
+ call->child =
static_cast<child_call*>(gpr_arena_alloc(arena, sizeof(child_call)));
call->child->parent = args->parent;
@@ -386,10 +388,6 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
GPR_ASSERT(call->is_client);
GPR_ASSERT(!args->parent->is_client);
- parent_call* pc = get_or_create_parent_call(args->parent);
-
- gpr_mu_lock(&pc->child_list_mu);
-
if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
send_deadline = GPR_MIN(send_deadline, args->parent->send_deadline);
}
@@ -417,18 +415,6 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
immediately_cancel = true;
}
}
-
- if (pc->first_child == nullptr) {
- pc->first_child = call;
- cc->sibling_next = cc->sibling_prev = call;
- } else {
- cc->sibling_next = pc->first_child;
- cc->sibling_prev = pc->first_child->child->sibling_prev;
- cc->sibling_next->child->sibling_prev =
- cc->sibling_prev->child->sibling_next = call;
- }
-
- gpr_mu_unlock(&pc->child_list_mu);
}
call->send_deadline = send_deadline;
@@ -445,6 +431,22 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args,
&call->call_combiner};
add_init_error(&error, grpc_call_stack_init(channel_stack, 1, destroy_call,
call, &call_args));
+ // Publish this call to parent only after the call stack has been initialized.
+ if (args->parent != nullptr) {
+ child_call* cc = call->child;
+ parent_call* pc = get_or_create_parent_call(args->parent);
+ gpr_mu_lock(&pc->child_list_mu);
+ if (pc->first_child == nullptr) {
+ pc->first_child = call;
+ cc->sibling_next = cc->sibling_prev = call;
+ } else {
+ cc->sibling_next = pc->first_child;
+ cc->sibling_prev = pc->first_child->child->sibling_prev;
+ cc->sibling_next->child->sibling_prev =
+ cc->sibling_prev->child->sibling_next = call;
+ }
+ gpr_mu_unlock(&pc->child_list_mu);
+ }
if (error != GRPC_ERROR_NONE) {
cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
}
@@ -521,9 +523,7 @@ static void destroy_call(void* call, grpc_error* error) {
grpc_metadata_batch_destroy(
&c->metadata_batch[1 /* is_receiving */][i /* is_initial */]);
}
- if (c->receiving_stream != nullptr) {
- grpc_byte_stream_destroy(c->receiving_stream);
- }
+ c->receiving_stream.reset();
parent_call* pc = get_parent_call(c);
if (pc != nullptr) {
gpr_mu_destroy(&pc->child_list_mu);
@@ -976,32 +976,6 @@ static int prepare_application_metadata(grpc_call* call, int count,
return 1;
}
-/* we offset status by a small amount when storing it into transport metadata
- as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
- */
-#define STATUS_OFFSET 1
-static void destroy_status(void* ignored) {}
-
-static uint32_t decode_status(grpc_mdelem md) {
- uint32_t status;
- void* user_data;
- if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) return 0;
- if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) return 1;
- if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) return 2;
- user_data = grpc_mdelem_get_user_data(md, destroy_status);
- if (user_data != nullptr) {
- status = (static_cast<uint32_t>((intptr_t)user_data)) - STATUS_OFFSET;
- } else {
- if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
- status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
- }
- grpc_mdelem_set_user_data(
- md, destroy_status,
- (void*)static_cast<intptr_t>(status + STATUS_OFFSET));
- }
- return status;
-}
-
static grpc_message_compression_algorithm decode_message_compression(
grpc_mdelem md) {
grpc_message_compression_algorithm algorithm =
@@ -1093,7 +1067,8 @@ static void recv_initial_filter(grpc_call* call, grpc_metadata_batch* b) {
static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
grpc_call* call = static_cast<grpc_call*>(args);
if (b->idx.named.grpc_status != nullptr) {
- uint32_t status_code = decode_status(b->idx.named.grpc_status->md);
+ grpc_status_code status_code =
+ grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
grpc_error* error =
status_code == GRPC_STATUS_OK
? GRPC_ERROR_NONE
@@ -1305,25 +1280,21 @@ static void continue_receiving_slices(batch_control* bctl) {
grpc_error* error;
grpc_call* call = bctl->call;
for (;;) {
- size_t remaining = call->receiving_stream->length -
+ size_t remaining = call->receiving_stream->length() -
(*call->receiving_buffer)->data.raw.slice_buffer.length;
if (remaining == 0) {
call->receiving_message = 0;
- grpc_byte_stream_destroy(call->receiving_stream);
- call->receiving_stream = nullptr;
+ call->receiving_stream.reset();
finish_batch_step(bctl);
return;
}
- if (grpc_byte_stream_next(call->receiving_stream, remaining,
- &call->receiving_slice_ready)) {
- error =
- grpc_byte_stream_pull(call->receiving_stream, &call->receiving_slice);
+ if (call->receiving_stream->Next(remaining, &call->receiving_slice_ready)) {
+ error = call->receiving_stream->Pull(&call->receiving_slice);
if (error == GRPC_ERROR_NONE) {
grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
call->receiving_slice);
} else {
- grpc_byte_stream_destroy(call->receiving_stream);
- call->receiving_stream = nullptr;
+ call->receiving_stream.reset();
grpc_byte_buffer_destroy(*call->receiving_buffer);
*call->receiving_buffer = nullptr;
call->receiving_message = 0;
@@ -1339,19 +1310,17 @@ static void continue_receiving_slices(batch_control* bctl) {
static void receiving_slice_ready(void* bctlp, grpc_error* error) {
batch_control* bctl = static_cast<batch_control*>(bctlp);
grpc_call* call = bctl->call;
- grpc_byte_stream* bs = call->receiving_stream;
bool release_error = false;
if (error == GRPC_ERROR_NONE) {
grpc_slice slice;
- error = grpc_byte_stream_pull(bs, &slice);
+ error = call->receiving_stream->Pull(&slice);
if (error == GRPC_ERROR_NONE) {
grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
slice);
continue_receiving_slices(bctl);
} else {
- /* Error returned by grpc_byte_stream_pull needs to be released manually
- */
+ /* Error returned by ByteStream::Pull() needs to be released manually */
release_error = true;
}
}
@@ -1360,8 +1329,7 @@ static void receiving_slice_ready(void* bctlp, grpc_error* error) {
if (grpc_trace_operation_failures.enabled()) {
GRPC_LOG_IF_ERROR("receiving_slice_ready", GRPC_ERROR_REF(error));
}
- grpc_byte_stream_destroy(call->receiving_stream);
- call->receiving_stream = nullptr;
+ call->receiving_stream.reset();
grpc_byte_buffer_destroy(*call->receiving_buffer);
*call->receiving_buffer = nullptr;
call->receiving_message = 0;
@@ -1379,8 +1347,8 @@ static void process_data_after_md(batch_control* bctl) {
call->receiving_message = 0;
finish_batch_step(bctl);
} else {
- call->test_only_last_message_flags = call->receiving_stream->flags;
- if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
+ call->test_only_last_message_flags = call->receiving_stream->flags();
+ if ((call->receiving_stream->flags() & GRPC_WRITE_INTERNAL_COMPRESS) &&
(call->incoming_message_compression_algorithm >
GRPC_MESSAGE_COMPRESS_NONE)) {
grpc_compression_algorithm algo;
@@ -1403,10 +1371,7 @@ static void receiving_stream_ready(void* bctlp, grpc_error* error) {
batch_control* bctl = static_cast<batch_control*>(bctlp);
grpc_call* call = bctl->call;
if (error != GRPC_ERROR_NONE) {
- if (call->receiving_stream != nullptr) {
- grpc_byte_stream_destroy(call->receiving_stream);
- call->receiving_stream = nullptr;
- }
+ call->receiving_stream.reset();
add_batch_error(bctl, GRPC_ERROR_REF(error), true);
cancel_with_error(call, STATUS_FROM_SURFACE, GRPC_ERROR_REF(error));
}
@@ -1700,21 +1665,20 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- stream_op->send_message = true;
- call->sending_message = true;
- grpc_slice_buffer_stream_init(
- &call->sending_stream,
- &op->data.send_message.send_message->data.raw.slice_buffer,
- op->flags);
+ uint32_t flags = op->flags;
/* If the outgoing buffer is already compressed, mark it as so in the
flags. These will be picked up by the compression filter and further
(wasteful) attempts at compression skipped. */
if (op->data.send_message.send_message->data.raw.compression >
GRPC_COMPRESS_NONE) {
- call->sending_stream.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+ flags |= GRPC_WRITE_INTERNAL_COMPRESS;
}
- stream_op_payload->send_message.send_message =
- &call->sending_stream.base;
+ stream_op->send_message = true;
+ call->sending_message = true;
+ call->sending_stream.Init(
+ &op->data.send_message.send_message->data.raw.slice_buffer, flags);
+ stream_op_payload->send_message.send_message.reset(
+ call->sending_stream.get());
break;
}
case GRPC_OP_SEND_CLOSE_FROM_CLIENT: {
@@ -1933,7 +1897,7 @@ done_with_error:
}
if (stream_op->send_message) {
call->sending_message = false;
- grpc_byte_stream_destroy(&call->sending_stream.base);
+ call->sending_stream->Orphan();
}
if (stream_op->send_trailing_metadata) {
call->sent_final_op = false;
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index 7bc24a5049..ac9f9e6066 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -32,7 +32,7 @@
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/fork.h"
-#include "src/core/lib/gpr/thd.h"
+#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/combiner.h"
@@ -123,7 +123,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
- gpr_thd_init();
+ grpc_core::Thread::Init();
grpc_stats_init();
grpc_slice_intern_init();
grpc_mdctx_global_init();
diff --git a/src/core/lib/surface/lame_client.cc b/src/core/lib/surface/lame_client.cc
index f5aca91f97..5a84428b0e 100644
--- a/src/core/lib/surface/lame_client.cc
+++ b/src/core/lib/surface/lame_client.cc
@@ -52,14 +52,14 @@ struct ChannelData {
};
static void fill_metadata(grpc_call_element* elem, grpc_metadata_batch* mdb) {
- CallData* calld = reinterpret_cast<CallData*>(elem->call_data);
+ CallData* calld = static_cast<CallData*>(elem->call_data);
bool expected = false;
if (!calld->filled_metadata.compare_exchange_strong(
expected, true, grpc_core::memory_order_relaxed,
grpc_core::memory_order_relaxed)) {
return;
}
- ChannelData* chand = reinterpret_cast<ChannelData*>(elem->channel_data);
+ ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
char tmp[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(chand->error_code, tmp);
calld->status.md = grpc_mdelem_from_slices(
@@ -78,7 +78,7 @@ static void fill_metadata(grpc_call_element* elem, grpc_metadata_batch* mdb) {
static void lame_start_transport_stream_op_batch(
grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
- CallData* calld = reinterpret_cast<CallData*>(elem->call_data);
+ CallData* calld = static_cast<CallData*>(elem->call_data);
if (op->recv_initial_metadata) {
fill_metadata(elem,
op->payload->recv_initial_metadata.recv_initial_metadata);
@@ -119,7 +119,7 @@ static void lame_start_transport_op(grpc_channel_element* elem,
static grpc_error* init_call_elem(grpc_call_element* elem,
const grpc_call_element_args* args) {
- CallData* calld = reinterpret_cast<CallData*>(elem->call_data);
+ CallData* calld = static_cast<CallData*>(elem->call_data);
calld->call_combiner = args->call_combiner;
return GRPC_ERROR_NONE;
}
@@ -172,7 +172,7 @@ grpc_channel* grpc_lame_client_channel_create(const char* target,
"error_message=%s)",
3, (target, (int)error_code, error_message));
GPR_ASSERT(elem->filter == &grpc_lame_filter);
- auto chand = reinterpret_cast<grpc_core::ChannelData*>(elem->channel_data);
+ auto chand = static_cast<grpc_core::ChannelData*>(elem->channel_data);
chand->error_code = error_code;
chand->error_message = error_message;
diff --git a/src/core/lib/transport/byte_stream.cc b/src/core/lib/transport/byte_stream.cc
index e1751f8010..cb15a71a91 100644
--- a/src/core/lib/transport/byte_stream.cc
+++ b/src/core/lib/transport/byte_stream.cc
@@ -25,160 +25,136 @@
#include <grpc/support/log.h>
+#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/slice/slice_internal.h"
-bool grpc_byte_stream_next(grpc_byte_stream* byte_stream, size_t max_size_hint,
- grpc_closure* on_complete) {
- return byte_stream->vtable->next(byte_stream, max_size_hint, on_complete);
-}
+namespace grpc_core {
-grpc_error* grpc_byte_stream_pull(grpc_byte_stream* byte_stream,
- grpc_slice* slice) {
- return byte_stream->vtable->pull(byte_stream, slice);
-}
+//
+// SliceBufferByteStream
+//
-void grpc_byte_stream_shutdown(grpc_byte_stream* byte_stream,
- grpc_error* error) {
- byte_stream->vtable->shutdown(byte_stream, error);
+SliceBufferByteStream::SliceBufferByteStream(grpc_slice_buffer* slice_buffer,
+ uint32_t flags)
+ : ByteStream(static_cast<uint32_t>(slice_buffer->length), flags) {
+ GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
+ grpc_slice_buffer_init(&backing_buffer_);
+ grpc_slice_buffer_swap(slice_buffer, &backing_buffer_);
}
-void grpc_byte_stream_destroy(grpc_byte_stream* byte_stream) {
- byte_stream->vtable->destroy(byte_stream);
-}
+SliceBufferByteStream::~SliceBufferByteStream() {}
-// grpc_slice_buffer_stream
+void SliceBufferByteStream::Orphan() {
+ grpc_slice_buffer_destroy(&backing_buffer_);
+ GRPC_ERROR_UNREF(shutdown_error_);
+ // Note: We do not actually delete the object here, since
+ // SliceBufferByteStream is usually allocated as part of a larger
+ // object and has an OrphanablePtr of itself passed down through the
+ // filter stack.
+}
-static bool slice_buffer_stream_next(grpc_byte_stream* byte_stream,
- size_t max_size_hint,
- grpc_closure* on_complete) {
- grpc_slice_buffer_stream* stream =
- reinterpret_cast<grpc_slice_buffer_stream*>(byte_stream);
- GPR_ASSERT(stream->cursor < stream->backing_buffer.count);
+bool SliceBufferByteStream::Next(size_t max_size_hint,
+ grpc_closure* on_complete) {
+ GPR_ASSERT(cursor_ < backing_buffer_.count);
return true;
}
-static grpc_error* slice_buffer_stream_pull(grpc_byte_stream* byte_stream,
- grpc_slice* slice) {
- grpc_slice_buffer_stream* stream =
- reinterpret_cast<grpc_slice_buffer_stream*>(byte_stream);
- if (stream->shutdown_error != GRPC_ERROR_NONE) {
- return GRPC_ERROR_REF(stream->shutdown_error);
+grpc_error* SliceBufferByteStream::Pull(grpc_slice* slice) {
+ if (shutdown_error_ != GRPC_ERROR_NONE) {
+ return GRPC_ERROR_REF(shutdown_error_);
}
- GPR_ASSERT(stream->cursor < stream->backing_buffer.count);
- *slice =
- grpc_slice_ref_internal(stream->backing_buffer.slices[stream->cursor]);
- stream->cursor++;
+ GPR_ASSERT(cursor_ < backing_buffer_.count);
+ *slice = grpc_slice_ref_internal(backing_buffer_.slices[cursor_]);
+ ++cursor_;
return GRPC_ERROR_NONE;
}
-static void slice_buffer_stream_shutdown(grpc_byte_stream* byte_stream,
- grpc_error* error) {
- grpc_slice_buffer_stream* stream =
- reinterpret_cast<grpc_slice_buffer_stream*>(byte_stream);
- GRPC_ERROR_UNREF(stream->shutdown_error);
- stream->shutdown_error = error;
+void SliceBufferByteStream::Shutdown(grpc_error* error) {
+ GRPC_ERROR_UNREF(shutdown_error_);
+ shutdown_error_ = error;
}
-static void slice_buffer_stream_destroy(grpc_byte_stream* byte_stream) {
- grpc_slice_buffer_stream* stream =
- reinterpret_cast<grpc_slice_buffer_stream*>(byte_stream);
- grpc_slice_buffer_destroy(&stream->backing_buffer);
- GRPC_ERROR_UNREF(stream->shutdown_error);
+//
+// ByteStreamCache
+//
+
+ByteStreamCache::ByteStreamCache(OrphanablePtr<ByteStream> underlying_stream)
+ : underlying_stream_(std::move(underlying_stream)),
+ length_(underlying_stream_->length()),
+ flags_(underlying_stream_->flags()) {
+ grpc_slice_buffer_init(&cache_buffer_);
}
-static const grpc_byte_stream_vtable slice_buffer_stream_vtable = {
- slice_buffer_stream_next, slice_buffer_stream_pull,
- slice_buffer_stream_shutdown, slice_buffer_stream_destroy};
+ByteStreamCache::~ByteStreamCache() { Destroy(); }
-void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream* stream,
- grpc_slice_buffer* slice_buffer,
- uint32_t flags) {
- GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
- stream->base.length = static_cast<uint32_t>(slice_buffer->length);
- stream->base.flags = flags;
- stream->base.vtable = &slice_buffer_stream_vtable;
- grpc_slice_buffer_init(&stream->backing_buffer);
- grpc_slice_buffer_swap(slice_buffer, &stream->backing_buffer);
- stream->cursor = 0;
- stream->shutdown_error = GRPC_ERROR_NONE;
+void ByteStreamCache::Destroy() {
+ underlying_stream_.reset();
+ if (cache_buffer_.length > 0) {
+ grpc_slice_buffer_destroy_internal(&cache_buffer_);
+ }
}
-// grpc_caching_byte_stream
+//
+// ByteStreamCache::CachingByteStream
+//
-void grpc_byte_stream_cache_init(grpc_byte_stream_cache* cache,
- grpc_byte_stream* underlying_stream) {
- cache->underlying_stream = underlying_stream;
- grpc_slice_buffer_init(&cache->cache_buffer);
-}
+ByteStreamCache::CachingByteStream::CachingByteStream(ByteStreamCache* cache)
+ : ByteStream(cache->length_, cache->flags_), cache_(cache) {}
-void grpc_byte_stream_cache_destroy(grpc_byte_stream_cache* cache) {
- grpc_byte_stream_destroy(cache->underlying_stream);
- grpc_slice_buffer_destroy_internal(&cache->cache_buffer);
+ByteStreamCache::CachingByteStream::~CachingByteStream() {}
+
+void ByteStreamCache::CachingByteStream::Orphan() {
+ GRPC_ERROR_UNREF(shutdown_error_);
+ // Note: We do not actually delete the object here, since
+ // CachingByteStream is usually allocated as part of a larger
+ // object and has an OrphanablePtr of itself passed down through the
+ // filter stack.
}
-static bool caching_byte_stream_next(grpc_byte_stream* byte_stream,
- size_t max_size_hint,
- grpc_closure* on_complete) {
- grpc_caching_byte_stream* stream =
- reinterpret_cast<grpc_caching_byte_stream*>(byte_stream);
- if (stream->shutdown_error != GRPC_ERROR_NONE) return true;
- if (stream->cursor < stream->cache->cache_buffer.count) return true;
- return grpc_byte_stream_next(stream->cache->underlying_stream, max_size_hint,
- on_complete);
+bool ByteStreamCache::CachingByteStream::Next(size_t max_size_hint,
+ grpc_closure* on_complete) {
+ if (shutdown_error_ != GRPC_ERROR_NONE) return true;
+ if (cursor_ < cache_->cache_buffer_.count) return true;
+ GPR_ASSERT(cache_->underlying_stream_ != nullptr);
+ return cache_->underlying_stream_->Next(max_size_hint, on_complete);
}
-static grpc_error* caching_byte_stream_pull(grpc_byte_stream* byte_stream,
- grpc_slice* slice) {
- grpc_caching_byte_stream* stream =
- reinterpret_cast<grpc_caching_byte_stream*>(byte_stream);
- if (stream->shutdown_error != GRPC_ERROR_NONE) {
- return GRPC_ERROR_REF(stream->shutdown_error);
+grpc_error* ByteStreamCache::CachingByteStream::Pull(grpc_slice* slice) {
+ if (shutdown_error_ != GRPC_ERROR_NONE) {
+ return GRPC_ERROR_REF(shutdown_error_);
}
- if (stream->cursor < stream->cache->cache_buffer.count) {
- *slice = grpc_slice_ref_internal(
- stream->cache->cache_buffer.slices[stream->cursor]);
- ++stream->cursor;
+ if (cursor_ < cache_->cache_buffer_.count) {
+ *slice = grpc_slice_ref_internal(cache_->cache_buffer_.slices[cursor_]);
+ ++cursor_;
+ offset_ += GRPC_SLICE_LENGTH(*slice);
return GRPC_ERROR_NONE;
}
- grpc_error* error =
- grpc_byte_stream_pull(stream->cache->underlying_stream, slice);
+ GPR_ASSERT(cache_->underlying_stream_ != nullptr);
+ grpc_error* error = cache_->underlying_stream_->Pull(slice);
if (error == GRPC_ERROR_NONE) {
- ++stream->cursor;
- grpc_slice_buffer_add(&stream->cache->cache_buffer,
+ grpc_slice_buffer_add(&cache_->cache_buffer_,
grpc_slice_ref_internal(*slice));
+ ++cursor_;
+ offset_ += GRPC_SLICE_LENGTH(*slice);
+ // Orphan the underlying stream if it's been drained.
+ if (offset_ == cache_->underlying_stream_->length()) {
+ cache_->underlying_stream_.reset();
+ }
}
return error;
}
-static void caching_byte_stream_shutdown(grpc_byte_stream* byte_stream,
- grpc_error* error) {
- grpc_caching_byte_stream* stream =
- reinterpret_cast<grpc_caching_byte_stream*>(byte_stream);
- GRPC_ERROR_UNREF(stream->shutdown_error);
- stream->shutdown_error = GRPC_ERROR_REF(error);
- grpc_byte_stream_shutdown(stream->cache->underlying_stream, error);
-}
-
-static void caching_byte_stream_destroy(grpc_byte_stream* byte_stream) {
- grpc_caching_byte_stream* stream =
- reinterpret_cast<grpc_caching_byte_stream*>(byte_stream);
- GRPC_ERROR_UNREF(stream->shutdown_error);
+void ByteStreamCache::CachingByteStream::Shutdown(grpc_error* error) {
+ GRPC_ERROR_UNREF(shutdown_error_);
+ shutdown_error_ = GRPC_ERROR_REF(error);
+ if (cache_->underlying_stream_ != nullptr) {
+ cache_->underlying_stream_->Shutdown(error);
+ }
}
-static const grpc_byte_stream_vtable caching_byte_stream_vtable = {
- caching_byte_stream_next, caching_byte_stream_pull,
- caching_byte_stream_shutdown, caching_byte_stream_destroy};
-
-void grpc_caching_byte_stream_init(grpc_caching_byte_stream* stream,
- grpc_byte_stream_cache* cache) {
- memset(stream, 0, sizeof(*stream));
- stream->base.length = cache->underlying_stream->length;
- stream->base.flags = cache->underlying_stream->flags;
- stream->base.vtable = &caching_byte_stream_vtable;
- stream->cache = cache;
- stream->shutdown_error = GRPC_ERROR_NONE;
+void ByteStreamCache::CachingByteStream::Reset() {
+ cursor_ = 0;
+ offset_ = 0;
}
-void grpc_caching_byte_stream_reset(grpc_caching_byte_stream* stream) {
- stream->cursor = 0;
-}
+} // namespace grpc_core
diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h
index 4d3c3c131b..95a756a5e4 100644
--- a/src/core/lib/transport/byte_stream.h
+++ b/src/core/lib/transport/byte_stream.h
@@ -22,6 +22,8 @@
#include <grpc/support/port_platform.h>
#include <grpc/slice_buffer.h>
+#include "src/core/lib/gprpp/abstract.h"
+#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/iomgr/exec_ctx.h"
/** Internal bit flag for grpc_begin_message's \a flags signaling the use of
@@ -30,71 +32,82 @@
/** Mask of all valid internal flags. */
#define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS)
-typedef struct grpc_byte_stream grpc_byte_stream;
-
-typedef struct {
- bool (*next)(grpc_byte_stream* byte_stream, size_t max_size_hint,
- grpc_closure* on_complete);
- grpc_error* (*pull)(grpc_byte_stream* byte_stream, grpc_slice* slice);
- void (*shutdown)(grpc_byte_stream* byte_stream, grpc_error* error);
- void (*destroy)(grpc_byte_stream* byte_stream);
-} grpc_byte_stream_vtable;
-
-struct grpc_byte_stream {
- uint32_t length;
- uint32_t flags;
- const grpc_byte_stream_vtable* vtable;
+namespace grpc_core {
+
+class ByteStream : public Orphanable {
+ public:
+ virtual ~ByteStream() {}
+
+ // Returns true if the bytes are available immediately (in which case
+ // on_complete will not be called), or false if the bytes will be available
+ // asynchronously (in which case on_complete will be called when they
+ // are available).
+ //
+ // max_size_hint can be set as a hint as to the maximum number
+ // of bytes that would be acceptable to read.
+ virtual bool Next(size_t max_size_hint,
+ grpc_closure* on_complete) GRPC_ABSTRACT;
+
+ // Returns the next slice in the byte stream when it is available, as
+ // indicated by Next().
+ //
+ // Once a slice is returned into *slice, it is owned by the caller.
+ virtual grpc_error* Pull(grpc_slice* slice) GRPC_ABSTRACT;
+
+ // Shuts down the byte stream.
+ //
+ // If there is a pending call to on_complete from Next(), it will be
+ // invoked with the error passed to Shutdown().
+ //
+ // The next call to Pull() (if any) will return the error passed to
+ // Shutdown().
+ virtual void Shutdown(grpc_error* error) GRPC_ABSTRACT;
+
+ uint32_t length() const { return length_; }
+ uint32_t flags() const { return flags_; }
+
+ void set_flags(uint32_t flags) { flags_ = flags; }
+
+ GRPC_ABSTRACT_BASE_CLASS
+
+ protected:
+ ByteStream(uint32_t length, uint32_t flags)
+ : length_(length), flags_(flags) {}
+
+ private:
+ const uint32_t length_;
+ uint32_t flags_;
};
-// Returns true if the bytes are available immediately (in which case
-// on_complete will not be called), false if the bytes will be available
-// asynchronously.
//
-// max_size_hint can be set as a hint as to the maximum number
-// of bytes that would be acceptable to read.
-bool grpc_byte_stream_next(grpc_byte_stream* byte_stream, size_t max_size_hint,
- grpc_closure* on_complete);
-
-// Returns the next slice in the byte stream when it is ready (indicated by
-// either grpc_byte_stream_next returning true or on_complete passed to
-// grpc_byte_stream_next is called).
+// SliceBufferByteStream
//
-// Once a slice is returned into *slice, it is owned by the caller.
-grpc_error* grpc_byte_stream_pull(grpc_byte_stream* byte_stream,
- grpc_slice* slice);
-
-// Shuts down the byte stream.
+// A ByteStream that wraps a slice buffer.
//
-// If there is a pending call to on_complete from grpc_byte_stream_next(),
-// it will be invoked with the error passed to grpc_byte_stream_shutdown().
-//
-// The next call to grpc_byte_stream_pull() (if any) will return the error
-// passed to grpc_byte_stream_shutdown().
-void grpc_byte_stream_shutdown(grpc_byte_stream* byte_stream,
- grpc_error* error);
-void grpc_byte_stream_destroy(grpc_byte_stream* byte_stream);
+class SliceBufferByteStream : public ByteStream {
+ public:
+ // Removes all slices in slice_buffer, leaving it empty.
+ SliceBufferByteStream(grpc_slice_buffer* slice_buffer, uint32_t flags);
+
+ ~SliceBufferByteStream();
+
+ void Orphan() override;
+
+ bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
+ grpc_error* Pull(grpc_slice* slice) override;
+ void Shutdown(grpc_error* error) override;
+
+ private:
+ grpc_slice_buffer backing_buffer_;
+ size_t cursor_ = 0;
+ grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+};
-// grpc_slice_buffer_stream
//
-// A grpc_byte_stream that wraps a slice buffer. The stream takes
-// ownership of the slices in the buffer, and on destruction will
-// reset the contents of the buffer.
-
-typedef struct grpc_slice_buffer_stream {
- grpc_byte_stream base;
- grpc_slice_buffer backing_buffer;
- size_t cursor;
- grpc_error* shutdown_error;
-} grpc_slice_buffer_stream;
-
-void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream* stream,
- grpc_slice_buffer* slice_buffer,
- uint32_t flags);
-
-// grpc_caching_byte_stream
+// CachingByteStream
//
-// A grpc_byte_stream that that wraps an underlying byte stream but caches
+// A ByteStream that that wraps an underlying byte stream but caches
// the resulting slices in a slice buffer. If an initial attempt fails
// without fully draining the underlying stream, a new caching stream
// can be created from the same underlying cache, in which case it will
@@ -102,32 +115,50 @@ void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream* stream,
// underlying stream.
//
// NOTE: No synchronization is done, so it is not safe to have multiple
-// grpc_caching_byte_streams simultaneously drawing from the same underlying
-// grpc_byte_stream_cache at the same time.
+// CachingByteStreams simultaneously drawing from the same underlying
+// ByteStreamCache at the same time.
+//
+
+class ByteStreamCache {
+ public:
+ class CachingByteStream : public ByteStream {
+ public:
+ explicit CachingByteStream(ByteStreamCache* cache);
+
+ ~CachingByteStream();
+
+ void Orphan() override;
-typedef struct {
- grpc_byte_stream* underlying_stream;
- grpc_slice_buffer cache_buffer;
-} grpc_byte_stream_cache;
+ bool Next(size_t max_size_hint, grpc_closure* on_complete) override;
+ grpc_error* Pull(grpc_slice* slice) override;
+ void Shutdown(grpc_error* error) override;
-// Takes ownership of underlying_stream.
-void grpc_byte_stream_cache_init(grpc_byte_stream_cache* cache,
- grpc_byte_stream* underlying_stream);
+ // Resets the byte stream to the start of the underlying stream.
+ void Reset();
-// Must not be called while still in use by a grpc_caching_byte_stream.
-void grpc_byte_stream_cache_destroy(grpc_byte_stream_cache* cache);
+ private:
+ ByteStreamCache* cache_;
+ size_t cursor_ = 0;
+ size_t offset_ = 0;
+ grpc_error* shutdown_error_ = GRPC_ERROR_NONE;
+ };
-typedef struct {
- grpc_byte_stream base;
- grpc_byte_stream_cache* cache;
- size_t cursor;
- grpc_error* shutdown_error;
-} grpc_caching_byte_stream;
+ explicit ByteStreamCache(OrphanablePtr<ByteStream> underlying_stream);
-void grpc_caching_byte_stream_init(grpc_caching_byte_stream* stream,
- grpc_byte_stream_cache* cache);
+ ~ByteStreamCache();
+
+ // Must not be destroyed while still in use by a CachingByteStream.
+ void Destroy();
+
+ grpc_slice_buffer* cache_buffer() { return &cache_buffer_; }
+
+ private:
+ OrphanablePtr<ByteStream> underlying_stream_;
+ uint32_t length_;
+ uint32_t flags_;
+ grpc_slice_buffer cache_buffer_;
+};
-// Resets the byte stream to the start of the underlying stream.
-void grpc_caching_byte_stream_reset(grpc_caching_byte_stream* stream);
+} // namespace grpc_core
#endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */
diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc
index b23f516516..49740fcd1e 100644
--- a/src/core/lib/transport/metadata_batch.cc
+++ b/src/core/lib/transport/metadata_batch.cc
@@ -303,3 +303,27 @@ grpc_error* grpc_metadata_batch_filter(grpc_metadata_batch* batch,
}
return error;
}
+
+void grpc_metadata_batch_copy(grpc_metadata_batch* src,
+ grpc_metadata_batch* dst,
+ grpc_linked_mdelem* storage) {
+ grpc_metadata_batch_init(dst);
+ dst->deadline = src->deadline;
+ size_t i = 0;
+ for (grpc_linked_mdelem* elem = src->list.head; elem != nullptr;
+ elem = elem->next) {
+ grpc_error* error = grpc_metadata_batch_add_tail(dst, &storage[i++],
+ GRPC_MDELEM_REF(elem->md));
+ // The only way that grpc_metadata_batch_add_tail() can fail is if
+ // there's a duplicate entry for a callout. However, that can't be
+ // the case here, because we would not have been allowed to create
+ // a source batch that had that kind of conflict.
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ }
+}
+
+void grpc_metadata_batch_move(grpc_metadata_batch* src,
+ grpc_metadata_batch* dst) {
+ *dst = *src;
+ grpc_metadata_batch_init(src);
+}
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 06fc9ade7e..3876063b52 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -137,4 +137,13 @@ void grpc_metadata_batch_assert_ok(grpc_metadata_batch* comd);
} while (0)
#endif
+/// Copies \a src to \a dst. \a storage must point to an array of
+/// \a grpc_linked_mdelem structs of at least the same size as \a src.
+void grpc_metadata_batch_copy(grpc_metadata_batch* src,
+ grpc_metadata_batch* dst,
+ grpc_linked_mdelem* storage);
+
+void grpc_metadata_batch_move(grpc_metadata_batch* src,
+ grpc_metadata_batch* dst);
+
#endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H */
diff --git a/src/core/lib/transport/service_config.cc b/src/core/lib/transport/service_config.cc
index b1d727419d..e1a55d98ab 100644
--- a/src/core/lib/transport/service_config.cc
+++ b/src/core/lib/transport/service_config.cc
@@ -31,74 +31,30 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
-// The main purpose of the code here is to parse the service config in
-// JSON form, which will look like this:
-//
-// {
-// "loadBalancingPolicy": "string", // optional
-// "methodConfig": [ // array of one or more method_config objects
-// {
-// "name": [ // array of one or more name objects
-// {
-// "service": "string", // required
-// "method": "string", // optional
-// }
-// ],
-// // remaining fields are optional.
-// // see https://developers.google.com/protocol-buffers/docs/proto3#json
-// // for format details.
-// "waitForReady": bool,
-// "timeout": "duration_string",
-// "maxRequestMessageBytes": "int64_string",
-// "maxResponseMessageBytes": "int64_string",
-// }
-// ]
-// }
-
-struct grpc_service_config {
- char* json_string; // Underlying storage for json_tree.
- grpc_json* json_tree;
-};
+namespace grpc_core {
-grpc_service_config* grpc_service_config_create(const char* json_string) {
- grpc_service_config* service_config =
- static_cast<grpc_service_config*>(gpr_malloc(sizeof(*service_config)));
- service_config->json_string = gpr_strdup(json_string);
- service_config->json_tree =
- grpc_json_parse_string(service_config->json_string);
- if (service_config->json_tree == nullptr) {
+UniquePtr<ServiceConfig> ServiceConfig::Create(const char* json) {
+ UniquePtr<char> json_string(gpr_strdup(json));
+ grpc_json* json_tree = grpc_json_parse_string(json_string.get());
+ if (json_tree == nullptr) {
gpr_log(GPR_INFO, "failed to parse JSON for service config");
- gpr_free(service_config->json_string);
- gpr_free(service_config);
return nullptr;
}
- return service_config;
+ return MakeUnique<ServiceConfig>(std::move(json_string), json_tree);
}
-void grpc_service_config_destroy(grpc_service_config* service_config) {
- grpc_json_destroy(service_config->json_tree);
- gpr_free(service_config->json_string);
- gpr_free(service_config);
-}
+ServiceConfig::ServiceConfig(UniquePtr<char> json_string, grpc_json* json_tree)
+ : json_string_(std::move(json_string)), json_tree_(json_tree) {}
-void grpc_service_config_parse_global_params(
- const grpc_service_config* service_config,
- void (*process_json)(const grpc_json* json, void* arg), void* arg) {
- const grpc_json* json = service_config->json_tree;
- if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return;
- for (grpc_json* field = json->child; field != nullptr; field = field->next) {
- if (field->key == nullptr) return;
- if (strcmp(field->key, "methodConfig") == 0) continue;
- process_json(field, arg);
- }
-}
+ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); }
-const char* grpc_service_config_get_lb_policy_name(
- const grpc_service_config* service_config) {
- const grpc_json* json = service_config->json_tree;
- if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return nullptr;
+const char* ServiceConfig::GetLoadBalancingPolicyName() const {
+ if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
+ return nullptr;
+ }
const char* lb_policy_name = nullptr;
- for (grpc_json* field = json->child; field != nullptr; field = field->next) {
+ for (grpc_json* field = json_tree_->child; field != nullptr;
+ field = field->next) {
if (field->key == nullptr) return nullptr;
if (strcmp(field->key, "loadBalancingPolicy") == 0) {
if (lb_policy_name != nullptr) return nullptr; // Duplicate.
@@ -109,8 +65,7 @@ const char* grpc_service_config_get_lb_policy_name(
return lb_policy_name;
}
-// Returns the number of names specified in the method config \a json.
-static size_t count_names_in_method_config_json(grpc_json* json) {
+size_t ServiceConfig::CountNamesInMethodConfig(grpc_json* json) {
size_t num_names = 0;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key != nullptr && strcmp(field->key, "name") == 0) {
@@ -124,9 +79,7 @@ static size_t count_names_in_method_config_json(grpc_json* json) {
return num_names;
}
-// Returns a path string for the JSON name object specified by \a json.
-// Returns NULL on error. Caller takes ownership of result.
-static char* parse_json_method_name(grpc_json* json) {
+UniquePtr<char> ServiceConfig::ParseJsonMethodName(grpc_json* json) {
if (json->type != GRPC_JSON_OBJECT) return nullptr;
const char* service_name = nullptr;
const char* method_name = nullptr;
@@ -147,116 +100,7 @@ static char* parse_json_method_name(grpc_json* json) {
char* path;
gpr_asprintf(&path, "/%s/%s", service_name,
method_name == nullptr ? "*" : method_name);
- return path;
+ return UniquePtr<char>(path);
}
-// Parses the method config from \a json. Adds an entry to \a entries for
-// each name found, incrementing \a idx for each entry added.
-// Returns false on error.
-static bool parse_json_method_config(
- grpc_json* json, void* (*create_value)(const grpc_json* method_config_json),
- void* (*ref_value)(void* value), void (*unref_value)(void* value),
- grpc_slice_hash_table_entry* entries, size_t* idx) {
- // Construct value.
- void* method_config = create_value(json);
- if (method_config == nullptr) return false;
- // Construct list of paths.
- bool success = false;
- gpr_strvec paths;
- gpr_strvec_init(&paths);
- for (grpc_json* child = json->child; child != nullptr; child = child->next) {
- if (child->key == nullptr) continue;
- if (strcmp(child->key, "name") == 0) {
- if (child->type != GRPC_JSON_ARRAY) goto done;
- for (grpc_json* name = child->child; name != nullptr; name = name->next) {
- char* path = parse_json_method_name(name);
- if (path == nullptr) goto done;
- gpr_strvec_add(&paths, path);
- }
- }
- }
- if (paths.count == 0) goto done; // No names specified.
- // Add entry for each path.
- for (size_t i = 0; i < paths.count; ++i) {
- entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]);
- entries[*idx].value = ref_value(method_config);
- ++*idx;
- }
- success = true;
-done:
- unref_value(method_config);
- gpr_strvec_destroy(&paths);
- return success;
-}
-
-grpc_slice_hash_table* grpc_service_config_create_method_config_table(
- const grpc_service_config* service_config,
- void* (*create_value)(const grpc_json* method_config_json),
- void* (*ref_value)(void* value), void (*unref_value)(void* value)) {
- const grpc_json* json = service_config->json_tree;
- // Traverse parsed JSON tree.
- if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return nullptr;
- size_t num_entries = 0;
- grpc_slice_hash_table_entry* entries = nullptr;
- for (grpc_json* field = json->child; field != nullptr; field = field->next) {
- if (field->key == nullptr) return nullptr;
- if (strcmp(field->key, "methodConfig") == 0) {
- if (entries != nullptr) return nullptr; // Duplicate.
- if (field->type != GRPC_JSON_ARRAY) return nullptr;
- // Find number of entries.
- for (grpc_json* method = field->child; method != nullptr;
- method = method->next) {
- size_t count = count_names_in_method_config_json(method);
- if (count <= 0) return nullptr;
- num_entries += count;
- }
- // Populate method config table entries.
- entries = static_cast<grpc_slice_hash_table_entry*>(
- gpr_malloc(num_entries * sizeof(grpc_slice_hash_table_entry)));
- size_t idx = 0;
- for (grpc_json* method = field->child; method != nullptr;
- method = method->next) {
- if (!parse_json_method_config(method, create_value, ref_value,
- unref_value, entries, &idx)) {
- for (size_t i = 0; i < idx; ++i) {
- grpc_slice_unref_internal(entries[i].key);
- unref_value(entries[i].value);
- }
- gpr_free(entries);
- return nullptr;
- }
- }
- GPR_ASSERT(idx == num_entries);
- }
- }
- // Instantiate method config table.
- grpc_slice_hash_table* method_config_table = nullptr;
- if (entries != nullptr) {
- method_config_table = grpc_slice_hash_table_create(num_entries, entries,
- unref_value, nullptr);
- gpr_free(entries);
- }
- return method_config_table;
-}
-
-void* grpc_method_config_table_get(const grpc_slice_hash_table* table,
- grpc_slice path) {
- void* value = grpc_slice_hash_table_get(table, path);
- // If we didn't find a match for the path, try looking for a wildcard
- // entry (i.e., change "/service/method" to "/service/*").
- if (value == nullptr) {
- char* path_str = grpc_slice_to_c_string(path);
- const char* sep = strrchr(path_str, '/') + 1;
- const size_t len = static_cast<size_t>(sep - path_str);
- char* buf = static_cast<char*>(gpr_malloc(len + 2)); // '*' and NUL
- memcpy(buf, path_str, len);
- buf[len] = '*';
- buf[len + 1] = '\0';
- grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
- gpr_free(buf);
- value = grpc_slice_hash_table_get(table, wildcard_path);
- grpc_slice_unref_internal(wildcard_path);
- gpr_free(path_str);
- }
- return value;
-}
+} // namespace grpc_core
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
index 6517f36802..a65b267d46 100644
--- a/src/core/lib/transport/service_config.h
+++ b/src/core/lib/transport/service_config.h
@@ -20,44 +20,230 @@
#include <grpc/support/port_platform.h>
#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/string_util.h>
+#include "src/core/lib/gprpp/inlined_vector.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/slice/slice_hash_table.h"
-typedef struct grpc_service_config grpc_service_config;
-
-grpc_service_config* grpc_service_config_create(const char* json_string);
-void grpc_service_config_destroy(grpc_service_config* service_config);
-
-/// Invokes \a process_json() for each global parameter in the service
-/// config. \a arg is passed as the second argument to \a process_json().
-void grpc_service_config_parse_global_params(
- const grpc_service_config* service_config,
- void (*process_json)(const grpc_json* json, void* arg), void* arg);
-
-/// Gets the LB policy name from \a service_config.
-/// Returns NULL if no LB policy name was specified.
-/// Caller does NOT take ownership.
-const char* grpc_service_config_get_lb_policy_name(
- const grpc_service_config* service_config);
-
-/// Creates a method config table based on the data in \a json.
-/// The table's keys are request paths. The table's value type is
-/// returned by \a create_value(), based on data parsed from the JSON tree.
-/// \a ref_value() and \a unref_value() are used to ref and unref values.
-/// Returns NULL on error.
-grpc_slice_hash_table* grpc_service_config_create_method_config_table(
- const grpc_service_config* service_config,
- void* (*create_value)(const grpc_json* method_config_json),
- void* (*ref_value)(void* value), void (*unref_value)(void* value));
-
-/// A helper function for looking up values in the table returned by
-/// \a grpc_service_config_create_method_config_table().
-/// Gets the method config for the specified \a path, which should be of
-/// the form "/service/method".
-/// Returns NULL if the method has no config.
-/// Caller does NOT own a reference to the result.
-void* grpc_method_config_table_get(const grpc_slice_hash_table* table,
- grpc_slice path);
+// The main purpose of the code here is to parse the service config in
+// JSON form, which will look like this:
+//
+// {
+// "loadBalancingPolicy": "string", // optional
+// "methodConfig": [ // array of one or more method_config objects
+// {
+// "name": [ // array of one or more name objects
+// {
+// "service": "string", // required
+// "method": "string", // optional
+// }
+// ],
+// // remaining fields are optional.
+// // see
+// https://developers.google.com/protocol-buffers/docs/proto3#json
+// // for format details.
+// "waitForReady": bool,
+// "timeout": "duration_string",
+// "maxRequestMessageBytes": "int64_string",
+// "maxResponseMessageBytes": "int64_string",
+// }
+// ]
+// }
+
+namespace grpc_core {
+
+class ServiceConfig {
+ public:
+ /// Creates a new service config from parsing \a json_string.
+ /// Returns null on parse error.
+ static UniquePtr<ServiceConfig> Create(const char* json);
+
+ ~ServiceConfig();
+
+ /// Invokes \a process_json() for each global parameter in the service
+ /// config. \a arg is passed as the second argument to \a process_json().
+ template <typename T>
+ using ProcessJson = void (*)(const grpc_json*, T*);
+ template <typename T>
+ void ParseGlobalParams(ProcessJson<T> process_json, T* arg) const;
+
+ /// Gets the LB policy name from \a service_config.
+ /// Returns NULL if no LB policy name was specified.
+ /// Caller does NOT take ownership.
+ const char* GetLoadBalancingPolicyName() const;
+
+ /// Creates a method config table based on the data in \a json.
+ /// The table's keys are request paths. The table's value type is
+ /// returned by \a create_value(), based on data parsed from the JSON tree.
+ /// Returns null on error.
+ template <typename T>
+ using CreateValue = RefCountedPtr<T> (*)(const grpc_json* method_config_json);
+ template <typename T>
+ RefCountedPtr<SliceHashTable<RefCountedPtr<T>>> CreateMethodConfigTable(
+ CreateValue<T> create_value);
+
+ /// A helper function for looking up values in the table returned by
+ /// \a CreateMethodConfigTable().
+ /// Gets the method config for the specified \a path, which should be of
+ /// the form "/service/method".
+ /// Returns null if the method has no config.
+ /// Caller does NOT own a reference to the result.
+ template <typename T>
+ static RefCountedPtr<T> MethodConfigTableLookup(
+ const SliceHashTable<RefCountedPtr<T>>& table, grpc_slice path);
+
+ private:
+ // So New() can call our private ctor.
+ template <typename T, typename... Args>
+ friend T* New(Args&&... args);
+
+ // Takes ownership of \a json_tree.
+ ServiceConfig(UniquePtr<char> json_string, grpc_json* json_tree);
+
+ // Returns the number of names specified in the method config \a json.
+ static size_t CountNamesInMethodConfig(grpc_json* json);
+
+ // Returns a path string for the JSON name object specified by \a json.
+ // Returns null on error.
+ static UniquePtr<char> ParseJsonMethodName(grpc_json* json);
+
+ // Parses the method config from \a json. Adds an entry to \a entries for
+ // each name found, incrementing \a idx for each entry added.
+ // Returns false on error.
+ template <typename T>
+ static bool ParseJsonMethodConfig(
+ grpc_json* json, CreateValue<T> create_value,
+ typename SliceHashTable<RefCountedPtr<T>>::Entry* entries, size_t* idx);
+
+ UniquePtr<char> json_string_; // Underlying storage for json_tree.
+ grpc_json* json_tree_;
+};
+
+//
+// implementation -- no user-serviceable parts below
+//
+
+template <typename T>
+void ServiceConfig::ParseGlobalParams(ProcessJson<T> process_json,
+ T* arg) const {
+ if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
+ return;
+ }
+ for (grpc_json* field = json_tree_->child; field != nullptr;
+ field = field->next) {
+ if (field->key == nullptr) return;
+ if (strcmp(field->key, "methodConfig") == 0) continue;
+ process_json(field, arg);
+ }
+}
+
+template <typename T>
+bool ServiceConfig::ParseJsonMethodConfig(
+ grpc_json* json, CreateValue<T> create_value,
+ typename SliceHashTable<RefCountedPtr<T>>::Entry* entries, size_t* idx) {
+ // Construct value.
+ RefCountedPtr<T> method_config = create_value(json);
+ if (method_config == nullptr) return false;
+ // Construct list of paths.
+ InlinedVector<UniquePtr<char>, 10> paths;
+ for (grpc_json* child = json->child; child != nullptr; child = child->next) {
+ if (child->key == nullptr) continue;
+ if (strcmp(child->key, "name") == 0) {
+ if (child->type != GRPC_JSON_ARRAY) return false;
+ for (grpc_json* name = child->child; name != nullptr; name = name->next) {
+ UniquePtr<char> path = ParseJsonMethodName(name);
+ if (path == nullptr) return false;
+ paths.push_back(std::move(path));
+ }
+ }
+ }
+ if (paths.size() == 0) return false; // No names specified.
+ // Add entry for each path.
+ for (size_t i = 0; i < paths.size(); ++i) {
+ entries[*idx].key = grpc_slice_from_copied_string(paths[i].get());
+ entries[*idx].value = method_config; // Takes a new ref.
+ ++*idx;
+ }
+ // Success.
+ return true;
+}
+
+template <typename T>
+RefCountedPtr<SliceHashTable<RefCountedPtr<T>>>
+ServiceConfig::CreateMethodConfigTable(CreateValue<T> create_value) {
+ // Traverse parsed JSON tree.
+ if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
+ return nullptr;
+ }
+ size_t num_entries = 0;
+ typename SliceHashTable<RefCountedPtr<T>>::Entry* entries = nullptr;
+ for (grpc_json* field = json_tree_->child; field != nullptr;
+ field = field->next) {
+ if (field->key == nullptr) return nullptr;
+ if (strcmp(field->key, "methodConfig") == 0) {
+ if (entries != nullptr) return nullptr; // Duplicate.
+ if (field->type != GRPC_JSON_ARRAY) return nullptr;
+ // Find number of entries.
+ for (grpc_json* method = field->child; method != nullptr;
+ method = method->next) {
+ size_t count = CountNamesInMethodConfig(method);
+ if (count <= 0) return nullptr;
+ num_entries += count;
+ }
+ // Populate method config table entries.
+ entries = static_cast<typename SliceHashTable<RefCountedPtr<T>>::Entry*>(
+ gpr_zalloc(num_entries *
+ sizeof(typename SliceHashTable<RefCountedPtr<T>>::Entry)));
+ size_t idx = 0;
+ for (grpc_json* method = field->child; method != nullptr;
+ method = method->next) {
+ if (!ParseJsonMethodConfig(method, create_value, entries, &idx)) {
+ for (size_t i = 0; i < idx; ++i) {
+ grpc_slice_unref_internal(entries[i].key);
+ entries[i].value.reset();
+ }
+ gpr_free(entries);
+ return nullptr;
+ }
+ }
+ GPR_ASSERT(idx == num_entries);
+ }
+ }
+ // Instantiate method config table.
+ RefCountedPtr<SliceHashTable<RefCountedPtr<T>>> method_config_table;
+ if (entries != nullptr) {
+ method_config_table =
+ SliceHashTable<RefCountedPtr<T>>::Create(num_entries, entries, nullptr);
+ gpr_free(entries);
+ }
+ return method_config_table;
+}
+
+template <typename T>
+RefCountedPtr<T> ServiceConfig::MethodConfigTableLookup(
+ const SliceHashTable<RefCountedPtr<T>>& table, grpc_slice path) {
+ const RefCountedPtr<T>* value = table.Get(path);
+ // If we didn't find a match for the path, try looking for a wildcard
+ // entry (i.e., change "/service/method" to "/service/*").
+ if (value == nullptr) {
+ char* path_str = grpc_slice_to_c_string(path);
+ const char* sep = strrchr(path_str, '/') + 1;
+ const size_t len = (size_t)(sep - path_str);
+ char* buf = (char*)gpr_malloc(len + 2); // '*' and NUL
+ memcpy(buf, path_str, len);
+ buf[len] = '*';
+ buf[len + 1] = '\0';
+ grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
+ gpr_free(buf);
+ value = table.Get(wildcard_path);
+ grpc_slice_unref_internal(wildcard_path);
+ gpr_free(path_str);
+ }
+ return RefCountedPtr<T>(*value);
+}
+
+} // namespace grpc_core
#endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */
diff --git a/src/core/lib/transport/static_metadata.cc b/src/core/lib/transport/static_metadata.cc
index 0e11b6e4e4..6a5144f21a 100644
--- a/src/core/lib/transport/static_metadata.cc
+++ b/src/core/lib/transport/static_metadata.cc
@@ -50,61 +50,64 @@ static uint8_t g_bytes[] = {
114, 110, 97, 108, 45, 115, 116, 114, 101, 97, 109, 45, 101, 110, 99,
111, 100, 105, 110, 103, 45, 114, 101, 113, 117, 101, 115, 116, 117, 115,
101, 114, 45, 97, 103, 101, 110, 116, 104, 111, 115, 116, 108, 98, 45,
- 116, 111, 107, 101, 110, 103, 114, 112, 99, 45, 116, 105, 109, 101, 111,
- 117, 116, 103, 114, 112, 99, 46, 119, 97, 105, 116, 95, 102, 111, 114,
- 95, 114, 101, 97, 100, 121, 103, 114, 112, 99, 46, 116, 105, 109, 101,
- 111, 117, 116, 103, 114, 112, 99, 46, 109, 97, 120, 95, 114, 101, 113,
- 117, 101, 115, 116, 95, 109, 101, 115, 115, 97, 103, 101, 95, 98, 121,
- 116, 101, 115, 103, 114, 112, 99, 46, 109, 97, 120, 95, 114, 101, 115,
- 112, 111, 110, 115, 101, 95, 109, 101, 115, 115, 97, 103, 101, 95, 98,
- 121, 116, 101, 115, 47, 103, 114, 112, 99, 46, 108, 98, 46, 118, 49,
- 46, 76, 111, 97, 100, 66, 97, 108, 97, 110, 99, 101, 114, 47, 66,
- 97, 108, 97, 110, 99, 101, 76, 111, 97, 100, 100, 101, 102, 108, 97,
- 116, 101, 103, 122, 105, 112, 115, 116, 114, 101, 97, 109, 47, 103, 122,
- 105, 112, 48, 49, 50, 105, 100, 101, 110, 116, 105, 116, 121, 116, 114,
- 97, 105, 108, 101, 114, 115, 97, 112, 112, 108, 105, 99, 97, 116, 105,
- 111, 110, 47, 103, 114, 112, 99, 80, 79, 83, 84, 50, 48, 48, 52,
- 48, 52, 104, 116, 116, 112, 104, 116, 116, 112, 115, 103, 114, 112, 99,
- 71, 69, 84, 80, 85, 84, 47, 47, 105, 110, 100, 101, 120, 46, 104,
- 116, 109, 108, 50, 48, 52, 50, 48, 54, 51, 48, 52, 52, 48, 48,
- 53, 48, 48, 97, 99, 99, 101, 112, 116, 45, 99, 104, 97, 114, 115,
- 101, 116, 103, 122, 105, 112, 44, 32, 100, 101, 102, 108, 97, 116, 101,
- 97, 99, 99, 101, 112, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101,
- 97, 99, 99, 101, 112, 116, 45, 114, 97, 110, 103, 101, 115, 97, 99,
- 99, 101, 112, 116, 97, 99, 99, 101, 115, 115, 45, 99, 111, 110, 116,
- 114, 111, 108, 45, 97, 108, 108, 111, 119, 45, 111, 114, 105, 103, 105,
- 110, 97, 103, 101, 97, 108, 108, 111, 119, 97, 117, 116, 104, 111, 114,
- 105, 122, 97, 116, 105, 111, 110, 99, 97, 99, 104, 101, 45, 99, 111,
- 110, 116, 114, 111, 108, 99, 111, 110, 116, 101, 110, 116, 45, 100, 105,
- 115, 112, 111, 115, 105, 116, 105, 111, 110, 99, 111, 110, 116, 101, 110,
- 116, 45, 108, 97, 110, 103, 117, 97, 103, 101, 99, 111, 110, 116, 101,
- 110, 116, 45, 108, 101, 110, 103, 116, 104, 99, 111, 110, 116, 101, 110,
- 116, 45, 108, 111, 99, 97, 116, 105, 111, 110, 99, 111, 110, 116, 101,
- 110, 116, 45, 114, 97, 110, 103, 101, 99, 111, 111, 107, 105, 101, 100,
- 97, 116, 101, 101, 116, 97, 103, 101, 120, 112, 101, 99, 116, 101, 120,
- 112, 105, 114, 101, 115, 102, 114, 111, 109, 105, 102, 45, 109, 97, 116,
- 99, 104, 105, 102, 45, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115,
- 105, 110, 99, 101, 105, 102, 45, 110, 111, 110, 101, 45, 109, 97, 116,
- 99, 104, 105, 102, 45, 114, 97, 110, 103, 101, 105, 102, 45, 117, 110,
- 109, 111, 100, 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, 101, 108,
- 97, 115, 116, 45, 109, 111, 100, 105, 102, 105, 101, 100, 108, 98, 45,
- 99, 111, 115, 116, 45, 98, 105, 110, 108, 105, 110, 107, 108, 111, 99,
- 97, 116, 105, 111, 110, 109, 97, 120, 45, 102, 111, 114, 119, 97, 114,
- 100, 115, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 101, 110, 116,
- 105, 99, 97, 116, 101, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104,
- 111, 114, 105, 122, 97, 116, 105, 111, 110, 114, 97, 110, 103, 101, 114,
- 101, 102, 101, 114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101,
- 116, 114, 121, 45, 97, 102, 116, 101, 114, 115, 101, 114, 118, 101, 114,
- 115, 101, 116, 45, 99, 111, 111, 107, 105, 101, 115, 116, 114, 105, 99,
- 116, 45, 116, 114, 97, 110, 115, 112, 111, 114, 116, 45, 115, 101, 99,
- 117, 114, 105, 116, 121, 116, 114, 97, 110, 115, 102, 101, 114, 45, 101,
- 110, 99, 111, 100, 105, 110, 103, 118, 97, 114, 121, 118, 105, 97, 119,
- 119, 119, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101,
- 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116,
- 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 103, 122, 105, 112, 100,
- 101, 102, 108, 97, 116, 101, 44, 103, 122, 105, 112, 105, 100, 101, 110,
- 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122,
- 105, 112};
+ 116, 111, 107, 101, 110, 103, 114, 112, 99, 45, 112, 114, 101, 118, 105,
+ 111, 117, 115, 45, 114, 112, 99, 45, 97, 116, 116, 101, 109, 112, 116,
+ 115, 103, 114, 112, 99, 45, 114, 101, 116, 114, 121, 45, 112, 117, 115,
+ 104, 98, 97, 99, 107, 45, 109, 115, 103, 114, 112, 99, 45, 116, 105,
+ 109, 101, 111, 117, 116, 49, 50, 51, 52, 103, 114, 112, 99, 46, 119,
+ 97, 105, 116, 95, 102, 111, 114, 95, 114, 101, 97, 100, 121, 103, 114,
+ 112, 99, 46, 116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99, 46,
+ 109, 97, 120, 95, 114, 101, 113, 117, 101, 115, 116, 95, 109, 101, 115,
+ 115, 97, 103, 101, 95, 98, 121, 116, 101, 115, 103, 114, 112, 99, 46,
+ 109, 97, 120, 95, 114, 101, 115, 112, 111, 110, 115, 101, 95, 109, 101,
+ 115, 115, 97, 103, 101, 95, 98, 121, 116, 101, 115, 47, 103, 114, 112,
+ 99, 46, 108, 98, 46, 118, 49, 46, 76, 111, 97, 100, 66, 97, 108,
+ 97, 110, 99, 101, 114, 47, 66, 97, 108, 97, 110, 99, 101, 76, 111,
+ 97, 100, 100, 101, 102, 108, 97, 116, 101, 103, 122, 105, 112, 115, 116,
+ 114, 101, 97, 109, 47, 103, 122, 105, 112, 48, 105, 100, 101, 110, 116,
+ 105, 116, 121, 116, 114, 97, 105, 108, 101, 114, 115, 97, 112, 112, 108,
+ 105, 99, 97, 116, 105, 111, 110, 47, 103, 114, 112, 99, 80, 79, 83,
+ 84, 50, 48, 48, 52, 48, 52, 104, 116, 116, 112, 104, 116, 116, 112,
+ 115, 103, 114, 112, 99, 71, 69, 84, 80, 85, 84, 47, 47, 105, 110,
+ 100, 101, 120, 46, 104, 116, 109, 108, 50, 48, 52, 50, 48, 54, 51,
+ 48, 52, 52, 48, 48, 53, 48, 48, 97, 99, 99, 101, 112, 116, 45,
+ 99, 104, 97, 114, 115, 101, 116, 103, 122, 105, 112, 44, 32, 100, 101,
+ 102, 108, 97, 116, 101, 97, 99, 99, 101, 112, 116, 45, 108, 97, 110,
+ 103, 117, 97, 103, 101, 97, 99, 99, 101, 112, 116, 45, 114, 97, 110,
+ 103, 101, 115, 97, 99, 99, 101, 112, 116, 97, 99, 99, 101, 115, 115,
+ 45, 99, 111, 110, 116, 114, 111, 108, 45, 97, 108, 108, 111, 119, 45,
+ 111, 114, 105, 103, 105, 110, 97, 103, 101, 97, 108, 108, 111, 119, 97,
+ 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 99, 97, 99,
+ 104, 101, 45, 99, 111, 110, 116, 114, 111, 108, 99, 111, 110, 116, 101,
+ 110, 116, 45, 100, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 99,
+ 111, 110, 116, 101, 110, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101,
+ 99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 99,
+ 111, 110, 116, 101, 110, 116, 45, 108, 111, 99, 97, 116, 105, 111, 110,
+ 99, 111, 110, 116, 101, 110, 116, 45, 114, 97, 110, 103, 101, 99, 111,
+ 111, 107, 105, 101, 100, 97, 116, 101, 101, 116, 97, 103, 101, 120, 112,
+ 101, 99, 116, 101, 120, 112, 105, 114, 101, 115, 102, 114, 111, 109, 105,
+ 102, 45, 109, 97, 116, 99, 104, 105, 102, 45, 109, 111, 100, 105, 102,
+ 105, 101, 100, 45, 115, 105, 110, 99, 101, 105, 102, 45, 110, 111, 110,
+ 101, 45, 109, 97, 116, 99, 104, 105, 102, 45, 114, 97, 110, 103, 101,
+ 105, 102, 45, 117, 110, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115,
+ 105, 110, 99, 101, 108, 97, 115, 116, 45, 109, 111, 100, 105, 102, 105,
+ 101, 100, 108, 98, 45, 99, 111, 115, 116, 45, 98, 105, 110, 108, 105,
+ 110, 107, 108, 111, 99, 97, 116, 105, 111, 110, 109, 97, 120, 45, 102,
+ 111, 114, 119, 97, 114, 100, 115, 112, 114, 111, 120, 121, 45, 97, 117,
+ 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 112, 114, 111, 120, 121,
+ 45, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 114,
+ 97, 110, 103, 101, 114, 101, 102, 101, 114, 101, 114, 114, 101, 102, 114,
+ 101, 115, 104, 114, 101, 116, 114, 121, 45, 97, 102, 116, 101, 114, 115,
+ 101, 114, 118, 101, 114, 115, 101, 116, 45, 99, 111, 111, 107, 105, 101,
+ 115, 116, 114, 105, 99, 116, 45, 116, 114, 97, 110, 115, 112, 111, 114,
+ 116, 45, 115, 101, 99, 117, 114, 105, 116, 121, 116, 114, 97, 110, 115,
+ 102, 101, 114, 45, 101, 110, 99, 111, 100, 105, 110, 103, 118, 97, 114,
+ 121, 118, 105, 97, 119, 119, 119, 45, 97, 117, 116, 104, 101, 110, 116,
+ 105, 99, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100,
+ 101, 102, 108, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44,
+ 103, 122, 105, 112, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122, 105,
+ 112, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97,
+ 116, 101, 44, 103, 122, 105, 112};
static void static_ref(void* unused) {}
static void static_unref(void* unused) {}
@@ -217,6 +220,10 @@ grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
+ {&grpc_static_metadata_vtable, &static_sub_refcnt},
};
const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
@@ -242,85 +249,89 @@ const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
- {&grpc_static_metadata_refcounts[22], {{g_bytes + 290, 12}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}},
- {&grpc_static_metadata_refcounts[24], {{g_bytes + 302, 19}}},
- {&grpc_static_metadata_refcounts[25], {{g_bytes + 321, 12}}},
- {&grpc_static_metadata_refcounts[26], {{g_bytes + 333, 30}}},
- {&grpc_static_metadata_refcounts[27], {{g_bytes + 363, 31}}},
- {&grpc_static_metadata_refcounts[28], {{g_bytes + 394, 36}}},
- {&grpc_static_metadata_refcounts[29], {{g_bytes + 430, 7}}},
- {&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}},
- {&grpc_static_metadata_refcounts[31], {{g_bytes + 441, 11}}},
- {&grpc_static_metadata_refcounts[32], {{g_bytes + 452, 1}}},
- {&grpc_static_metadata_refcounts[33], {{g_bytes + 453, 1}}},
- {&grpc_static_metadata_refcounts[34], {{g_bytes + 454, 1}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 463, 8}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 471, 16}}},
- {&grpc_static_metadata_refcounts[38], {{g_bytes + 487, 4}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 491, 3}}},
- {&grpc_static_metadata_refcounts[40], {{g_bytes + 494, 3}}},
- {&grpc_static_metadata_refcounts[41], {{g_bytes + 497, 4}}},
- {&grpc_static_metadata_refcounts[42], {{g_bytes + 501, 5}}},
- {&grpc_static_metadata_refcounts[43], {{g_bytes + 506, 4}}},
- {&grpc_static_metadata_refcounts[44], {{g_bytes + 510, 3}}},
- {&grpc_static_metadata_refcounts[45], {{g_bytes + 513, 3}}},
- {&grpc_static_metadata_refcounts[46], {{g_bytes + 516, 1}}},
- {&grpc_static_metadata_refcounts[47], {{g_bytes + 517, 11}}},
- {&grpc_static_metadata_refcounts[48], {{g_bytes + 528, 3}}},
- {&grpc_static_metadata_refcounts[49], {{g_bytes + 531, 3}}},
- {&grpc_static_metadata_refcounts[50], {{g_bytes + 534, 3}}},
- {&grpc_static_metadata_refcounts[51], {{g_bytes + 537, 3}}},
- {&grpc_static_metadata_refcounts[52], {{g_bytes + 540, 3}}},
- {&grpc_static_metadata_refcounts[53], {{g_bytes + 543, 14}}},
- {&grpc_static_metadata_refcounts[54], {{g_bytes + 557, 13}}},
- {&grpc_static_metadata_refcounts[55], {{g_bytes + 570, 15}}},
- {&grpc_static_metadata_refcounts[56], {{g_bytes + 585, 13}}},
- {&grpc_static_metadata_refcounts[57], {{g_bytes + 598, 6}}},
- {&grpc_static_metadata_refcounts[58], {{g_bytes + 604, 27}}},
- {&grpc_static_metadata_refcounts[59], {{g_bytes + 631, 3}}},
- {&grpc_static_metadata_refcounts[60], {{g_bytes + 634, 5}}},
- {&grpc_static_metadata_refcounts[61], {{g_bytes + 639, 13}}},
- {&grpc_static_metadata_refcounts[62], {{g_bytes + 652, 13}}},
- {&grpc_static_metadata_refcounts[63], {{g_bytes + 665, 19}}},
- {&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 16}}},
- {&grpc_static_metadata_refcounts[65], {{g_bytes + 700, 14}}},
- {&grpc_static_metadata_refcounts[66], {{g_bytes + 714, 16}}},
- {&grpc_static_metadata_refcounts[67], {{g_bytes + 730, 13}}},
- {&grpc_static_metadata_refcounts[68], {{g_bytes + 743, 6}}},
- {&grpc_static_metadata_refcounts[69], {{g_bytes + 749, 4}}},
- {&grpc_static_metadata_refcounts[70], {{g_bytes + 753, 4}}},
- {&grpc_static_metadata_refcounts[71], {{g_bytes + 757, 6}}},
- {&grpc_static_metadata_refcounts[72], {{g_bytes + 763, 7}}},
- {&grpc_static_metadata_refcounts[73], {{g_bytes + 770, 4}}},
- {&grpc_static_metadata_refcounts[74], {{g_bytes + 774, 8}}},
- {&grpc_static_metadata_refcounts[75], {{g_bytes + 782, 17}}},
- {&grpc_static_metadata_refcounts[76], {{g_bytes + 799, 13}}},
- {&grpc_static_metadata_refcounts[77], {{g_bytes + 812, 8}}},
- {&grpc_static_metadata_refcounts[78], {{g_bytes + 820, 19}}},
- {&grpc_static_metadata_refcounts[79], {{g_bytes + 839, 13}}},
- {&grpc_static_metadata_refcounts[80], {{g_bytes + 852, 11}}},
- {&grpc_static_metadata_refcounts[81], {{g_bytes + 863, 4}}},
- {&grpc_static_metadata_refcounts[82], {{g_bytes + 867, 8}}},
- {&grpc_static_metadata_refcounts[83], {{g_bytes + 875, 12}}},
- {&grpc_static_metadata_refcounts[84], {{g_bytes + 887, 18}}},
- {&grpc_static_metadata_refcounts[85], {{g_bytes + 905, 19}}},
- {&grpc_static_metadata_refcounts[86], {{g_bytes + 924, 5}}},
- {&grpc_static_metadata_refcounts[87], {{g_bytes + 929, 7}}},
- {&grpc_static_metadata_refcounts[88], {{g_bytes + 936, 7}}},
- {&grpc_static_metadata_refcounts[89], {{g_bytes + 943, 11}}},
- {&grpc_static_metadata_refcounts[90], {{g_bytes + 954, 6}}},
- {&grpc_static_metadata_refcounts[91], {{g_bytes + 960, 10}}},
- {&grpc_static_metadata_refcounts[92], {{g_bytes + 970, 25}}},
- {&grpc_static_metadata_refcounts[93], {{g_bytes + 995, 17}}},
- {&grpc_static_metadata_refcounts[94], {{g_bytes + 1012, 4}}},
- {&grpc_static_metadata_refcounts[95], {{g_bytes + 1016, 3}}},
- {&grpc_static_metadata_refcounts[96], {{g_bytes + 1019, 16}}},
- {&grpc_static_metadata_refcounts[97], {{g_bytes + 1035, 16}}},
- {&grpc_static_metadata_refcounts[98], {{g_bytes + 1051, 13}}},
- {&grpc_static_metadata_refcounts[99], {{g_bytes + 1064, 12}}},
- {&grpc_static_metadata_refcounts[100], {{g_bytes + 1076, 21}}},
+ {&grpc_static_metadata_refcounts[22], {{g_bytes + 290, 26}}},
+ {&grpc_static_metadata_refcounts[23], {{g_bytes + 316, 22}}},
+ {&grpc_static_metadata_refcounts[24], {{g_bytes + 338, 12}}},
+ {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}},
+ {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}},
+ {&grpc_static_metadata_refcounts[27], {{g_bytes + 352, 1}}},
+ {&grpc_static_metadata_refcounts[28], {{g_bytes + 353, 1}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}},
+ {&grpc_static_metadata_refcounts[30], {{g_bytes + 354, 19}}},
+ {&grpc_static_metadata_refcounts[31], {{g_bytes + 373, 12}}},
+ {&grpc_static_metadata_refcounts[32], {{g_bytes + 385, 30}}},
+ {&grpc_static_metadata_refcounts[33], {{g_bytes + 415, 31}}},
+ {&grpc_static_metadata_refcounts[34], {{g_bytes + 446, 36}}},
+ {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}},
+ {&grpc_static_metadata_refcounts[37], {{g_bytes + 493, 11}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}},
+ {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}},
+ {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}},
+ {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}},
+ {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}},
+ {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}},
+ {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}},
+ {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}},
+ {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}},
+ {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}},
+ {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}},
+ {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}},
+ {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}},
+ {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}},
+ {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}},
+ {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}},
+ {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}},
+ {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}},
+ {&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
+ {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}},
+ {&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
+ {&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
+ {&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
+ {&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
+ {&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
+ {&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
+ {&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
+ {&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
+ {&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
+ {&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
+ {&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
+ {&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
+ {&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
+ {&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
+ {&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
+ {&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
+ {&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
+ {&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
+ {&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
+ {&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
+ {&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
+ {&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
+ {&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
+ {&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
+ {&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
+ {&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
+ {&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
+ {&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
+ {&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
+ {&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
+ {&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
+ {&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
+ {&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
+ {&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
+ {&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
+ {&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
+ {&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
+ {&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
+ {&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
+ {&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
+ {&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
+ {&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
+ {&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}},
+ {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}},
+ {&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}},
+ {&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}},
};
uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
@@ -330,50 +341,51 @@ uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8, 2, 4, 4};
static const int8_t elems_r[] = {
- 13, 2, 1, 0, 15, 4, 0, 21, 0, 23, -3, 0, 0, 0, 10, 19, -4,
- 0, 0, 1, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, -52, 0, -55, -36, -57, -58, -58, -58, 0, 40, 39, 38, 37, 36, 35,
- 34, 33, 32, 31, 30, 29, 28, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
- 18, 17, 16, 15, 18, 17, 16, 15, 14, 13, 12, 11, 11, 0};
+ 16, 11, -1, 0, 15, 2, -78, 24, 0, 18, -5, 0, 0, 0, 17, 14, -8, 0,
+ 0, 27, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, -64, 0, -44, -43, -70, 0, 34, 33, 33, 32, 31, 30, 29, 28, 27,
+ 27, 26, 25, 24, 23, 22, 21, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12,
+ 11, 14, 13, 12, 11, 10, 9, 9, 8, 7, 6, 5, 0};
static uint32_t elems_phash(uint32_t i) {
- i -= 46;
- uint32_t x = i % 99;
- uint32_t y = i / 99;
+ i -= 50;
+ uint32_t x = i % 103;
+ uint32_t y = i / 103;
uint32_t h = x;
if (y < GPR_ARRAY_SIZE(elems_r)) {
- uint32_t delta = static_cast<uint32_t>(elems_r[y]);
+ uint32_t delta = (uint32_t)elems_r[y];
h += delta;
}
return h;
}
static const uint16_t elem_keys[] = {
- 1039, 1040, 145, 146, 541, 1639, 1045, 250, 251, 252, 253, 254,
- 1646, 46, 47, 1437, 1942, 1651, 445, 446, 447, 739, 740, 741,
- 938, 939, 1538, 2043, 2144, 1451, 944, 5376, 5578, 1545, 5780, 5881,
- 1670, 5982, 1550, 6083, 6184, 6285, 6386, 6487, 6588, 6689, 6790, 6891,
- 6992, 7093, 7194, 7295, 7396, 5679, 7497, 7598, 7699, 7800, 7901, 8002,
- 8103, 8204, 8305, 8406, 8507, 8608, 8709, 8810, 1107, 1108, 1109, 1110,
- 8911, 9012, 9113, 9214, 9315, 9416, 9517, 9618, 1714, 9719, 0, 326,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 241, 242, 0, 0, 0, 0, 0, 0, 139, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0};
+ 1085, 1086, 565, 1709, 1089, 262, 263, 264, 265, 266, 1716,
+ 153, 154, 1719, 760, 761, 50, 51, 465, 466, 467, 980,
+ 981, 1604, 1499, 984, 773, 2129, 2234, 6014, 1611, 6434, 1738,
+ 1614, 6539, 6644, 1511, 6749, 6854, 6959, 7064, 7169, 7274, 7379,
+ 2024, 7484, 7589, 7694, 7799, 7904, 8009, 8114, 8219, 6224, 8324,
+ 8429, 6329, 8534, 8639, 8744, 8849, 8954, 9059, 9164, 9269, 9374,
+ 1151, 1152, 1153, 1154, 9479, 9584, 9689, 9794, 9899, 10004, 1782,
+ 10109, 10214, 10319, 10424, 10529, 0, 0, 0, 0, 0, 344,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 253, 254, 147, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0};
static const uint8_t elem_idxs[] = {
- 77, 79, 15, 16, 6, 25, 76, 19, 20, 21, 22, 23, 84, 17,
- 18, 43, 72, 83, 11, 12, 13, 0, 1, 2, 5, 4, 38, 50,
- 57, 7, 3, 24, 27, 37, 29, 30, 26, 31, 36, 32, 33, 34,
- 35, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 28, 51, 52,
- 53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 78, 80,
- 81, 82, 66, 67, 68, 69, 70, 71, 73, 74, 85, 75, 255, 14,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 9, 10, 255, 255, 255, 255, 255, 255, 8};
+ 77, 79, 6, 25, 76, 19, 20, 21, 22, 23, 84, 15, 16, 83, 1,
+ 2, 17, 18, 11, 12, 13, 5, 4, 38, 43, 3, 0, 50, 57, 24,
+ 37, 29, 26, 36, 30, 31, 7, 32, 33, 34, 35, 39, 40, 41, 72,
+ 42, 44, 45, 46, 47, 48, 49, 51, 27, 52, 53, 28, 54, 55, 56,
+ 58, 59, 60, 61, 62, 63, 78, 80, 81, 82, 64, 65, 66, 67, 68,
+ 69, 85, 70, 71, 73, 74, 75, 255, 255, 255, 255, 255, 14, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 9, 10, 8};
grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
if (a == -1 || b == -1) return GRPC_MDNULL;
- uint32_t k = static_cast<uint32_t>(a * 101 + b);
+ uint32_t k = (uint32_t)(a * 105 + b);
uint32_t h = elems_phash(k);
return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k &&
elem_idxs[h] != 255
@@ -384,177 +396,177 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
- {&grpc_static_metadata_refcounts[32], {{g_bytes + 452, 1}}}},
+ {&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
- {&grpc_static_metadata_refcounts[33], {{g_bytes + 453, 1}}}},
+ {&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
- {&grpc_static_metadata_refcounts[34], {{g_bytes + 454, 1}}}},
+ {&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
- {&grpc_static_metadata_refcounts[29], {{g_bytes + 430, 7}}}},
+ {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
{{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
- {&grpc_static_metadata_refcounts[36], {{g_bytes + 463, 8}}}},
+ {&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
- {&grpc_static_metadata_refcounts[37], {{g_bytes + 471, 16}}}},
+ {&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[38], {{g_bytes + 487, 4}}}},
+ {&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[39], {{g_bytes + 491, 3}}}},
+ {&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[40], {{g_bytes + 494, 3}}}},
+ {&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[41], {{g_bytes + 497, 4}}}},
+ {&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[42], {{g_bytes + 501, 5}}}},
+ {&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
- {&grpc_static_metadata_refcounts[43], {{g_bytes + 506, 4}}}},
+ {&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}}},
{{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[44], {{g_bytes + 510, 3}}}},
+ {&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
- {&grpc_static_metadata_refcounts[45], {{g_bytes + 513, 3}}}},
+ {&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
- {&grpc_static_metadata_refcounts[46], {{g_bytes + 516, 1}}}},
+ {&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
- {&grpc_static_metadata_refcounts[47], {{g_bytes + 517, 11}}}},
+ {&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[48], {{g_bytes + 528, 3}}}},
+ {&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[49], {{g_bytes + 531, 3}}}},
+ {&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[50], {{g_bytes + 534, 3}}}},
+ {&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[51], {{g_bytes + 537, 3}}}},
+ {&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
- {&grpc_static_metadata_refcounts[52], {{g_bytes + 540, 3}}}},
- {{&grpc_static_metadata_refcounts[53], {{g_bytes + 543, 14}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}}},
+ {{&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[54], {{g_bytes + 557, 13}}}},
- {{&grpc_static_metadata_refcounts[55], {{g_bytes + 570, 15}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[56], {{g_bytes + 585, 13}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[57], {{g_bytes + 598, 6}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[58], {{g_bytes + 604, 27}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[59], {{g_bytes + 631, 3}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[60], {{g_bytes + 634, 5}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[61], {{g_bytes + 639, 13}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[62], {{g_bytes + 652, 13}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[63], {{g_bytes + 665, 19}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}}},
+ {{&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
- {&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 16}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[65], {{g_bytes + 700, 14}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[66], {{g_bytes + 714, 16}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[67], {{g_bytes + 730, 13}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[68], {{g_bytes + 743, 6}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[69], {{g_bytes + 749, 4}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[70], {{g_bytes + 753, 4}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[71], {{g_bytes + 757, 6}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[72], {{g_bytes + 763, 7}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[73], {{g_bytes + 770, 4}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[74], {{g_bytes + 774, 8}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[75], {{g_bytes + 782, 17}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[76], {{g_bytes + 799, 13}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[77], {{g_bytes + 812, 8}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[78], {{g_bytes + 820, 19}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[79], {{g_bytes + 839, 13}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[80], {{g_bytes + 852, 11}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[81], {{g_bytes + 863, 4}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[82], {{g_bytes + 867, 8}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[83], {{g_bytes + 875, 12}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[84], {{g_bytes + 887, 18}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[85], {{g_bytes + 905, 19}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[86], {{g_bytes + 924, 5}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[87], {{g_bytes + 929, 7}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[88], {{g_bytes + 936, 7}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[89], {{g_bytes + 943, 11}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[90], {{g_bytes + 954, 6}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[91], {{g_bytes + 960, 10}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[92], {{g_bytes + 970, 25}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[93], {{g_bytes + 995, 17}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[94], {{g_bytes + 1012, 4}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[95], {{g_bytes + 1016, 3}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
- {{&grpc_static_metadata_refcounts[96], {{g_bytes + 1019, 16}}},
- {&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
+ {{&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
+ {&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[29], {{g_bytes + 430, 7}}}},
+ {&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[97], {{g_bytes + 1035, 16}}}},
+ {&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[98], {{g_bytes + 1051, 13}}}},
+ {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[99], {{g_bytes + 1064, 12}}}},
+ {&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
- {&grpc_static_metadata_refcounts[100], {{g_bytes + 1076, 21}}}},
+ {&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
+ {&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
+ {&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
- {&grpc_static_metadata_refcounts[98], {{g_bytes + 1051, 13}}}},
+ {&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
};
bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
true, // :path
@@ -579,6 +591,8 @@ bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
true, // user-agent
true, // host
true, // lb-token
+ true, // grpc-previous-rpc-attempts
+ true, // grpc-retry-pushback-ms
};
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index 88d9f9f52c..b3a10f5873 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -31,7 +31,7 @@
#include "src/core/lib/transport/metadata.h"
-#define GRPC_STATIC_MDSTR_COUNT 101
+#define GRPC_STATIC_MDSTR_COUNT 105
extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
/* ":path" */
#define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
@@ -78,168 +78,176 @@ extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
#define GRPC_MDSTR_HOST (grpc_static_slice_table[20])
/* "lb-token" */
#define GRPC_MDSTR_LB_TOKEN (grpc_static_slice_table[21])
+/* "grpc-previous-rpc-attempts" */
+#define GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS (grpc_static_slice_table[22])
+/* "grpc-retry-pushback-ms" */
+#define GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS (grpc_static_slice_table[23])
/* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[22])
+#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[24])
+/* "1" */
+#define GRPC_MDSTR_1 (grpc_static_slice_table[25])
+/* "2" */
+#define GRPC_MDSTR_2 (grpc_static_slice_table[26])
+/* "3" */
+#define GRPC_MDSTR_3 (grpc_static_slice_table[27])
+/* "4" */
+#define GRPC_MDSTR_4 (grpc_static_slice_table[28])
/* "" */
-#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[23])
+#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[29])
/* "grpc.wait_for_ready" */
-#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[24])
+#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[30])
/* "grpc.timeout" */
-#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[25])
+#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[31])
/* "grpc.max_request_message_bytes" */
#define GRPC_MDSTR_GRPC_DOT_MAX_REQUEST_MESSAGE_BYTES \
- (grpc_static_slice_table[26])
+ (grpc_static_slice_table[32])
/* "grpc.max_response_message_bytes" */
#define GRPC_MDSTR_GRPC_DOT_MAX_RESPONSE_MESSAGE_BYTES \
- (grpc_static_slice_table[27])
+ (grpc_static_slice_table[33])
/* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */
#define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \
- (grpc_static_slice_table[28])
+ (grpc_static_slice_table[34])
/* "deflate" */
-#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[29])
+#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[35])
/* "gzip" */
-#define GRPC_MDSTR_GZIP (grpc_static_slice_table[30])
+#define GRPC_MDSTR_GZIP (grpc_static_slice_table[36])
/* "stream/gzip" */
-#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[31])
+#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[37])
/* "0" */
-#define GRPC_MDSTR_0 (grpc_static_slice_table[32])
-/* "1" */
-#define GRPC_MDSTR_1 (grpc_static_slice_table[33])
-/* "2" */
-#define GRPC_MDSTR_2 (grpc_static_slice_table[34])
+#define GRPC_MDSTR_0 (grpc_static_slice_table[38])
/* "identity" */
-#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[35])
+#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[39])
/* "trailers" */
-#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[36])
+#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[40])
/* "application/grpc" */
-#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[37])
+#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[41])
/* "POST" */
-#define GRPC_MDSTR_POST (grpc_static_slice_table[38])
+#define GRPC_MDSTR_POST (grpc_static_slice_table[42])
/* "200" */
-#define GRPC_MDSTR_200 (grpc_static_slice_table[39])
+#define GRPC_MDSTR_200 (grpc_static_slice_table[43])
/* "404" */
-#define GRPC_MDSTR_404 (grpc_static_slice_table[40])
+#define GRPC_MDSTR_404 (grpc_static_slice_table[44])
/* "http" */
-#define GRPC_MDSTR_HTTP (grpc_static_slice_table[41])
+#define GRPC_MDSTR_HTTP (grpc_static_slice_table[45])
/* "https" */
-#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[42])
+#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[46])
/* "grpc" */
-#define GRPC_MDSTR_GRPC (grpc_static_slice_table[43])
+#define GRPC_MDSTR_GRPC (grpc_static_slice_table[47])
/* "GET" */
-#define GRPC_MDSTR_GET (grpc_static_slice_table[44])
+#define GRPC_MDSTR_GET (grpc_static_slice_table[48])
/* "PUT" */
-#define GRPC_MDSTR_PUT (grpc_static_slice_table[45])
+#define GRPC_MDSTR_PUT (grpc_static_slice_table[49])
/* "/" */
-#define GRPC_MDSTR_SLASH (grpc_static_slice_table[46])
+#define GRPC_MDSTR_SLASH (grpc_static_slice_table[50])
/* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[47])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[51])
/* "204" */
-#define GRPC_MDSTR_204 (grpc_static_slice_table[48])
+#define GRPC_MDSTR_204 (grpc_static_slice_table[52])
/* "206" */
-#define GRPC_MDSTR_206 (grpc_static_slice_table[49])
+#define GRPC_MDSTR_206 (grpc_static_slice_table[53])
/* "304" */
-#define GRPC_MDSTR_304 (grpc_static_slice_table[50])
+#define GRPC_MDSTR_304 (grpc_static_slice_table[54])
/* "400" */
-#define GRPC_MDSTR_400 (grpc_static_slice_table[51])
+#define GRPC_MDSTR_400 (grpc_static_slice_table[55])
/* "500" */
-#define GRPC_MDSTR_500 (grpc_static_slice_table[52])
+#define GRPC_MDSTR_500 (grpc_static_slice_table[56])
/* "accept-charset" */
-#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[53])
+#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[57])
/* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[54])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[58])
/* "accept-language" */
-#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[55])
+#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[59])
/* "accept-ranges" */
-#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[56])
+#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[60])
/* "accept" */
-#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[57])
+#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[61])
/* "access-control-allow-origin" */
-#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[58])
+#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[62])
/* "age" */
-#define GRPC_MDSTR_AGE (grpc_static_slice_table[59])
+#define GRPC_MDSTR_AGE (grpc_static_slice_table[63])
/* "allow" */
-#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[60])
+#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[64])
/* "authorization" */
-#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[61])
+#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[65])
/* "cache-control" */
-#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[62])
+#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[66])
/* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[63])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[67])
/* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[64])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[68])
/* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[65])
+#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[69])
/* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[66])
+#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[70])
/* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[67])
+#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[71])
/* "cookie" */
-#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[68])
+#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[72])
/* "date" */
-#define GRPC_MDSTR_DATE (grpc_static_slice_table[69])
+#define GRPC_MDSTR_DATE (grpc_static_slice_table[73])
/* "etag" */
-#define GRPC_MDSTR_ETAG (grpc_static_slice_table[70])
+#define GRPC_MDSTR_ETAG (grpc_static_slice_table[74])
/* "expect" */
-#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[71])
+#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[75])
/* "expires" */
-#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[72])
+#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[76])
/* "from" */
-#define GRPC_MDSTR_FROM (grpc_static_slice_table[73])
+#define GRPC_MDSTR_FROM (grpc_static_slice_table[77])
/* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[74])
+#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[78])
/* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[75])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[79])
/* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[76])
+#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[80])
/* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[77])
+#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[81])
/* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[78])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[82])
/* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[79])
+#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[83])
/* "lb-cost-bin" */
-#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[80])
+#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[84])
/* "link" */
-#define GRPC_MDSTR_LINK (grpc_static_slice_table[81])
+#define GRPC_MDSTR_LINK (grpc_static_slice_table[85])
/* "location" */
-#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[82])
+#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[86])
/* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[83])
+#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[87])
/* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[84])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[88])
/* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[85])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[89])
/* "range" */
-#define GRPC_MDSTR_RANGE (grpc_static_slice_table[86])
+#define GRPC_MDSTR_RANGE (grpc_static_slice_table[90])
/* "referer" */
-#define GRPC_MDSTR_REFERER (grpc_static_slice_table[87])
+#define GRPC_MDSTR_REFERER (grpc_static_slice_table[91])
/* "refresh" */
-#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[88])
+#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[92])
/* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[89])
+#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[93])
/* "server" */
-#define GRPC_MDSTR_SERVER (grpc_static_slice_table[90])
+#define GRPC_MDSTR_SERVER (grpc_static_slice_table[94])
/* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[91])
+#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[95])
/* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[92])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[96])
/* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[93])
+#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[97])
/* "vary" */
-#define GRPC_MDSTR_VARY (grpc_static_slice_table[94])
+#define GRPC_MDSTR_VARY (grpc_static_slice_table[98])
/* "via" */
-#define GRPC_MDSTR_VIA (grpc_static_slice_table[95])
+#define GRPC_MDSTR_VIA (grpc_static_slice_table[99])
/* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[96])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[100])
/* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[97])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[101])
/* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[98])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[102])
/* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[99])
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[103])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
- (grpc_static_slice_table[100])
+ (grpc_static_slice_table[104])
extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;
extern grpc_slice_refcount
@@ -537,6 +545,8 @@ typedef enum {
GRPC_BATCH_USER_AGENT,
GRPC_BATCH_HOST,
GRPC_BATCH_LB_TOKEN,
+ GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS,
+ GRPC_BATCH_GRPC_RETRY_PUSHBACK_MS,
GRPC_BATCH_CALLOUTS_COUNT
} grpc_metadata_batch_callouts_index;
@@ -565,6 +575,8 @@ typedef union {
struct grpc_linked_mdelem* user_agent;
struct grpc_linked_mdelem* host;
struct grpc_linked_mdelem* lb_token;
+ struct grpc_linked_mdelem* grpc_previous_rpc_attempts;
+ struct grpc_linked_mdelem* grpc_retry_pushback_ms;
} named;
} grpc_metadata_batch_callouts;
diff --git a/src/core/lib/transport/status_metadata.cc b/src/core/lib/transport/status_metadata.cc
new file mode 100644
index 0000000000..f896053e4d
--- /dev/null
+++ b/src/core/lib/transport/status_metadata.cc
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/transport/status_metadata.h"
+
+#include "src/core/lib/slice/slice_string_helpers.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+/* we offset status by a small amount when storing it into transport metadata
+ as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
+ */
+#define STATUS_OFFSET 1
+
+static void destroy_status(void* ignored) {}
+
+grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md) {
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
+ return GRPC_STATUS_OK;
+ }
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) {
+ return GRPC_STATUS_CANCELLED;
+ }
+ if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) {
+ return GRPC_STATUS_UNKNOWN;
+ }
+ void* user_data = grpc_mdelem_get_user_data(md, destroy_status);
+ if (user_data != nullptr) {
+ return static_cast<grpc_status_code>((intptr_t)user_data - STATUS_OFFSET);
+ }
+ uint32_t status;
+ if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
+ status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
+ }
+ grpc_mdelem_set_user_data(
+ md, destroy_status, (void*)static_cast<intptr_t>(status + STATUS_OFFSET));
+ return static_cast<grpc_status_code>(status);
+}
diff --git a/src/core/lib/iomgr/timer_uv.h b/src/core/lib/transport/status_metadata.h
index 093b2d085d..aed9c7ac20 100644
--- a/src/core/lib/iomgr/timer_uv.h
+++ b/src/core/lib/transport/status_metadata.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2016 gRPC authors.
+ * Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,19 +16,15 @@
*
*/
-#ifndef GRPC_CORE_LIB_IOMGR_TIMER_UV_H
-#define GRPC_CORE_LIB_IOMGR_TIMER_UV_H
+#ifndef GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H
+#define GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H
#include <grpc/support/port_platform.h>
-#include "src/core/lib/iomgr/exec_ctx.h"
+#include <grpc/status.h>
-struct grpc_timer {
- grpc_closure* closure;
- /* This is actually a uv_timer_t*, but we want to keep platform-specific
- types out of headers */
- void* uv_timer;
- int pending;
-};
+#include "src/core/lib/transport/metadata.h"
-#endif /* GRPC_CORE_LIB_IOMGR_TIMER_UV_H */
+grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H */
diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc
index c90d16fc32..6b41e4b37e 100644
--- a/src/core/lib/transport/transport.cc
+++ b/src/core/lib/transport/transport.cc
@@ -209,7 +209,7 @@ void grpc_transport_stream_op_batch_finish_with_failure(
grpc_transport_stream_op_batch* batch, grpc_error* error,
grpc_call_combiner* call_combiner) {
if (batch->send_message) {
- grpc_byte_stream_destroy(batch->payload->send_message.send_message);
+ batch->payload->send_message.send_message.reset();
}
if (batch->recv_message) {
GRPC_CALL_COMBINER_START(
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index b279ce8c80..10e9df0f7c 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -98,6 +98,19 @@ void grpc_transport_move_one_way_stats(grpc_transport_one_way_stats* from,
void grpc_transport_move_stats(grpc_transport_stream_stats* from,
grpc_transport_stream_stats* to);
+// This struct (which is present in both grpc_transport_stream_op_batch
+// and grpc_transport_op_batch) is a convenience to allow filters or
+// transports to schedule a closure related to a particular batch without
+// having to allocate memory. The general pattern is to initialize the
+// closure with the callback arg set to the batch and extra_arg set to
+// whatever state is associated with the handler (e.g., the call element
+// or the transport stream object).
+//
+// Note that this can only be used by the current handler of a given
+// batch on the way down the stack (i.e., whichever filter or transport is
+// currently handling the batch). Once a filter or transport passes control
+// of the batch to the next handler, it cannot depend on the contents of
+// this struct anymore, because the next handler may reuse it.
typedef struct {
void* extra_arg;
grpc_closure closure;
@@ -157,6 +170,11 @@ struct grpc_transport_stream_op_batch_payload {
uint32_t send_initial_metadata_flags;
// If non-NULL, will be set by the transport to the peer string
// (a char*, which the caller takes ownership of).
+ // Note: This pointer may be used by the transport after the
+ // send_initial_metadata op is completed. It must remain valid
+ // until the call is destroyed.
+ // Note: When a transport sets this, it must free the previous
+ // value, if any.
gpr_atm* peer_string;
} send_initial_metadata;
@@ -166,15 +184,17 @@ struct grpc_transport_stream_op_batch_payload {
struct {
// The transport (or a filter that decides to return a failure before
- // the op gets down to the transport) is responsible for calling
- // grpc_byte_stream_destroy() on this.
+ // the op gets down to the transport) takes ownership.
// The batch's on_complete will not be called until after the byte
- // stream is destroyed.
- grpc_byte_stream* send_message;
+ // stream is orphaned.
+ grpc_core::OrphanablePtr<grpc_core::ByteStream> send_message;
} send_message;
struct {
grpc_metadata_batch* recv_initial_metadata;
+ // Flags are used only on the server side. If non-null, will be set to
+ // a bitfield of the GRPC_INITIAL_METADATA_xxx macros (e.g., to
+ // indicate if the call is idempotent).
uint32_t* recv_flags;
/** Should be enqueued when initial metadata is ready to be processed. */
grpc_closure* recv_initial_metadata_ready;
@@ -184,15 +204,19 @@ struct grpc_transport_stream_op_batch_payload {
bool* trailing_metadata_available;
// If non-NULL, will be set by the transport to the peer string
// (a char*, which the caller takes ownership of).
+ // Note: This pointer may be used by the transport after the
+ // recv_initial_metadata op is completed. It must remain valid
+ // until the call is destroyed.
+ // Note: When a transport sets this, it must free the previous
+ // value, if any.
gpr_atm* peer_string;
} recv_initial_metadata;
struct {
// Will be set by the transport to point to the byte stream
// containing a received message.
- // The caller is responsible for calling grpc_byte_stream_destroy()
- // on this byte stream.
- grpc_byte_stream** recv_message;
+ // Will be NULL if trailing metadata is received instead of a message.
+ grpc_core::OrphanablePtr<grpc_core::ByteStream>* recv_message;
/** Should be enqueued when one message is ready to be processed. */
grpc_closure* recv_message_ready;
} recv_message;
diff --git a/src/core/lib/transport/transport_op_string.cc b/src/core/lib/transport/transport_op_string.cc
index 6898da17ed..99af7c1931 100644
--- a/src/core/lib/transport/transport_op_string.cc
+++ b/src/core/lib/transport/transport_op_string.cc
@@ -75,9 +75,16 @@ char* grpc_transport_stream_op_batch_string(
if (op->send_message) {
gpr_strvec_add(&b, gpr_strdup(" "));
- gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
- op->payload->send_message.send_message->flags,
- op->payload->send_message.send_message->length);
+ if (op->payload->send_message.send_message != nullptr) {
+ gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
+ op->payload->send_message.send_message->flags(),
+ op->payload->send_message.send_message->length());
+ } else {
+ // This can happen when we check a batch after the transport has
+ // processed and cleared the send_message op.
+ tmp =
+ gpr_strdup("SEND_MESSAGE(flag and length unknown, already orphaned)");
+ }
gpr_strvec_add(&b, tmp);
}