aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib')
-rw-r--r--src/core/lib/channel/channel_args.c7
-rw-r--r--src/core/lib/channel/channel_args.h2
-rw-r--r--src/core/lib/channel/channel_stack.c11
-rw-r--r--src/core/lib/channel/channel_stack.h11
-rw-r--r--src/core/lib/channel/compress_filter.c34
-rw-r--r--src/core/lib/channel/connected_channel.c8
-rw-r--r--src/core/lib/channel/deadline_filter.c44
-rw-r--r--src/core/lib/channel/deadline_filter.h6
-rw-r--r--src/core/lib/channel/http_client_filter.c170
-rw-r--r--src/core/lib/channel/http_server_filter.c140
-rw-r--r--src/core/lib/channel/message_size_filter.c29
-rw-r--r--src/core/lib/http/httpcli_security_connector.c2
-rw-r--r--src/core/lib/iomgr/ev_epoll_linux.c140
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.c2
-rw-r--r--src/core/lib/iomgr/resource_quota.c14
-rw-r--r--src/core/lib/iomgr/tcp_server_utils_posix_common.c4
-rw-r--r--src/core/lib/iomgr/timer.h3
-rw-r--r--src/core/lib/iomgr/timer_generic.c320
-rw-r--r--src/core/lib/iomgr/timer_generic.h2
-rw-r--r--src/core/lib/iomgr/timer_heap.c16
-rw-r--r--src/core/lib/iomgr/udp_server.c9
-rw-r--r--src/core/lib/security/credentials/jwt/json_token.c2
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_verifier.c4
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c38
-rw-r--r--src/core/lib/security/transport/secure_endpoint.c2
-rw-r--r--src/core/lib/security/transport/security_connector.c4
-rw-r--r--src/core/lib/security/transport/security_connector.h2
-rw-r--r--src/core/lib/security/transport/server_auth_filter.c26
-rw-r--r--src/core/lib/security/transport/tsi_error.h2
-rw-r--r--src/core/lib/slice/b64.c (renamed from src/core/lib/security/util/b64.c)27
-rw-r--r--src/core/lib/slice/b64.h (renamed from src/core/lib/security/util/b64.h)20
-rw-r--r--src/core/lib/support/time.c14
-rw-r--r--src/core/lib/surface/call.c173
-rw-r--r--src/core/lib/surface/channel.c23
-rw-r--r--src/core/lib/surface/completion_queue_factory.c77
-rw-r--r--src/core/lib/surface/completion_queue_factory.h (renamed from src/core/lib/tsi/ssl_types.h)34
-rw-r--r--src/core/lib/surface/init_secure.c2
-rw-r--r--src/core/lib/surface/lame_client.c20
-rw-r--r--src/core/lib/surface/server.c44
-rw-r--r--src/core/lib/transport/bdp_estimator.h2
-rw-r--r--src/core/lib/transport/transport.c34
-rw-r--r--src/core/lib/transport/transport.h121
-rw-r--r--src/core/lib/transport/transport_impl.h3
-rw-r--r--src/core/lib/transport/transport_op_string.c34
-rw-r--r--src/core/lib/tsi/README.md2
-rw-r--r--src/core/lib/tsi/fake_transport_security.c527
-rw-r--r--src/core/lib/tsi/fake_transport_security.h61
-rw-r--r--src/core/lib/tsi/ssl_transport_security.c1572
-rw-r--r--src/core/lib/tsi/ssl_transport_security.h191
-rw-r--r--src/core/lib/tsi/test_creds/BUILD36
-rw-r--r--src/core/lib/tsi/test_creds/README62
-rw-r--r--src/core/lib/tsi/test_creds/badclient.key16
-rw-r--r--src/core/lib/tsi/test_creds/badclient.pem17
-rw-r--r--src/core/lib/tsi/test_creds/badserver.key16
-rw-r--r--src/core/lib/tsi/test_creds/badserver.pem17
-rw-r--r--src/core/lib/tsi/test_creds/ca-openssl.cnf17
-rw-r--r--src/core/lib/tsi/test_creds/ca.key16
-rw-r--r--src/core/lib/tsi/test_creds/ca.pem15
-rw-r--r--src/core/lib/tsi/test_creds/client.key16
-rw-r--r--src/core/lib/tsi/test_creds/client.pem14
-rw-r--r--src/core/lib/tsi/test_creds/server0.key16
-rw-r--r--src/core/lib/tsi/test_creds/server0.pem14
-rw-r--r--src/core/lib/tsi/test_creds/server1-openssl.cnf26
-rw-r--r--src/core/lib/tsi/test_creds/server1.key16
-rw-r--r--src/core/lib/tsi/test_creds/server1.pem16
-rw-r--r--src/core/lib/tsi/transport_security.c266
-rw-r--r--src/core/lib/tsi/transport_security.h111
-rw-r--r--src/core/lib/tsi/transport_security_interface.h353
68 files changed, 1080 insertions, 4015 deletions
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 1a099ac437..a6d124c719 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -346,3 +346,10 @@ int grpc_channel_arg_get_integer(grpc_arg *arg, grpc_integer_options options) {
}
return arg->value.integer;
}
+
+bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args) {
+ const grpc_arg *arg = grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK);
+ if (arg == NULL) return false;
+ if (arg->type == GRPC_ARG_INTEGER && arg->value.integer == 0) return false;
+ return true;
+}
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 5c7d31f8bb..158cda5b21 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -113,6 +113,8 @@ grpc_channel_args *grpc_channel_args_set_socket_mutator(
const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args,
const char *name);
+bool grpc_channel_args_want_minimal_stack(const grpc_channel_args *args);
+
typedef struct grpc_integer_options {
int default_value; // Return this if value is outside of expected bounds.
int min_value;
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 6d53b0576e..94382980eb 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -246,9 +246,9 @@ void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
}
void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
grpc_call_element *next_elem = elem + 1;
- next_elem->filter->start_transport_stream_op(exec_ctx, next_elem, op);
+ next_elem->filter->start_transport_stream_op_batch(exec_ctx, next_elem, op);
}
char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx,
@@ -284,7 +284,8 @@ grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_error *error) {
- grpc_transport_stream_op *op = grpc_make_transport_stream_op(NULL);
- op->cancel_error = error;
- elem->filter->start_transport_stream_op(exec_ctx, elem, op);
+ grpc_transport_stream_op_batch *op = grpc_make_transport_stream_op(NULL);
+ op->cancel_stream = true;
+ op->payload->cancel_stream.cancel_error = error;
+ elem->filter->start_transport_stream_op_batch(exec_ctx, elem, op);
}
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 80e3603e8d..fdbcbdb018 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -112,9 +112,9 @@ typedef struct {
typedef struct {
/* Called to eg. send/receive data on a call.
See grpc_call_next_op on how to call the next element in the stack */
- void (*start_transport_stream_op)(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_transport_stream_op *op);
+ void (*start_transport_stream_op_batch)(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_transport_stream_op_batch *op);
/* Called to handle channel level operations - e.g. new calls, or transport
closure.
See grpc_channel_next_op on how to call the next element in the stack */
@@ -281,7 +281,7 @@ void grpc_call_stack_ignore_set_pollset_or_pollset_set(
grpc_polling_entity *pollent);
/* Call the next operation in a call stack */
void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_transport_stream_op *op);
+ grpc_transport_stream_op_batch *op);
/* Call the next operation (depending on call directionality) in a channel
stack */
void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
@@ -300,7 +300,8 @@ grpc_channel_stack *grpc_channel_stack_from_top_element(
grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
- grpc_call_element *elem, grpc_transport_stream_op *op);
+ grpc_call_element *elem,
+ grpc_transport_stream_op_batch *op);
void grpc_call_element_signal_error(grpc_exec_ctx *exec_ctx,
grpc_call_element *cur_elem,
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 790c9d27ad..1fc0104911 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -62,7 +62,7 @@ typedef struct call_data {
/** If true, contents of \a compression_algorithm are authoritative */
int has_compression_algorithm;
- grpc_transport_stream_op *send_op;
+ grpc_transport_stream_op_batch *send_op;
uint32_t send_length;
uint32_t send_flags;
grpc_slice incoming_slice;
@@ -210,7 +210,8 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
calld->send_flags);
- calld->send_op->send_message = &calld->replacement_stream.base;
+ calld->send_op->payload->send_message.send_message =
+ &calld->replacement_stream.base;
calld->post_send = calld->send_op->on_complete;
calld->send_op->on_complete = &calld->send_done;
@@ -237,9 +238,9 @@ static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
call_data *calld = elem->call_data;
- while (grpc_byte_stream_next(exec_ctx, calld->send_op->send_message,
+ while (grpc_byte_stream_next(exec_ctx, calld->send_op->payload->send_message.send_message,
~(size_t)0, &calld->got_slice)) {
- grpc_byte_stream_pull(exec_ctx, calld->send_op->send_message,
+ grpc_byte_stream_pull(exec_ctx, calld->send_op->payload->send_message.send_message,
&calld->incoming_slice);
grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
@@ -249,33 +250,34 @@ static void continue_send_message(grpc_exec_ctx *exec_ctx,
}
}
-static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+static void compress_start_transport_stream_op_batch(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ grpc_transport_stream_op_batch *op) {
call_data *calld = elem->call_data;
- GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0);
+ GPR_TIMER_BEGIN("compress_start_transport_stream_op_batch", 0);
if (op->send_initial_metadata) {
grpc_error *error = process_send_initial_metadata(
- exec_ctx, elem, op->send_initial_metadata);
+ exec_ctx, elem,
+ op->payload->send_initial_metadata.send_initial_metadata);
if (error != GRPC_ERROR_NONE) {
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
return;
}
}
- if (op->send_message != NULL &&
- !skip_compression(elem, op->send_message->flags)) {
+ if (op->send_message &&
+ !skip_compression(elem, op->payload->send_message.send_message->flags)) {
calld->send_op = op;
- calld->send_length = op->send_message->length;
- calld->send_flags = op->send_message->flags;
+ calld->send_length = op->payload->send_message.send_message->length;
+ calld->send_flags = op->payload->send_message.send_message->flags;
continue_send_message(exec_ctx, elem);
} else {
/* pass control down the stack */
grpc_call_next_op(exec_ctx, elem, op);
}
- GPR_TIMER_END("compress_start_transport_stream_op", 0);
+ GPR_TIMER_END("compress_start_transport_stream_op_batch", 0);
}
/* Constructor for call_data */
@@ -344,7 +346,7 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {}
const grpc_channel_filter grpc_compress_filter = {
- compress_start_transport_stream_op,
+ compress_start_transport_stream_op_batch,
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 75c68a5534..22caf24373 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -62,9 +62,9 @@ typedef struct connected_channel_call_data { void *unused; } call_data;
/* Intercept a call operation and either push it directly up or translate it
into transport stream operations */
-static void con_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+static void con_start_transport_stream_op_batch(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ grpc_transport_stream_op_batch *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
@@ -142,7 +142,7 @@ static void con_get_channel_info(grpc_exec_ctx *exec_ctx,
const grpc_channel_info *channel_info) {}
const grpc_channel_filter grpc_connected_filter = {
- con_start_transport_stream_op,
+ con_start_transport_stream_op_batch,
con_start_transport_op,
sizeof(call_data),
init_call_elem,
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index ca701ed457..fda099b021 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -134,7 +134,7 @@ static void on_complete(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
// Inject our own on_complete callback into op.
static void inject_on_complete_cb(grpc_deadline_state* deadline_state,
- grpc_transport_stream_op* op) {
+ grpc_transport_stream_op_batch* op) {
deadline_state->next_on_complete = op->on_complete;
grpc_closure_init(&deadline_state->on_complete, on_complete, deadline_state,
grpc_schedule_on_exec_ctx);
@@ -196,16 +196,16 @@ void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
start_timer_if_needed(exec_ctx, elem, new_deadline);
}
-void grpc_deadline_state_client_start_transport_stream_op(
+void grpc_deadline_state_client_start_transport_stream_op_batch(
grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
- grpc_transport_stream_op* op) {
+ grpc_transport_stream_op_batch* op) {
grpc_deadline_state* deadline_state = elem->call_data;
- if (op->cancel_error != GRPC_ERROR_NONE) {
+ if (op->cancel_stream) {
cancel_timer_if_needed(exec_ctx, deadline_state);
} else {
// Make sure we know when the call is complete, so that we can cancel
// the timer.
- if (op->recv_trailing_metadata != NULL) {
+ if (op->recv_trailing_metadata) {
inject_on_complete_cb(deadline_state, op);
}
}
@@ -261,10 +261,11 @@ static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
}
// Method for starting a call op for client filter.
-static void client_start_transport_stream_op(grpc_exec_ctx* exec_ctx,
- grpc_call_element* elem,
- grpc_transport_stream_op* op) {
- grpc_deadline_state_client_start_transport_stream_op(exec_ctx, elem, op);
+static void client_start_transport_stream_op_batch(
+ grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+ grpc_transport_stream_op_batch* op) {
+ grpc_deadline_state_client_start_transport_stream_op_batch(exec_ctx, elem,
+ op);
// Chain to next filter.
grpc_call_next_op(exec_ctx, elem, op);
}
@@ -282,30 +283,33 @@ static void recv_initial_metadata_ready(grpc_exec_ctx* exec_ctx, void* arg,
}
// Method for starting a call op for server filter.
-static void server_start_transport_stream_op(grpc_exec_ctx* exec_ctx,
- grpc_call_element* elem,
- grpc_transport_stream_op* op) {
+static void server_start_transport_stream_op_batch(
+ grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+ grpc_transport_stream_op_batch* op) {
server_call_data* calld = elem->call_data;
- if (op->cancel_error != GRPC_ERROR_NONE) {
+ if (op->cancel_stream) {
cancel_timer_if_needed(exec_ctx, &calld->base.deadline_state);
} else {
// If we're receiving initial metadata, we need to get the deadline
// from the recv_initial_metadata_ready callback. So we inject our
// own callback into that hook.
- if (op->recv_initial_metadata_ready != NULL) {
- calld->next_recv_initial_metadata_ready = op->recv_initial_metadata_ready;
- calld->recv_initial_metadata = op->recv_initial_metadata;
+ if (op->recv_initial_metadata) {
+ calld->next_recv_initial_metadata_ready =
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+ calld->recv_initial_metadata =
+ op->payload->recv_initial_metadata.recv_initial_metadata;
grpc_closure_init(&calld->recv_initial_metadata_ready,
recv_initial_metadata_ready, elem,
grpc_schedule_on_exec_ctx);
- op->recv_initial_metadata_ready = &calld->recv_initial_metadata_ready;
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+ &calld->recv_initial_metadata_ready;
}
// Make sure we know when the call is complete, so that we can cancel
// the timer.
// Note that we trigger this on recv_trailing_metadata, even though
// the client never sends trailing metadata, because this is the
// hook that tells us when the call is complete on the server side.
- if (op->recv_trailing_metadata != NULL) {
+ if (op->recv_trailing_metadata) {
inject_on_complete_cb(&calld->base.deadline_state, op);
}
}
@@ -314,7 +318,7 @@ static void server_start_transport_stream_op(grpc_exec_ctx* exec_ctx,
}
const grpc_channel_filter grpc_client_deadline_filter = {
- client_start_transport_stream_op,
+ client_start_transport_stream_op_batch,
grpc_channel_next_op,
sizeof(base_call_data),
init_call_elem,
@@ -329,7 +333,7 @@ const grpc_channel_filter grpc_client_deadline_filter = {
};
const grpc_channel_filter grpc_server_deadline_filter = {
- server_start_transport_stream_op,
+ server_start_transport_stream_op_batch,
grpc_channel_next_op,
sizeof(server_call_data),
init_call_elem,
diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h
index 72cd5cb929..d8db9a9f97 100644
--- a/src/core/lib/channel/deadline_filter.h
+++ b/src/core/lib/channel/deadline_filter.h
@@ -83,15 +83,15 @@ void grpc_deadline_state_start(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
void grpc_deadline_state_reset(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
gpr_timespec new_deadline);
-// To be called from the client-side filter's start_transport_stream_op()
+// To be called from the client-side filter's start_transport_stream_op_batch()
// method. Ensures that the deadline timer is cancelled when the call
// is completed.
//
// Note: It is the caller's responsibility to chain to the next filter if
// necessary after this function returns.
-void grpc_deadline_state_client_start_transport_stream_op(
+void grpc_deadline_state_client_start_transport_stream_op_batch(
grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
- grpc_transport_stream_op* op);
+ grpc_transport_stream_op_batch* op);
// Deadline filters for direct client channels and server channels.
// Note: Deadlines for non-direct client channels are handled by the
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 884fb123ca..8455e154ac 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -36,6 +36,7 @@
#include <grpc/support/string_util.h>
#include <string.h>
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/b64.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
@@ -56,14 +57,13 @@ typedef struct call_data {
grpc_linked_mdelem te_trailers;
grpc_linked_mdelem content_type;
grpc_linked_mdelem user_agent;
- grpc_linked_mdelem payload_bin;
grpc_metadata_batch *recv_initial_metadata;
grpc_metadata_batch *recv_trailing_metadata;
uint8_t *payload_bytes;
/* Vars to read data off of send_message */
- grpc_transport_stream_op send_op;
+ grpc_transport_stream_op_batch *send_op;
uint32_t send_length;
uint32_t send_flags;
grpc_slice incoming_slice;
@@ -219,9 +219,9 @@ static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
call_data *calld = elem->call_data;
uint8_t *wrptr = calld->payload_bytes;
- while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
+ while (grpc_byte_stream_next(exec_ctx, calld->send_op->payload->send_message.send_message,
~(size_t)0, &calld->got_slice)) {
- grpc_byte_stream_pull(exec_ctx, calld->send_op.send_message,
+ grpc_byte_stream_pull(exec_ctx, calld->send_op->payload->send_message.send_message,
&calld->incoming_slice);
memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice),
GRPC_SLICE_LENGTH(calld->incoming_slice));
@@ -249,10 +249,11 @@ static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
/* Pass down the original send_message op that was blocked.*/
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
calld->send_flags);
- calld->send_op.send_message = &calld->replacement_stream.base;
- calld->post_send = calld->send_op.on_complete;
- calld->send_op.on_complete = &calld->send_done;
- grpc_call_next_op(exec_ctx, elem, &calld->send_op);
+ calld->send_op->payload->send_message.send_message =
+ &calld->replacement_stream.base;
+ calld->post_send = calld->send_op->on_complete;
+ calld->send_op->on_complete = &calld->send_done;
+ grpc_call_next_op(exec_ctx, elem, calld->send_op);
} else {
continue_send_message(exec_ctx, elem);
}
@@ -260,29 +261,30 @@ static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
grpc_error *error;
- if (op->send_initial_metadata != NULL) {
+ if (op->send_initial_metadata) {
/* Decide which HTTP VERB to use. We use GET if the request is marked
cacheable, and the operation contains both initial metadata and send
message, and the payload is below the size threshold, and all the data
for this request is immediately available. */
grpc_mdelem method = GRPC_MDELEM_METHOD_POST;
- if ((op->send_initial_metadata_flags &
+ if (op->send_message &&
+ (op->payload->send_initial_metadata.send_initial_metadata_flags &
GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
- op->send_message != NULL &&
- op->send_message->length < channeld->max_payload_size_for_get) {
+ op->payload->send_message.send_message->length <
+ channeld->max_payload_size_for_get) {
method = GRPC_MDELEM_METHOD_GET;
/* The following write to calld->send_message_blocked isn't racy with
reads in hc_start_transport_op (which deals with SEND_MESSAGE ops) because
being here means ops->send_message is not NULL, which is primarily
guarding the read there. */
calld->send_message_blocked = true;
- } else if (op->send_initial_metadata_flags &
+ } else if (op->payload->send_initial_metadata.send_initial_metadata_flags &
GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
method = GRPC_MDELEM_METHOD_PUT;
}
@@ -290,28 +292,71 @@ static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
/* Attempt to read the data from send_message and create a header field. */
if (grpc_mdelem_eq(method, GRPC_MDELEM_METHOD_GET)) {
/* allocate memory to hold the entire payload */
- calld->payload_bytes = gpr_malloc(op->send_message->length);
+ calld->payload_bytes =
+ gpr_malloc(op->payload->send_message.send_message->length);
/* read slices of send_message and copy into payload_bytes */
- calld->send_op = *op;
- calld->send_length = op->send_message->length;
- calld->send_flags = op->send_message->flags;
+ calld->send_op = op;
+ calld->send_length = op->payload->send_message.send_message->length;
+ calld->send_flags = op->payload->send_message.send_message->flags;
continue_send_message(exec_ctx, elem);
if (calld->send_message_blocked == false) {
- /* when all the send_message data is available, then create a MDELEM and
- append to headers */
- grpc_mdelem payload_bin = grpc_mdelem_from_slices(
- exec_ctx, GRPC_MDSTR_GRPC_PAYLOAD_BIN,
- grpc_slice_from_copied_buffer((const char *)calld->payload_bytes,
- op->send_message->length));
- error =
- grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
- &calld->payload_bin, payload_bin);
+ /* when all the send_message data is available, then modify the path
+ * MDELEM by appending base64 encoded query to the path */
+ const int k_url_safe = 1;
+ const int k_multi_line = 0;
+ const unsigned char k_query_separator = '?';
+
+ grpc_slice path_slice =
+ GRPC_MDVALUE(op->payload->send_initial_metadata
+ .send_initial_metadata->idx.named.path->md);
+ /* sum up individual component's lengths and allocate enough memory to
+ * hold combined path+query */
+ size_t estimated_len = GRPC_SLICE_LENGTH(path_slice);
+ estimated_len++; /* for the '?' */
+ estimated_len += grpc_base64_estimate_encoded_size(
+ op->payload->send_message.send_message->length, k_url_safe,
+ k_multi_line);
+ estimated_len += 1; /* for the trailing 0 */
+ grpc_slice path_with_query_slice = grpc_slice_malloc(estimated_len);
+
+ /* memcopy individual pieces into this slice */
+ uint8_t *write_ptr =
+ (uint8_t *)GRPC_SLICE_START_PTR(path_with_query_slice);
+ uint8_t *original_path = (uint8_t *)GRPC_SLICE_START_PTR(path_slice);
+ memcpy(write_ptr, original_path, GRPC_SLICE_LENGTH(path_slice));
+ write_ptr += GRPC_SLICE_LENGTH(path_slice);
+
+ *write_ptr = k_query_separator;
+ write_ptr++; /* for the '?' */
+
+ grpc_base64_encode_core((char *)write_ptr, calld->payload_bytes,
+ op->payload->send_message.send_message->length,
+ k_url_safe, k_multi_line);
+
+ /* remove trailing unused memory and add trailing 0 to terminate string
+ */
+ char *t = (char *)GRPC_SLICE_START_PTR(path_with_query_slice);
+ /* safe to use strlen since base64_encode will always add '\0' */
+ size_t path_length = strlen(t) + 1;
+ *(t + path_length) = '\0';
+ path_with_query_slice =
+ grpc_slice_sub(path_with_query_slice, 0, path_length);
+
+ /* substitute previous path with the new path+query */
+ grpc_mdelem mdelem_path_and_query = grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_PATH, path_with_query_slice);
+ grpc_metadata_batch *b =
+ op->payload->send_initial_metadata.send_initial_metadata;
+ error = grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
+ mdelem_path_and_query);
if (error != GRPC_ERROR_NONE) return error;
+
calld->on_complete = op->on_complete;
op->on_complete = &calld->hc_on_complete;
- op->send_message = NULL;
+ op->send_message = false;
+ grpc_slice_unref_internal(exec_ctx, path_with_query_slice);
} else {
/* Not all data is available. Fall back to POST. */
gpr_log(GPR_DEBUG,
@@ -321,47 +366,60 @@ static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
}
}
- remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_METHOD);
- remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_SCHEME);
- remove_if_present(exec_ctx, op->send_initial_metadata, GRPC_BATCH_TE);
- remove_if_present(exec_ctx, op->send_initial_metadata,
+ remove_if_present(exec_ctx,
+ op->payload->send_initial_metadata.send_initial_metadata,
+ GRPC_BATCH_METHOD);
+ remove_if_present(exec_ctx,
+ op->payload->send_initial_metadata.send_initial_metadata,
+ GRPC_BATCH_SCHEME);
+ remove_if_present(exec_ctx,
+ op->payload->send_initial_metadata.send_initial_metadata,
+ GRPC_BATCH_TE);
+ remove_if_present(exec_ctx,
+ op->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_CONTENT_TYPE);
- remove_if_present(exec_ctx, op->send_initial_metadata,
+ remove_if_present(exec_ctx,
+ op->payload->send_initial_metadata.send_initial_metadata,
GRPC_BATCH_USER_AGENT);
/* Send : prefixed headers, which have to be before any application
layer headers. */
- error = grpc_metadata_batch_add_head(exec_ctx, op->send_initial_metadata,
- &calld->method, method);
+ error = grpc_metadata_batch_add_head(
+ exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+ &calld->method, method);
if (error != GRPC_ERROR_NONE) return error;
- error =
- grpc_metadata_batch_add_head(exec_ctx, op->send_initial_metadata,
- &calld->scheme, channeld->static_scheme);
+ error = grpc_metadata_batch_add_head(
+ exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+ &calld->scheme, channeld->static_scheme);
if (error != GRPC_ERROR_NONE) return error;
- error = grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
- &calld->te_trailers,
- GRPC_MDELEM_TE_TRAILERS);
+ error = grpc_metadata_batch_add_tail(
+ exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+ &calld->te_trailers, GRPC_MDELEM_TE_TRAILERS);
if (error != GRPC_ERROR_NONE) return error;
error = grpc_metadata_batch_add_tail(
- exec_ctx, op->send_initial_metadata, &calld->content_type,
- GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
+ exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+ &calld->content_type, GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC);
if (error != GRPC_ERROR_NONE) return error;
- error = grpc_metadata_batch_add_tail(exec_ctx, op->send_initial_metadata,
- &calld->user_agent,
- GRPC_MDELEM_REF(channeld->user_agent));
+ error = grpc_metadata_batch_add_tail(
+ exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+ &calld->user_agent, GRPC_MDELEM_REF(channeld->user_agent));
if (error != GRPC_ERROR_NONE) return error;
}
- if (op->recv_initial_metadata != NULL) {
+ if (op->recv_initial_metadata) {
/* substitute our callback for the higher callback */
- calld->recv_initial_metadata = op->recv_initial_metadata;
- calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
- op->recv_initial_metadata_ready = &calld->hc_on_recv_initial_metadata;
+ calld->recv_initial_metadata =
+ op->payload->recv_initial_metadata.recv_initial_metadata;
+ calld->on_done_recv_initial_metadata =
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+ &calld->hc_on_recv_initial_metadata;
}
- if (op->recv_trailing_metadata != NULL) {
+ if (op->recv_trailing_metadata) {
/* substitute our callback for the higher callback */
- calld->recv_trailing_metadata = op->recv_trailing_metadata;
+ calld->recv_trailing_metadata =
+ op->payload->recv_trailing_metadata.recv_trailing_metadata;
calld->on_done_recv_trailing_metadata = op->on_complete;
op->on_complete = &calld->hc_on_recv_trailing_metadata;
}
@@ -371,17 +429,17 @@ static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx,
static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
GPR_TIMER_BEGIN("hc_start_transport_op", 0);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
grpc_error *error = hc_mutate_op(exec_ctx, elem, op);
if (error != GRPC_ERROR_NONE) {
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
} else {
call_data *calld = elem->call_data;
- if (op->send_message != NULL && calld->send_message_blocked) {
+ if (op->send_message && calld->send_message_blocked) {
/* Don't forward the op. send_message contains slices that aren't ready
- yet. The call will be forwarded by the op_complete of slice read call.
+ yet. The call will be forwarded by the op_complete of slice read call.
*/
} else {
grpc_call_next_op(exec_ctx, elem, op);
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index 41a325bc04..c1e49ffacc 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -37,6 +37,7 @@
#include <grpc/support/log.h>
#include <string.h>
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/b64.h"
#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
@@ -51,17 +52,16 @@ typedef struct call_data {
grpc_linked_mdelem status;
grpc_linked_mdelem content_type;
- /* did this request come with payload-bin */
- bool seen_payload_bin;
+ /* did this request come with path query containing request payload */
+ bool seen_path_with_query;
/* flag to ensure payload_bin is delivered only once */
bool payload_bin_delivered;
grpc_metadata_batch *recv_initial_metadata;
- bool *recv_idempotent_request;
- bool *recv_cacheable_request;
+ uint32_t *recv_initial_metadata_flags;
/** Closure to call when finished with the hs_on_recv hook */
grpc_closure *on_done_recv;
- /** Closure to call when we retrieve read message from the payload-bin header
+ /** Closure to call when we retrieve read message from the path URI
*/
grpc_closure *recv_message_ready;
grpc_closure *on_complete;
@@ -115,14 +115,21 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
if (b->idx.named.method != NULL) {
if (grpc_mdelem_eq(b->idx.named.method->md, GRPC_MDELEM_METHOD_POST)) {
- *calld->recv_idempotent_request = false;
- *calld->recv_cacheable_request = false;
+ *calld->recv_initial_metadata_flags &=
+ ~(GRPC_INITIAL_METADATA_CACHEABLE_REQUEST |
+ GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST);
} else if (grpc_mdelem_eq(b->idx.named.method->md,
GRPC_MDELEM_METHOD_PUT)) {
- *calld->recv_idempotent_request = true;
+ *calld->recv_initial_metadata_flags &=
+ ~GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
+ *calld->recv_initial_metadata_flags |=
+ GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
} else if (grpc_mdelem_eq(b->idx.named.method->md,
GRPC_MDELEM_METHOD_GET)) {
- *calld->recv_cacheable_request = true;
+ *calld->recv_initial_metadata_flags |=
+ GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
+ *calld->recv_initial_metadata_flags &=
+ ~GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
} else {
add_error(error_name, &error,
grpc_attach_md_to_error(
@@ -205,6 +212,44 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing header"),
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":path")));
+ } else if (*calld->recv_initial_metadata_flags &
+ GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) {
+ /* We have a cacheable request made with GET verb. The path contains the
+ * query parameter which is base64 encoded request payload. */
+ const char k_query_separator = '?';
+ grpc_slice path_slice = GRPC_MDVALUE(b->idx.named.path->md);
+ uint8_t *path_ptr = (uint8_t *)GRPC_SLICE_START_PTR(path_slice);
+ size_t path_length = GRPC_SLICE_LENGTH(path_slice);
+ /* offset of the character '?' */
+ size_t offset = 0;
+ for (offset = 0; offset < path_length && *path_ptr != k_query_separator;
+ path_ptr++, offset++)
+ ;
+ if (offset < path_length) {
+ grpc_slice query_slice =
+ grpc_slice_sub(path_slice, offset + 1, path_length);
+
+ /* substitute path metadata with just the path (not query) */
+ grpc_mdelem mdelem_path_without_query = grpc_mdelem_from_slices(
+ exec_ctx, GRPC_MDSTR_PATH, grpc_slice_sub(path_slice, 0, offset));
+
+ grpc_metadata_batch_substitute(exec_ctx, b, b->idx.named.path,
+ mdelem_path_without_query);
+
+ /* decode payload from query and add to the slice buffer to be returned */
+ const int k_url_safe = 1;
+ grpc_slice_buffer_add(
+ &calld->read_slice_buffer,
+ grpc_base64_decode(exec_ctx,
+ (const char *)GRPC_SLICE_START_PTR(query_slice),
+ k_url_safe));
+ grpc_slice_buffer_stream_init(&calld->read_stream,
+ &calld->read_slice_buffer, 0);
+ calld->seen_path_with_query = true;
+ grpc_slice_unref_internal(exec_ctx, query_slice);
+ } else {
+ gpr_log(GPR_ERROR, "GET request without QUERY");
+ }
}
if (b->idx.named.host != NULL && b->idx.named.authority == NULL) {
@@ -228,16 +273,6 @@ static grpc_error *server_filter_incoming_metadata(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_STR_KEY, grpc_slice_from_static_string(":authority")));
}
- if (b->idx.named.grpc_payload_bin != NULL) {
- calld->seen_payload_bin = true;
- grpc_slice_buffer_add(&calld->read_slice_buffer,
- grpc_slice_ref_internal(
- GRPC_MDVALUE(b->idx.named.grpc_payload_bin->md)));
- grpc_slice_buffer_stream_init(&calld->read_stream,
- &calld->read_slice_buffer, 0);
- grpc_metadata_batch_remove(exec_ctx, b, b->idx.named.grpc_payload_bin);
- }
-
return error;
}
@@ -258,8 +293,8 @@ static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *err) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- /* Call recv_message_ready if we got the payload via the header field */
- if (calld->seen_payload_bin && calld->recv_message_ready != NULL) {
+ /* Call recv_message_ready if we got the payload via the path field */
+ if (calld->seen_path_with_query && calld->recv_message_ready != NULL) {
*calld->pp_recv_message = calld->payload_bin_delivered
? NULL
: (grpc_byte_stream *)&calld->read_stream;
@@ -274,7 +309,7 @@ static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *err) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- if (calld->seen_payload_bin) {
+ if (calld->seen_path_with_query) {
/* do nothing. This is probably a GET request, and payload will be returned
in hs_on_complete callback. */
} else {
@@ -283,45 +318,53 @@ static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data,
}
static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
- if (op->send_initial_metadata != NULL) {
+ if (op->send_initial_metadata) {
grpc_error *error = GRPC_ERROR_NONE;
static const char *error_name = "Failed sending initial metadata";
- add_error(error_name, &error, grpc_metadata_batch_add_head(
- exec_ctx, op->send_initial_metadata,
- &calld->status, GRPC_MDELEM_STATUS_200));
- add_error(error_name, &error,
- grpc_metadata_batch_add_tail(
- exec_ctx, op->send_initial_metadata, &calld->content_type,
- GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC));
+ add_error(
+ error_name, &error,
+ grpc_metadata_batch_add_head(
+ exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+ &calld->status, GRPC_MDELEM_STATUS_200));
+ add_error(
+ error_name, &error,
+ grpc_metadata_batch_add_tail(
+ exec_ctx, op->payload->send_initial_metadata.send_initial_metadata,
+ &calld->content_type,
+ GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC));
add_error(error_name, &error,
- server_filter_outgoing_metadata(exec_ctx, elem,
- op->send_initial_metadata));
+ server_filter_outgoing_metadata(
+ exec_ctx, elem,
+ op->payload->send_initial_metadata.send_initial_metadata));
if (error != GRPC_ERROR_NONE) {
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
return;
}
}
if (op->recv_initial_metadata) {
/* substitute our callback for the higher callback */
- GPR_ASSERT(op->recv_idempotent_request != NULL);
- GPR_ASSERT(op->recv_cacheable_request != NULL);
- calld->recv_initial_metadata = op->recv_initial_metadata;
- calld->recv_idempotent_request = op->recv_idempotent_request;
- calld->recv_cacheable_request = op->recv_cacheable_request;
- calld->on_done_recv = op->recv_initial_metadata_ready;
- op->recv_initial_metadata_ready = &calld->hs_on_recv;
+ GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags != NULL);
+ calld->recv_initial_metadata =
+ op->payload->recv_initial_metadata.recv_initial_metadata;
+ calld->recv_initial_metadata_flags =
+ op->payload->recv_initial_metadata.recv_flags;
+ calld->on_done_recv =
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+ &calld->hs_on_recv;
}
if (op->recv_message) {
- calld->recv_message_ready = op->recv_message_ready;
- calld->pp_recv_message = op->recv_message;
- if (op->recv_message_ready) {
- op->recv_message_ready = &calld->hs_recv_message_ready;
+ calld->recv_message_ready = op->payload->recv_message.recv_message_ready;
+ calld->pp_recv_message = op->payload->recv_message.recv_message;
+ if (op->payload->recv_message.recv_message_ready) {
+ op->payload->recv_message.recv_message_ready =
+ &calld->hs_recv_message_ready;
}
if (op->on_complete) {
calld->on_complete = op->on_complete;
@@ -331,9 +374,10 @@ static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
if (op->send_trailing_metadata) {
grpc_error *error = server_filter_outgoing_metadata(
- exec_ctx, elem, op->send_trailing_metadata);
+ exec_ctx, elem,
+ op->payload->send_trailing_metadata.send_trailing_metadata);
if (error != GRPC_ERROR_NONE) {
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
return;
}
}
@@ -341,7 +385,7 @@ static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
GPR_TIMER_BEGIN("hs_start_transport_op", 0);
hs_mutate_op(exec_ctx, elem, op);
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 63136650a5..57726c8476 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -132,21 +132,23 @@ static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data,
gpr_free(message_string);
}
// Invoke the next callback.
- grpc_closure_sched(exec_ctx, calld->next_recv_message_ready, error);
+ grpc_closure_run(exec_ctx, calld->next_recv_message_ready, error);
}
// Start transport stream op.
-static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
- grpc_call_element* elem,
- grpc_transport_stream_op* op) {
+static void start_transport_stream_op_batch(
+ grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+ grpc_transport_stream_op_batch* op) {
call_data* calld = elem->call_data;
// Check max send message size.
- if (op->send_message != NULL && calld->max_send_size >= 0 &&
- op->send_message->length > (size_t)calld->max_send_size) {
+ if (op->send_message && calld->max_send_size >= 0 &&
+ op->payload->send_message.send_message->length >
+ (size_t)calld->max_send_size) {
char* message_string;
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
- op->send_message->length, calld->max_send_size);
- grpc_transport_stream_op_finish_with_failure(
+ op->payload->send_message.send_message->length,
+ calld->max_send_size);
+ grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, op,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(message_string),
GRPC_ERROR_INT_GRPC_STATUS,
@@ -155,10 +157,11 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
return;
}
// Inject callback for receiving a message.
- if (op->recv_message_ready != NULL) {
- calld->next_recv_message_ready = op->recv_message_ready;
- calld->recv_message = op->recv_message;
- op->recv_message_ready = &calld->recv_message_ready;
+ if (op->recv_message) {
+ calld->next_recv_message_ready =
+ op->payload->recv_message.recv_message_ready;
+ calld->recv_message = op->payload->recv_message.recv_message;
+ op->payload->recv_message.recv_message_ready = &calld->recv_message_ready;
}
// Chain to the next filter.
grpc_call_next_op(exec_ctx, elem, op);
@@ -253,7 +256,7 @@ static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
}
const grpc_channel_filter grpc_message_size_filter = {
- start_transport_stream_op,
+ start_transport_stream_op_batch,
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index be6a6d618a..fc338342e4 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -43,7 +43,7 @@
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
-#include "src/core/lib/tsi/ssl_transport_security.h"
+#include "src/core/tsi/ssl_transport_security.h"
typedef struct {
grpc_channel_security_connector base;
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 1924e76f13..7014b98349 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -56,6 +56,7 @@
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/wakeup_fd_posix.h"
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h"
@@ -1107,19 +1108,20 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
grpc_closure *closure) {
while (true) {
- /* Fast-path: CLOSURE_NOT_READY -> <closure>.
- The 'release' cas here matches the 'acquire' load in set_ready and
- set_shutdown ensuring that the closure (scheduled by set_ready or
- set_shutdown) happens-after the I/O event on the fd */
- if (gpr_atm_rel_cas(state, CLOSURE_NOT_READY, (gpr_atm)closure)) {
- return; /* Fast-path successful. Return */
- }
-
- /* Slowpath. The 'acquire' load matches the 'release' cas in set_ready and
- set_shutdown */
- gpr_atm curr = gpr_atm_acq_load(state);
+ gpr_atm curr = gpr_atm_no_barrier_load(state);
switch (curr) {
case CLOSURE_NOT_READY: {
+ /* CLOSURE_NOT_READY -> <closure>.
+
+ We're guaranteed by API that there's an acquire barrier before here,
+ so there's no need to double-dip and this can be a release-only.
+
+ The release itself pairs with the acquire half of a set_ready full
+ barrier. */
+ if (gpr_atm_rel_cas(state, CLOSURE_NOT_READY, (gpr_atm)closure)) {
+ return; /* Successful. Return */
+ }
+
break; /* retry */
}
@@ -1134,7 +1136,7 @@ static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
is no other code that needs to 'happen-after' this) */
if (gpr_atm_no_barrier_cas(state, CLOSURE_READY, CLOSURE_NOT_READY)) {
grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
- return; /* Slow-path successful. Return */
+ return; /* Successful. Return */
}
break; /* retry */
@@ -1165,30 +1167,19 @@ static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
static void set_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
grpc_error *shutdown_err) {
- /* Try the fast-path first (i.e expect the current value to be
- CLOSURE_NOT_READY */
- gpr_atm curr = CLOSURE_NOT_READY;
gpr_atm new_state = (gpr_atm)shutdown_err | FD_SHUTDOWN_BIT;
while (true) {
- /* The 'release' cas here matches the 'acquire' load in notify_on to ensure
- that the closure it schedules 'happens-after' the set_shutdown is called
- on the fd */
- if (gpr_atm_rel_cas(state, curr, new_state)) {
- return; /* Fast-path successful. Return */
- }
-
- /* Fallback to slowpath. This 'acquire' load matches the 'release' cas in
- notify_on and set_ready */
- curr = gpr_atm_acq_load(state);
+ gpr_atm curr = gpr_atm_no_barrier_load(state);
switch (curr) {
- case CLOSURE_READY: {
+ case CLOSURE_READY:
+ case CLOSURE_NOT_READY:
+ /* Need a full barrier here so that the initial load in notify_on
+ doesn't need a barrier */
+ if (gpr_atm_full_cas(state, curr, new_state)) {
+ return; /* early out */
+ }
break; /* retry */
- }
-
- case CLOSURE_NOT_READY: {
- break; /* retry */
- }
default: {
/* 'curr' is either a closure or the fd is already shutdown */
@@ -1199,10 +1190,11 @@ static void set_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
}
/* Fd is not shutdown. Schedule the closure and move the state to
- shutdown state. The 'release' cas here matches the 'acquire' load in
- notify_on to ensure that the closure it schedules 'happens-after'
- the set_shutdown is called on the fd */
- if (gpr_atm_rel_cas(state, curr, new_state)) {
+ shutdown state.
+ Needs an acquire to pair with setting the closure (and get a
+ happens-after on that edge), and a release to pair with anything
+ loading the shutdown state. */
+ if (gpr_atm_full_cas(state, curr, new_state)) {
grpc_closure_sched(exec_ctx, (grpc_closure *)curr,
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"FD Shutdown", &shutdown_err, 1));
@@ -1220,52 +1212,42 @@ static void set_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
}
static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state) {
- /* Try an optimistic case first (i.e assume current state is
- CLOSURE_NOT_READY).
-
- This 'release' cas matches the 'acquire' load in notify_on ensuring that
- any closure (scheduled by notify_on) 'happens-after' the return from
- epoll_pwait */
- if (gpr_atm_rel_cas(state, CLOSURE_NOT_READY, CLOSURE_READY)) {
- return; /* early out */
- }
-
- /* The 'acquire' load here matches the 'release' cas in notify_on and
- set_shutdown */
- gpr_atm curr = gpr_atm_acq_load(state);
- switch (curr) {
- case CLOSURE_READY: {
- /* Already ready. We are done here */
- break;
- }
+ while (true) {
+ gpr_atm curr = gpr_atm_no_barrier_load(state);
- case CLOSURE_NOT_READY: {
- /* The state was not CLOSURE_NOT_READY when we checked initially at the
- beginning of this function but now it is CLOSURE_NOT_READY again.
- This is only possible if the state transitioned out of
- CLOSURE_NOT_READY to either CLOSURE_READY or <some closure> and then
- back to CLOSURE_NOT_READY again (i.e after we entered this function,
- the fd became "ready" and the necessary actions were already done).
- So there is no need to make the state CLOSURE_READY now */
- break;
- }
+ switch (curr) {
+ case CLOSURE_READY: {
+ /* Already ready. We are done here */
+ return;
+ }
- default: {
- /* 'curr' is either a closure or the fd is shutdown */
- if ((curr & FD_SHUTDOWN_BIT) > 0) {
- /* The fd is shutdown. Do nothing */
- } else if (gpr_atm_no_barrier_cas(state, curr, CLOSURE_NOT_READY)) {
- /* The cas above was no-barrier since the state is being transitioned to
- CLOSURE_NOT_READY; notify_on and set_shutdown do not schedule any
- closures when transitioning out of CLOSURE_NO_READY state (i.e there
- is no other code that needs to 'happen-after' this) */
+ case CLOSURE_NOT_READY: {
+ /* No barrier required as we're transitioning to a state that does not
+ involve a closure */
+ if (gpr_atm_no_barrier_cas(state, CLOSURE_NOT_READY, CLOSURE_READY)) {
+ return; /* early out */
+ }
+ break; /* retry */
+ }
- grpc_closure_sched(exec_ctx, (grpc_closure *)curr, GRPC_ERROR_NONE);
+ default: {
+ /* 'curr' is either a closure or the fd is shutdown */
+ if ((curr & FD_SHUTDOWN_BIT) > 0) {
+ /* The fd is shutdown. Do nothing */
+ return;
+ }
+ /* Full cas: acquire pairs with this cas' release in the event of a
+ spurious set_ready; release pairs with this or the acquire in
+ notify_on (or set_shutdown) */
+ else if (gpr_atm_full_cas(state, curr, CLOSURE_NOT_READY)) {
+ grpc_closure_sched(exec_ctx, (grpc_closure *)curr, GRPC_ERROR_NONE);
+ return;
+ }
+ /* else the state changed again (only possible by either a racing
+ set_ready or set_shutdown functions. In both these cases, the closure
+ would have been scheduled for execution. So we are done here */
+ return;
}
- /* else the state changed again (only possible by either a racing
- set_ready or set_shutdown functions. In both these cases, the closure
- would have been scheduled for execution. So we are done here */
- break;
}
}
}
@@ -1486,8 +1468,9 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
return 0;
}
timeout = gpr_time_sub(deadline, now);
- return gpr_time_to_millis(gpr_time_add(
+ int millis = gpr_time_to_millis(gpr_time_add(
timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
+ return millis >= 1 ? millis : 1;
}
static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
@@ -1669,6 +1652,7 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
for (int i = 0; i < ep_rv; ++i) {
void *data_ptr = ep_ev[i].data.ptr;
if (data_ptr == &global_wakeup_fd) {
+ grpc_timer_consume_kick();
append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
err_desc);
} else if (data_ptr == &pi->workqueue_wakeup_fd) {
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index ca6e855611..d90f223362 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -52,6 +52,7 @@
#include <grpc/support/useful.h>
#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/iomgr/wakeup_fd_cv.h"
#include "src/core/lib/iomgr/wakeup_fd_posix.h"
#include "src/core/lib/profiling/timers.h"
@@ -1006,6 +1007,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
} else {
if (pfds[0].revents & POLLIN_CHECK) {
+ grpc_timer_consume_kick();
work_combine_error(&error,
grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd));
}
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
index 511ffdcdf1..8dcd80d001 100644
--- a/src/core/lib/iomgr/resource_quota.c
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -279,11 +279,17 @@ static void rq_step_sched(grpc_exec_ctx *exec_ctx,
/* update the atomically available resource estimate - use no barriers since
timeliness of delivery really doesn't matter much */
static void rq_update_estimate(grpc_resource_quota *resource_quota) {
+ gpr_atm memory_usage_estimation = MEMORY_USAGE_ESTIMATION_MAX;
+ if (resource_quota->size != 0) {
+ memory_usage_estimation =
+ GPR_CLAMP((gpr_atm)((1.0 -
+ ((double)resource_quota->free_pool) /
+ ((double)resource_quota->size)) *
+ MEMORY_USAGE_ESTIMATION_MAX),
+ 0, MEMORY_USAGE_ESTIMATION_MAX);
+ }
gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation,
- (gpr_atm)((1.0 -
- ((double)resource_quota->free_pool) /
- ((double)resource_quota->size)) *
- MEMORY_USAGE_ESTIMATION_MAX));
+ memory_usage_estimation);
}
/* returns true if all allocations are completed */
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.c b/src/core/lib/iomgr/tcp_server_utils_posix_common.c
index 283b92b0a2..af2b00b4b5 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_common.c
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.c
@@ -33,7 +33,7 @@
#include "src/core/lib/iomgr/port.h"
-#ifdef GRPC_HAVE_IFADDRS
+#ifdef GRPC_POSIX_SOCKET
#include "src/core/lib/iomgr/tcp_server_utils_posix.h"
@@ -218,4 +218,4 @@ error:
return ret;
}
-#endif /* GRPC_HAVE_IFADDRS */
+#endif /* GRPC_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
index d84a278b18..e0338f93c7 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -101,6 +101,9 @@ bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
void grpc_timer_list_init(gpr_timespec now);
void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx);
+/* Consume a kick issued by grpc_kick_poller */
+void grpc_timer_consume_kick(void);
+
/* the following must be implemented by each iomgr implementation */
void grpc_kick_poller(void);
diff --git a/src/core/lib/iomgr/timer_generic.c b/src/core/lib/iomgr/timer_generic.c
index e53c801929..d8e6068431 100644
--- a/src/core/lib/iomgr/timer_generic.c
+++ b/src/core/lib/iomgr/timer_generic.c
@@ -37,9 +37,13 @@
#include "src/core/lib/iomgr/timer.h"
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
+#include <grpc/support/tls.h>
#include <grpc/support/useful.h>
+#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/time_averaged_stats.h"
#include "src/core/lib/iomgr/timer_heap.h"
#include "src/core/lib/support/spinlock.h"
@@ -52,12 +56,15 @@
#define MIN_QUEUE_WINDOW_DURATION 0.01
#define MAX_QUEUE_WINDOW_DURATION 1
+int grpc_timer_trace = 0;
+int grpc_timer_check_trace = 0;
+
typedef struct {
gpr_mu mu;
grpc_time_averaged_stats stats;
/* All and only timers with deadlines <= this will be in the heap. */
- gpr_timespec queue_deadline_cap;
- gpr_timespec min_deadline;
+ gpr_atm queue_deadline_cap;
+ gpr_atm min_deadline;
/* Index in the g_shard_queue */
uint32_t shard_queue_index;
/* This holds all timers with deadlines < queue_deadline_cap. Timers in this
@@ -67,38 +74,92 @@ typedef struct {
grpc_timer list;
} shard_type;
-/* Protects g_shard_queue */
-static gpr_mu g_mu;
-/* Allow only one run_some_expired_timers at once */
-static gpr_spinlock g_checker_mu = GPR_SPINLOCK_STATIC_INITIALIZER;
+struct shared_mutables {
+ gpr_atm min_timer;
+ /* Allow only one run_some_expired_timers at once */
+ gpr_spinlock checker_mu;
+ bool initialized;
+ /* Protects g_shard_queue */
+ gpr_mu mu;
+} GPR_ALIGN_STRUCT(GPR_CACHELINE_SIZE);
+
+static struct shared_mutables g_shared_mutables = {
+ .checker_mu = GPR_SPINLOCK_STATIC_INITIALIZER, .initialized = false,
+};
static gpr_clock_type g_clock_type;
static shard_type g_shards[NUM_SHARDS];
-/* Protected by g_mu */
+/* Protected by g_shared_mutables.mu */
static shard_type *g_shard_queue[NUM_SHARDS];
-static bool g_initialized = false;
+static gpr_timespec g_start_time;
+
+GPR_TLS_DECL(g_last_seen_min_timer);
+
+static gpr_atm saturating_add(gpr_atm a, gpr_atm b) {
+ if (a > GPR_ATM_MAX - b) {
+ return GPR_ATM_MAX;
+ }
+ return a + b;
+}
+
+static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_atm now,
+ gpr_atm *next, grpc_error *error);
+
+static gpr_timespec dbl_to_ts(double d) {
+ gpr_timespec ts;
+ ts.tv_sec = (int64_t)d;
+ ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec));
+ ts.clock_type = GPR_TIMESPAN;
+ return ts;
+}
+
+static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
+ ts = gpr_time_sub(ts, g_start_time);
+ double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
+ (double)ts.tv_nsec / GPR_NS_PER_MS +
+ (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC;
+ if (x < 0) return 0;
+ if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+ return (gpr_atm)x;
+}
+
+static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
+ ts = gpr_time_sub(ts, g_start_time);
+ double x =
+ GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS;
+ if (x < 0) return 0;
+ if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
+ return (gpr_atm)x;
+}
-static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
- gpr_timespec *next, grpc_error *error);
+static gpr_timespec atm_to_timespec(gpr_atm x) {
+ return gpr_time_add(g_start_time, dbl_to_ts((double)x / 1000.0));
+}
-static gpr_timespec compute_min_deadline(shard_type *shard) {
+static gpr_atm compute_min_deadline(shard_type *shard) {
return grpc_timer_heap_is_empty(&shard->heap)
- ? shard->queue_deadline_cap
+ ? saturating_add(shard->queue_deadline_cap, 1)
: grpc_timer_heap_top(&shard->heap)->deadline;
}
void grpc_timer_list_init(gpr_timespec now) {
uint32_t i;
- g_initialized = true;
- gpr_mu_init(&g_mu);
+ g_shared_mutables.initialized = true;
+ gpr_mu_init(&g_shared_mutables.mu);
g_clock_type = now.clock_type;
+ g_start_time = now;
+ g_shared_mutables.min_timer = timespec_to_atm_round_down(now);
+ gpr_tls_init(&g_last_seen_min_timer);
+ gpr_tls_set(&g_last_seen_min_timer, 0);
+ grpc_register_tracer("timer", &grpc_timer_trace);
+ grpc_register_tracer("timer_check", &grpc_timer_check_trace);
for (i = 0; i < NUM_SHARDS; i++) {
shard_type *shard = &g_shards[i];
gpr_mu_init(&shard->mu);
grpc_time_averaged_stats_init(&shard->stats, 1.0 / ADD_DEADLINE_SCALE, 0.1,
0.5);
- shard->queue_deadline_cap = now;
+ shard->queue_deadline_cap = g_shared_mutables.min_timer;
shard->shard_queue_index = i;
grpc_timer_heap_init(&shard->heap);
shard->list.next = shard->list.prev = &shard->list;
@@ -110,29 +171,23 @@ void grpc_timer_list_init(gpr_timespec now) {
void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {
int i;
run_some_expired_timers(
- exec_ctx, gpr_inf_future(g_clock_type), NULL,
+ exec_ctx, GPR_ATM_MAX, NULL,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Timer list shutdown"));
for (i = 0; i < NUM_SHARDS; i++) {
shard_type *shard = &g_shards[i];
gpr_mu_destroy(&shard->mu);
grpc_timer_heap_destroy(&shard->heap);
}
- gpr_mu_destroy(&g_mu);
- g_initialized = false;
+ gpr_mu_destroy(&g_shared_mutables.mu);
+ gpr_tls_destroy(&g_last_seen_min_timer);
+ g_shared_mutables.initialized = false;
}
static double ts_to_dbl(gpr_timespec ts) {
return (double)ts.tv_sec + 1e-9 * ts.tv_nsec;
}
-static gpr_timespec dbl_to_ts(double d) {
- gpr_timespec ts;
- ts.tv_sec = (int64_t)d;
- ts.tv_nsec = (int32_t)(1e9 * (d - (double)ts.tv_sec));
- ts.clock_type = GPR_TIMESPAN;
- return ts;
-}
-
+/* returns true if the first element in the list */
static void list_join(grpc_timer *head, grpc_timer *timer) {
timer->next = head;
timer->prev = head->prev;
@@ -158,15 +213,13 @@ static void swap_adjacent_shards_in_queue(uint32_t first_shard_queue_index) {
static void note_deadline_change(shard_type *shard) {
while (shard->shard_queue_index > 0 &&
- gpr_time_cmp(
- shard->min_deadline,
- g_shard_queue[shard->shard_queue_index - 1]->min_deadline) < 0) {
+ shard->min_deadline <
+ g_shard_queue[shard->shard_queue_index - 1]->min_deadline) {
swap_adjacent_shards_in_queue(shard->shard_queue_index - 1);
}
while (shard->shard_queue_index < NUM_SHARDS - 1 &&
- gpr_time_cmp(
- shard->min_deadline,
- g_shard_queue[shard->shard_queue_index + 1]->min_deadline) > 0) {
+ shard->min_deadline >
+ g_shard_queue[shard->shard_queue_index + 1]->min_deadline) {
swap_adjacent_shards_in_queue(shard->shard_queue_index);
}
}
@@ -179,9 +232,17 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
GPR_ASSERT(deadline.clock_type == g_clock_type);
GPR_ASSERT(now.clock_type == g_clock_type);
timer->closure = closure;
- timer->deadline = deadline;
+ timer->deadline = timespec_to_atm_round_up(deadline);
+
+ if (grpc_timer_trace) {
+ gpr_log(GPR_DEBUG, "TIMER %p: SET %" PRId64 ".%09d [%" PRIdPTR
+ "] now %" PRId64 ".%09d [%" PRIdPTR "] call %p[%p]",
+ timer, deadline.tv_sec, deadline.tv_nsec, timer->deadline,
+ now.tv_sec, now.tv_nsec, timespec_to_atm_round_down(now), closure,
+ closure->cb);
+ }
- if (!g_initialized) {
+ if (!g_shared_mutables.initialized) {
timer->pending = false;
grpc_closure_sched(exec_ctx, timer->closure,
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -201,12 +262,18 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
grpc_time_averaged_stats_add_sample(&shard->stats,
ts_to_dbl(gpr_time_sub(deadline, now)));
- if (gpr_time_cmp(deadline, shard->queue_deadline_cap) < 0) {
+ if (timer->deadline < shard->queue_deadline_cap) {
is_first_timer = grpc_timer_heap_add(&shard->heap, timer);
} else {
timer->heap_index = INVALID_HEAP_INDEX;
list_join(&shard->list, timer);
}
+ if (grpc_timer_trace) {
+ gpr_log(GPR_DEBUG, " .. add to shard %d with queue_deadline_cap=%" PRIdPTR
+ " => is_first_timer=%s",
+ (int)(shard - g_shards), shard->queue_deadline_cap,
+ is_first_timer ? "true" : "false");
+ }
gpr_mu_unlock(&shard->mu);
/* Deadline may have decreased, we need to adjust the master queue. Note
@@ -221,28 +288,41 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
In that case, the timer will simply have to wait for the next
grpc_timer_check. */
if (is_first_timer) {
- gpr_mu_lock(&g_mu);
- if (gpr_time_cmp(deadline, shard->min_deadline) < 0) {
- gpr_timespec old_min_deadline = g_shard_queue[0]->min_deadline;
- shard->min_deadline = deadline;
+ gpr_mu_lock(&g_shared_mutables.mu);
+ if (grpc_timer_trace) {
+ gpr_log(GPR_DEBUG, " .. old shard min_deadline=%" PRIdPTR,
+ shard->min_deadline);
+ }
+ if (timer->deadline < shard->min_deadline) {
+ gpr_atm old_min_deadline = g_shard_queue[0]->min_deadline;
+ shard->min_deadline = timer->deadline;
note_deadline_change(shard);
- if (shard->shard_queue_index == 0 &&
- gpr_time_cmp(deadline, old_min_deadline) < 0) {
+ if (shard->shard_queue_index == 0 && timer->deadline < old_min_deadline) {
+ gpr_atm_no_barrier_store(&g_shared_mutables.min_timer, timer->deadline);
grpc_kick_poller();
}
}
- gpr_mu_unlock(&g_mu);
+ gpr_mu_unlock(&g_shared_mutables.mu);
}
}
+void grpc_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_exec_ctx *exec_ctx, grpc_timer *timer) {
- if (!g_initialized) {
+ if (!g_shared_mutables.initialized) {
/* must have already been cancelled, also the shard mutex is invalid */
return;
}
shard_type *shard = &g_shards[GPR_HASH_POINTER(timer, NUM_SHARDS)];
gpr_mu_lock(&shard->mu);
+ if (grpc_timer_trace) {
+ gpr_log(GPR_DEBUG, "TIMER %p: CANCEL pending=%s", timer,
+ timer->pending ? "true" : "false");
+ }
if (timer->pending) {
grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
timer->pending = false;
@@ -260,7 +340,7 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
for timers that fall at or under it. Returns true if the queue is no
longer empty.
REQUIRES: shard->mu locked */
-static int refill_queue(shard_type *shard, gpr_timespec now) {
+static int refill_queue(shard_type *shard, gpr_atm now) {
/* Compute the new queue window width and bound by the limits: */
double computed_deadline_delta =
grpc_time_averaged_stats_update_average(&shard->stats) *
@@ -271,12 +351,22 @@ static int refill_queue(shard_type *shard, gpr_timespec now) {
grpc_timer *timer, *next;
/* Compute the new cap and put all timers under it into the queue: */
- shard->queue_deadline_cap = gpr_time_add(
- gpr_time_max(now, shard->queue_deadline_cap), dbl_to_ts(deadline_delta));
+ shard->queue_deadline_cap =
+ saturating_add(GPR_MAX(now, shard->queue_deadline_cap),
+ (gpr_atm)(deadline_delta * 1000.0));
+
+ if (grpc_timer_check_trace) {
+ gpr_log(GPR_DEBUG, " .. shard[%d]->queue_deadline_cap --> %" PRIdPTR,
+ (int)(shard - g_shards), shard->queue_deadline_cap);
+ }
for (timer = shard->list.next; timer != &shard->list; timer = next) {
next = timer->next;
- if (gpr_time_cmp(timer->deadline, shard->queue_deadline_cap) < 0) {
+ if (timer->deadline < shard->queue_deadline_cap) {
+ if (grpc_timer_check_trace) {
+ gpr_log(GPR_DEBUG, " .. add timer with deadline %" PRIdPTR " to heap",
+ timer->deadline);
+ }
list_remove(timer);
grpc_timer_heap_add(&shard->heap, timer);
}
@@ -287,15 +377,29 @@ static int refill_queue(shard_type *shard, gpr_timespec now) {
/* This pops the next non-cancelled timer with deadline <= now from the
queue, or returns NULL if there isn't one.
REQUIRES: shard->mu locked */
-static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) {
+static grpc_timer *pop_one(shard_type *shard, gpr_atm now) {
grpc_timer *timer;
for (;;) {
+ if (grpc_timer_check_trace) {
+ gpr_log(GPR_DEBUG, " .. shard[%d]: heap_empty=%s",
+ (int)(shard - g_shards),
+ grpc_timer_heap_is_empty(&shard->heap) ? "true" : "false");
+ }
if (grpc_timer_heap_is_empty(&shard->heap)) {
- if (gpr_time_cmp(now, shard->queue_deadline_cap) < 0) return NULL;
+ if (now < shard->queue_deadline_cap) return NULL;
if (!refill_queue(shard, now)) return NULL;
}
timer = grpc_timer_heap_top(&shard->heap);
- if (gpr_time_cmp(timer->deadline, now) > 0) return NULL;
+ if (grpc_timer_check_trace) {
+ gpr_log(GPR_DEBUG,
+ " .. check top timer deadline=%" PRIdPTR " now=%" PRIdPTR,
+ timer->deadline, now);
+ }
+ if (timer->deadline > now) return NULL;
+ if (grpc_timer_trace) {
+ gpr_log(GPR_DEBUG, "TIMER %p: FIRE %" PRIdPTR "ms late", timer,
+ now - timer->deadline);
+ }
timer->pending = false;
grpc_timer_heap_pop(&shard->heap);
return timer;
@@ -304,7 +408,7 @@ static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) {
/* REQUIRES: shard->mu unlocked */
static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
- gpr_timespec now, gpr_timespec *new_min_deadline,
+ gpr_atm now, gpr_atm *new_min_deadline,
grpc_error *error) {
size_t n = 0;
grpc_timer *timer;
@@ -318,17 +422,29 @@ static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
return n;
}
-static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
- gpr_timespec *next, grpc_error *error) {
+static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_atm now,
+ gpr_atm *next, grpc_error *error) {
size_t n = 0;
- /* TODO(ctiller): verify that there are any timers (atomically) here */
+ gpr_atm min_timer = gpr_atm_no_barrier_load(&g_shared_mutables.min_timer);
+ gpr_tls_set(&g_last_seen_min_timer, min_timer);
+ if (now < min_timer) {
+ if (next != NULL) *next = GPR_MIN(*next, min_timer);
+ return 0;
+ }
- if (gpr_spinlock_trylock(&g_checker_mu)) {
- gpr_mu_lock(&g_mu);
+ if (gpr_spinlock_trylock(&g_shared_mutables.checker_mu)) {
+ gpr_mu_lock(&g_shared_mutables.mu);
- while (gpr_time_cmp(g_shard_queue[0]->min_deadline, now) < 0) {
- gpr_timespec new_min_deadline;
+ if (grpc_timer_check_trace) {
+ gpr_log(GPR_DEBUG, " .. shard[%d]->min_deadline = %" PRIdPTR,
+ (int)(g_shard_queue[0] - g_shards),
+ g_shard_queue[0]->min_deadline);
+ }
+
+ while (g_shard_queue[0]->min_deadline < now ||
+ (now != GPR_ATM_MAX && g_shard_queue[0]->min_deadline == now)) {
+ gpr_atm new_min_deadline;
/* For efficiency, we pop as many available timers as we can from the
shard. This may violate perfect timer deadline ordering, but that
@@ -336,6 +452,14 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
n +=
pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, error);
+ if (grpc_timer_check_trace) {
+ gpr_log(GPR_DEBUG, " .. popped --> %" PRIdPTR
+ ", shard[%d]->min_deadline %" PRIdPTR
+ " --> %" PRIdPTR ", now=%" PRIdPTR,
+ n, (int)(g_shard_queue[0] - g_shards),
+ g_shard_queue[0]->min_deadline, new_min_deadline, now);
+ }
+
/* An grpc_timer_init() on the shard could intervene here, adding a new
timer that is earlier than new_min_deadline. However,
grpc_timer_init() will block on the master_lock before it can call
@@ -346,23 +470,24 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
}
if (next) {
- *next = gpr_time_min(*next, g_shard_queue[0]->min_deadline);
+ *next = GPR_MIN(*next, g_shard_queue[0]->min_deadline);
}
- gpr_mu_unlock(&g_mu);
- gpr_spinlock_unlock(&g_checker_mu);
+ gpr_atm_no_barrier_store(&g_shared_mutables.min_timer,
+ g_shard_queue[0]->min_deadline);
+ gpr_mu_unlock(&g_shared_mutables.mu);
+ gpr_spinlock_unlock(&g_shared_mutables.checker_mu);
} else if (next != NULL) {
/* TODO(ctiller): this forces calling code to do an short poll, and
then retry the timer check (because this time through the timer list was
contended).
- We could reduce the cost here dramatically by keeping a count of how many
- currently active pollers got through the uncontended case above
+ We could reduce the cost here dramatically by keeping a count of how
+ many currently active pollers got through the uncontended case above
successfully, and waking up other pollers IFF that count drops to zero.
Once that count is in place, this entire else branch could disappear. */
- *next = gpr_time_min(
- *next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN)));
+ *next = GPR_MIN(*next, now + 1);
}
GRPC_ERROR_UNREF(error);
@@ -372,12 +497,71 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
gpr_timespec *next) {
+ // prelude
GPR_ASSERT(now.clock_type == g_clock_type);
- return run_some_expired_timers(
- exec_ctx, now, next,
+ gpr_atm now_atm = timespec_to_atm_round_down(now);
+
+ /* fetch from a thread-local first: this avoids contention on a globally
+ mutable cacheline in the common case */
+ gpr_atm min_timer = gpr_tls_get(&g_last_seen_min_timer);
+ if (now_atm < min_timer) {
+ if (next != NULL) {
+ *next =
+ atm_to_timespec(GPR_MIN(timespec_to_atm_round_up(*next), min_timer));
+ }
+ if (grpc_timer_check_trace) {
+ gpr_log(GPR_DEBUG,
+ "TIMER CHECK SKIP: now_atm=%" PRIdPTR " min_timer=%" PRIdPTR,
+ now_atm, min_timer);
+ }
+ return 0;
+ }
+
+ grpc_error *shutdown_error =
gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0
? GRPC_ERROR_NONE
- : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system"));
+ : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system");
+
+ // tracing
+ if (grpc_timer_check_trace) {
+ char *next_str;
+ if (next == NULL) {
+ next_str = gpr_strdup("NULL");
+ } else {
+ gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec,
+ next->tv_nsec, timespec_to_atm_round_down(*next));
+ }
+ gpr_log(GPR_DEBUG, "TIMER CHECK BEGIN: now=%" PRId64 ".%09d [%" PRIdPTR
+ "] next=%s tls_min=%" PRIdPTR " glob_min=%" PRIdPTR,
+ now.tv_sec, now.tv_nsec, now_atm, next_str,
+ gpr_tls_get(&g_last_seen_min_timer),
+ gpr_atm_no_barrier_load(&g_shared_mutables.min_timer));
+ gpr_free(next_str);
+ }
+ // actual code
+ bool r;
+ gpr_atm next_atm;
+ if (next == NULL) {
+ r = run_some_expired_timers(exec_ctx, now_atm, NULL, shutdown_error);
+ } else {
+ next_atm = timespec_to_atm_round_down(*next);
+ r = run_some_expired_timers(exec_ctx, now_atm, &next_atm, shutdown_error);
+ *next = atm_to_timespec(next_atm);
+ }
+ // tracing
+ if (grpc_timer_check_trace) {
+ char *next_str;
+ if (next == NULL) {
+ next_str = gpr_strdup("NULL");
+ } else {
+ gpr_asprintf(&next_str, "%" PRId64 ".%09d [%" PRIdPTR "]", next->tv_sec,
+ next->tv_nsec, next_atm);
+ }
+ gpr_log(GPR_DEBUG, "TIMER CHECK END: %d timers triggered; next=%s", r,
+ next_str);
+ gpr_free(next_str);
+ }
+ return r > 0;
}
#endif /* GRPC_TIMER_USE_GENERIC */
diff --git a/src/core/lib/iomgr/timer_generic.h b/src/core/lib/iomgr/timer_generic.h
index 1608dce9fb..c79a431aa0 100644
--- a/src/core/lib/iomgr/timer_generic.h
+++ b/src/core/lib/iomgr/timer_generic.h
@@ -38,7 +38,7 @@
#include "src/core/lib/iomgr/exec_ctx.h"
struct grpc_timer {
- gpr_timespec deadline;
+ gpr_atm deadline;
uint32_t heap_index; /* INVALID_HEAP_INDEX if not in heap */
bool pending;
struct grpc_timer *next;
diff --git a/src/core/lib/iomgr/timer_heap.c b/src/core/lib/iomgr/timer_heap.c
index f736d335e6..03ccfe023a 100644
--- a/src/core/lib/iomgr/timer_heap.c
+++ b/src/core/lib/iomgr/timer_heap.c
@@ -50,7 +50,7 @@
static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) {
while (i > 0) {
uint32_t parent = (uint32_t)(((int)i - 1) / 2);
- if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break;
+ if (first[parent]->deadline <= t->deadline) break;
first[i] = first[parent];
first[i]->heap_index = i;
i = parent;
@@ -68,12 +68,12 @@ static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length,
uint32_t left_child = 1u + 2u * i;
if (left_child >= length) break;
uint32_t right_child = left_child + 1;
- uint32_t next_i = right_child < length &&
- gpr_time_cmp(first[left_child]->deadline,
- first[right_child]->deadline) > 0
- ? right_child
- : left_child;
- if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break;
+ uint32_t next_i =
+ right_child < length &&
+ first[left_child]->deadline > first[right_child]->deadline
+ ? right_child
+ : left_child;
+ if (t->deadline <= first[next_i]->deadline) break;
first[i] = first[next_i];
first[i]->heap_index = i;
i = next_i;
@@ -97,7 +97,7 @@ static void maybe_shrink(grpc_timer_heap *heap) {
static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) {
uint32_t i = timer->heap_index;
uint32_t parent = (uint32_t)(((int)i - 1) / 2);
- if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) {
+ if (heap->timers[parent]->deadline > timer->deadline) {
adjust_upwards(heap->timers, i, timer);
} else {
adjust_downwards(heap->timers, i, heap->timer_count, timer);
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index 86ec8f667d..60579e18ba 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -186,10 +186,7 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
/* delete ALL the things */
gpr_mu_lock(&s->mu);
- if (!s->shutdown) {
- gpr_mu_unlock(&s->mu);
- return;
- }
+ GPR_ASSERT(s->shutdown);
if (s->head) {
grpc_udp_listener *sp;
@@ -321,7 +318,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
gpr_mu_lock(&sp->server->mu);
if (error != GRPC_ERROR_NONE) {
- if (0 == --sp->server->active_ports) {
+ if (0 == --sp->server->active_ports && sp->server->shutdown) {
gpr_mu_unlock(&sp->server->mu);
deactivated_all_ports(exec_ctx, sp->server);
} else {
@@ -344,7 +341,7 @@ static void on_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
gpr_mu_lock(&(sp->server->mu));
if (error != GRPC_ERROR_NONE) {
- if (0 == --sp->server->active_ports) {
+ if (0 == --sp->server->active_ports && sp->server->shutdown) {
gpr_mu_unlock(&sp->server->mu);
deactivated_all_ports(exec_ctx, sp->server);
} else {
diff --git a/src/core/lib/security/credentials/jwt/json_token.c b/src/core/lib/security/credentials/jwt/json_token.c
index 192a5f47ed..aa905725fc 100644
--- a/src/core/lib/security/credentials/jwt/json_token.c
+++ b/src/core/lib/security/credentials/jwt/json_token.c
@@ -40,8 +40,8 @@
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
-#include "src/core/lib/security/util/b64.h"
#include "src/core/lib/security/util/json_util.h"
+#include "src/core/lib/slice/b64.h"
#include "src/core/lib/support/string.h"
#include <openssl/bio.h>
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c
index 5c59cf0f4a..0e2a264371 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.c
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c
@@ -45,10 +45,10 @@
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/iomgr/polling_entity.h"
-#include "src/core/lib/security/util/b64.h"
+#include "src/core/lib/slice/b64.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
-#include "src/core/lib/tsi/ssl_types.h"
+#include "src/core/tsi/ssl_types.h"
/* --- Utils. --- */
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index 8f321b9911..f526653ffa 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -64,7 +64,7 @@ typedef struct {
pollset_set so that work can progress when this call wants work to progress
*/
grpc_polling_entity *pollent;
- grpc_transport_stream_op op;
+ grpc_transport_stream_op_batch op;
uint8_t security_context_set;
grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
grpc_auth_metadata_context auth_md_context;
@@ -108,7 +108,7 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
const char *error_details) {
grpc_call_element *elem = (grpc_call_element *)user_data;
call_data *calld = elem->call_data;
- grpc_transport_stream_op *op = &calld->op;
+ grpc_transport_stream_op_batch *op = &calld->op;
grpc_metadata_batch *mdb;
size_t i;
reset_auth_metadata_context(&calld->auth_md_context);
@@ -122,8 +122,8 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED);
} else {
GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT);
- GPR_ASSERT(op->send_initial_metadata != NULL);
- mdb = op->send_initial_metadata;
+ GPR_ASSERT(op->send_initial_metadata);
+ mdb = op->payload->send_initial_metadata.send_initial_metadata;
for (i = 0; i < num_md; i++) {
add_error(&error,
grpc_metadata_batch_add_tail(
@@ -136,7 +136,7 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
if (error == GRPC_ERROR_NONE) {
grpc_call_next_op(exec_ctx, elem, op);
} else {
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+ grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
}
}
@@ -172,11 +172,13 @@ void build_auth_metadata_context(grpc_security_connector *sc,
static void send_security_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_client_security_context *ctx =
- (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value;
+ (grpc_client_security_context *)op->payload
+ ->context[GRPC_CONTEXT_SECURITY]
+ .value;
grpc_call_credentials *channel_call_creds =
chand->security_connector->request_metadata_creds;
int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL);
@@ -191,7 +193,7 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx,
calld->creds = grpc_composite_call_credentials_create(channel_call_creds,
ctx->creds, NULL);
if (calld->creds == NULL) {
- grpc_transport_stream_op_finish_with_failure(
+ grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, op,
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@@ -242,7 +244,7 @@ static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
that is being sent or received. */
static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
GPR_TIMER_BEGIN("auth_start_transport_op", 0);
/* grab pointers to our data from the call element */
@@ -251,23 +253,25 @@ static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_linked_mdelem *l;
grpc_client_security_context *sec_ctx = NULL;
- if (calld->security_context_set == 0 && op->cancel_error == GRPC_ERROR_NONE) {
+ if (calld->security_context_set == 0 && !op->cancel_stream) {
calld->security_context_set = 1;
- GPR_ASSERT(op->context);
- if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
- op->context[GRPC_CONTEXT_SECURITY].value =
+ GPR_ASSERT(op->payload->context != NULL);
+ if (op->payload->context[GRPC_CONTEXT_SECURITY].value == NULL) {
+ op->payload->context[GRPC_CONTEXT_SECURITY].value =
grpc_client_security_context_create();
- op->context[GRPC_CONTEXT_SECURITY].destroy =
+ op->payload->context[GRPC_CONTEXT_SECURITY].destroy =
grpc_client_security_context_destroy;
}
- sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
+ sec_ctx = op->payload->context[GRPC_CONTEXT_SECURITY].value;
GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
sec_ctx->auth_context =
GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
}
- if (op->send_initial_metadata != NULL) {
- for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
+ if (op->send_initial_metadata) {
+ for (l = op->payload->send_initial_metadata.send_initial_metadata->list
+ .head;
+ l != NULL; l = l->next) {
grpc_mdelem md = l->md;
/* Pointer comparison is OK for md_elems created from the same context.
*/
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index 568d70fa38..24da949e48 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -49,7 +49,7 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
-#include "src/core/lib/tsi/transport_security_interface.h"
+#include "src/core/tsi/transport_security_interface.h"
#define STAGING_BUFFER_SIZE 8192
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index b0cbc83639..2b51706161 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -54,8 +54,8 @@
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
-#include "src/core/lib/tsi/fake_transport_security.h"
-#include "src/core/lib/tsi/ssl_transport_security.h"
+#include "src/core/tsi/fake_transport_security.h"
+#include "src/core/tsi/ssl_transport_security.h"
/* -- Constants. -- */
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index 3df2fecd39..cf56cb3183 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -39,7 +39,7 @@
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/tcp_server.h"
-#include "src/core/lib/tsi/transport_security_interface.h"
+#include "src/core/tsi/transport_security_interface.h"
/* --- status enum. --- */
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index 3cf0632220..1aca76f9e8 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -49,7 +49,7 @@ typedef struct call_data {
up-call on transport_op, and remember to call our on_done_recv member after
handling it. */
grpc_closure auth_on_recv;
- grpc_transport_stream_op *transport_op;
+ grpc_transport_stream_op_batch *transport_op;
grpc_metadata_array md;
const grpc_metadata *consumed_md;
size_t num_consumed_md;
@@ -138,12 +138,11 @@ static void on_md_processing_done(
error_details = error_details != NULL
? error_details
: "Authentication metadata processing failed.";
- calld->transport_op->send_initial_metadata = NULL;
- if (calld->transport_op->send_message != NULL) {
- grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message);
- calld->transport_op->send_message = NULL;
+ if (calld->transport_op->send_message) {
+ grpc_byte_stream_destroy(
+ &exec_ctx, calld->transport_op->payload->send_message.send_message);
+ calld->transport_op->payload->send_message.send_message = NULL;
}
- calld->transport_op->send_trailing_metadata = NULL;
grpc_closure_sched(
&exec_ctx, calld->on_done_recv,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_details),
@@ -171,14 +170,17 @@ static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
}
static void set_recv_ops_md_callbacks(grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
call_data *calld = elem->call_data;
- if (op->recv_initial_metadata != NULL) {
+ if (op->recv_initial_metadata) {
/* substitute our callback for the higher callback */
- calld->recv_initial_metadata = op->recv_initial_metadata;
- calld->on_done_recv = op->recv_initial_metadata_ready;
- op->recv_initial_metadata_ready = &calld->auth_on_recv;
+ calld->recv_initial_metadata =
+ op->payload->recv_initial_metadata.recv_initial_metadata;
+ calld->on_done_recv =
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+ &calld->auth_on_recv;
calld->transport_op = op;
}
}
@@ -190,7 +192,7 @@ static void set_recv_ops_md_callbacks(grpc_call_element *elem,
that is being sent or received. */
static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
set_recv_ops_md_callbacks(elem, op);
grpc_call_next_op(exec_ctx, elem, op);
}
diff --git a/src/core/lib/security/transport/tsi_error.h b/src/core/lib/security/transport/tsi_error.h
index 636fbb89cf..b84693b5de 100644
--- a/src/core/lib/security/transport/tsi_error.h
+++ b/src/core/lib/security/transport/tsi_error.h
@@ -35,7 +35,7 @@
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H
#include "src/core/lib/iomgr/error.h"
-#include "src/core/lib/tsi/transport_security_interface.h"
+#include "src/core/tsi/transport_security_interface.h"
grpc_error *grpc_set_tsi_error_result(grpc_error *error, tsi_result result);
diff --git a/src/core/lib/security/util/b64.c b/src/core/lib/slice/b64.c
index 09c8213131..2007cc4810 100644
--- a/src/core/lib/security/util/b64.c
+++ b/src/core/lib/slice/b64.c
@@ -31,7 +31,7 @@
*
*/
-#include "src/core/lib/security/util/b64.h"
+#include "src/core/lib/slice/b64.h"
#include <stdint.h>
#include <string.h>
@@ -71,15 +71,31 @@ static const char base64_url_safe_chars[] =
char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
int multiline) {
- const unsigned char *data = vdata;
- const char *base64_chars =
- url_safe ? base64_url_safe_chars : base64_url_unsafe_chars;
+ size_t result_projected_size =
+ grpc_base64_estimate_encoded_size(data_size, url_safe, multiline);
+ char *result = gpr_malloc(result_projected_size);
+ grpc_base64_encode_core(result, vdata, data_size, url_safe, multiline);
+ return result;
+}
+
+size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe,
+ int multiline) {
size_t result_projected_size =
4 * ((data_size + 3) / 3) +
2 * (multiline ? (data_size / (3 * GRPC_BASE64_MULTILINE_NUM_BLOCKS))
: 0) +
1;
- char *result = gpr_malloc(result_projected_size);
+ return result_projected_size;
+}
+
+void grpc_base64_encode_core(char *result, const void *vdata, size_t data_size,
+ int url_safe, int multiline) {
+ const unsigned char *data = vdata;
+ const char *base64_chars =
+ url_safe ? base64_url_safe_chars : base64_url_unsafe_chars;
+ const size_t result_projected_size =
+ grpc_base64_estimate_encoded_size(data_size, url_safe, multiline);
+
char *current = result;
size_t num_blocks = 0;
size_t i = 0;
@@ -119,7 +135,6 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
GPR_ASSERT(current >= result);
GPR_ASSERT((uintptr_t)(current - result) < result_projected_size);
result[current - result] = '\0';
- return result;
}
grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64,
diff --git a/src/core/lib/security/util/b64.h b/src/core/lib/slice/b64.h
index d42a136f61..5cc821f4bf 100644
--- a/src/core/lib/security/util/b64.h
+++ b/src/core/lib/slice/b64.h
@@ -31,16 +31,28 @@
*
*/
-#ifndef GRPC_CORE_LIB_SECURITY_UTIL_B64_H
-#define GRPC_CORE_LIB_SECURITY_UTIL_B64_H
+#ifndef GRPC_CORE_LIB_SLICE_B64_H
+#define GRPC_CORE_LIB_SLICE_B64_H
#include <grpc/slice.h>
/* Encodes data using base64. It is the caller's responsability to free
- the returned char * using gpr_free. Returns NULL on NULL input. */
+ the returned char * using gpr_free. Returns NULL on NULL input.
+ TODO(makdharma) : change the flags to bool from int */
char *grpc_base64_encode(const void *data, size_t data_size, int url_safe,
int multiline);
+/* estimate the upper bound on size of base64 encoded data. The actual size
+ * is guaranteed to be less than or equal to the size returned here. */
+size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe,
+ int multiline);
+
+/* Encodes data using base64 and write it to memory pointed to by result. It is
+ * the caller's responsiblity to allocate enough memory in |result| to fit the
+ * encoded data. */
+void grpc_base64_encode_core(char *result, const void *vdata, size_t data_size,
+ int url_safe, int multiline);
+
/* Decodes data according to the base64 specification. Returns an empty
slice in case of failure. */
grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64,
@@ -50,4 +62,4 @@ grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64,
grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx *exec_ctx, const char *b64,
size_t b64_len, int url_safe);
-#endif /* GRPC_CORE_LIB_SECURITY_UTIL_B64_H */
+#endif /* GRPC_CORE_LIB_SLICE_B64_H */
diff --git a/src/core/lib/support/time.c b/src/core/lib/support/time.c
index 5a7d043aed..c5f94d46f7 100644
--- a/src/core/lib/support/time.c
+++ b/src/core/lib/support/time.c
@@ -42,7 +42,7 @@
int gpr_time_cmp(gpr_timespec a, gpr_timespec b) {
int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
GPR_ASSERT(a.clock_type == b.clock_type);
- if (cmp == 0) {
+ if (cmp == 0 && a.tv_sec != INT64_MAX && a.tv_sec != INT64_MIN) {
cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec);
}
return cmp;
@@ -244,15 +244,9 @@ gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
return t;
}
- if (t.tv_nsec == 0) {
- if (t.tv_sec == INT64_MAX) {
- t.clock_type = clock_type;
- return t;
- }
- if (t.tv_sec == INT64_MIN) {
- t.clock_type = clock_type;
- return t;
- }
+ if (t.tv_sec == INT64_MAX || t.tv_sec == INT64_MIN) {
+ t.clock_type = clock_type;
+ return t;
}
if (clock_type == GPR_TIMESPAN) {
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index c7b0b7ead3..4c1472bd4c 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -117,25 +117,32 @@ static received_status unpack_received_status(gpr_atm atm) {
typedef struct batch_control {
grpc_call *call;
- grpc_cq_completion cq_completion;
+ /* Share memory for cq_completion and notify_tag as they are never needed
+ simultaneously. Each byte used in this data structure count as six bytes
+ per call, so any savings we can make are worthwhile,
+
+ We use notify_tag to determine whether or not to send notification to the
+ completion queue. Once we've made that determination, we can reuse the
+ memory for cq_completion. */
+ union {
+ grpc_cq_completion cq_completion;
+ struct {
+ /* Any given op indicates completion by either (a) calling a closure or
+ (b) sending a notification on the call's completion queue. If
+ \a is_closure is true, \a tag indicates a closure to be invoked;
+ otherwise, \a tag indicates the tag to be used in the notification to
+ be sent to the completion queue. */
+ void *tag;
+ bool is_closure;
+ } notify_tag;
+ } completion_data;
grpc_closure finish_batch;
- void *notify_tag;
gpr_refcount steps_to_complete;
grpc_error *errors[MAX_ERRORS_PER_BATCH];
gpr_atm num_errors;
- uint8_t send_initial_metadata;
- uint8_t send_message;
- uint8_t send_final_op;
- uint8_t recv_initial_metadata;
- uint8_t recv_message;
- uint8_t recv_final_op;
- uint8_t is_notify_tag_closure;
-
- /* TODO(ctiller): now that this is inlined, figure out how much of the above
- state can be eliminated */
- grpc_transport_stream_op op;
+ grpc_transport_stream_op_batch op;
} batch_control;
struct grpc_call {
@@ -169,6 +176,7 @@ struct grpc_call {
bool has_initial_md_been_received;
batch_control active_batches[MAX_CONCURRENT_BATCHES];
+ grpc_transport_stream_op_batch_payload stream_op_payload;
/* first idx: is_receiving, second idx: is_trailing */
grpc_metadata_batch metadata_batch[2][2];
@@ -239,7 +247,7 @@ int grpc_call_error_trace = 0;
CALL_FROM_CALL_STACK(grpc_call_stack_from_top_element(top_elem))
static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
- grpc_transport_stream_op *op);
+ grpc_transport_stream_op_batch *op);
static void cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
status_source source, grpc_status_code status,
const char *description);
@@ -291,6 +299,7 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
call->is_client = args->server_transport_data == NULL;
+ call->stream_op_payload.context = call->context;
grpc_slice path = grpc_empty_slice();
if (call->is_client) {
GPR_ASSERT(args->add_initial_metadata_count <
@@ -504,9 +513,9 @@ void grpc_call_destroy(grpc_call *c) {
if (c == parent->first_child) {
parent->first_child = NULL;
}
- c->sibling_prev->sibling_next = c->sibling_next;
- c->sibling_next->sibling_prev = c->sibling_prev;
}
+ c->sibling_prev->sibling_next = c->sibling_next;
+ c->sibling_next->sibling_prev = c->sibling_prev;
gpr_mu_unlock(&parent->child_list_mu);
GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
}
@@ -535,13 +544,12 @@ grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved) {
}
static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
grpc_call_element *elem;
GPR_TIMER_BEGIN("execute_op", 0);
elem = CALL_ELEM_FROM_CALL(call, 0);
- op->context = call->context;
- elem->filter->start_transport_stream_op(exec_ctx, elem, op);
+ elem->filter->start_transport_stream_op_batch(exec_ctx, elem, op);
GPR_TIMER_END("execute_op", 0);
}
@@ -594,9 +602,10 @@ static void cancel_with_error(grpc_exec_ctx *exec_ctx, grpc_call *c,
status_source source, grpc_error *error) {
GRPC_CALL_INTERNAL_REF(c, "termination");
set_status_from_error(exec_ctx, c, source, GRPC_ERROR_REF(error));
- grpc_transport_stream_op *op = grpc_make_transport_stream_op(
+ grpc_transport_stream_op_batch *op = grpc_make_transport_stream_op(
grpc_closure_create(done_termination, c, grpc_schedule_on_exec_ctx));
- op->cancel_error = error;
+ op->cancel_stream = true;
+ op->payload->cancel_stream.cancel_error = error;
execute_op(exec_ctx, c, op);
}
@@ -625,7 +634,7 @@ static bool get_final_status_from(
void (*set_value)(grpc_status_code code, void *user_data),
void *set_value_user_data, grpc_slice *details) {
grpc_status_code code;
- grpc_slice slice;
+ grpc_slice slice = grpc_empty_slice();
grpc_error_get_status(error, call->send_deadline, &code, &slice, NULL);
if (code == GRPC_STATUS_OK && !allow_ok_status) {
return false;
@@ -1025,16 +1034,13 @@ static batch_control *allocate_batch_control(grpc_call *call,
const grpc_op *ops,
size_t num_ops) {
int slot = batch_slot_for_op(ops[0].op);
- for (size_t i = 1; i < num_ops; i++) {
- int op_slot = batch_slot_for_op(ops[i].op);
- slot = GPR_MIN(slot, op_slot);
- }
batch_control *bctl = &call->active_batches[slot];
if (bctl->call != NULL) {
return NULL;
}
memset(bctl, 0, sizeof(*bctl));
bctl->call = call;
+ bctl->op.payload = &call->stream_op_payload;
return bctl;
}
@@ -1074,20 +1080,20 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
grpc_call *call = bctl->call;
grpc_error *error = consolidate_batch_errors(bctl);
- if (bctl->send_initial_metadata) {
+ if (bctl->op.send_initial_metadata) {
grpc_metadata_batch_destroy(
exec_ctx,
&call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
}
- if (bctl->send_message) {
+ if (bctl->op.send_message) {
call->sending_message = false;
}
- if (bctl->send_final_op) {
+ if (bctl->op.send_trailing_metadata) {
grpc_metadata_batch_destroy(
exec_ctx,
&call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
}
- if (bctl->recv_final_op) {
+ if (bctl->op.recv_trailing_metadata) {
grpc_metadata_batch *md =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
recv_trailing_filter(exec_ctx, call, md);
@@ -1123,15 +1129,16 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
error = GRPC_ERROR_NONE;
}
- if (bctl->is_notify_tag_closure) {
+ if (bctl->completion_data.notify_tag.is_closure) {
/* unrefs bctl->error */
bctl->call = NULL;
- grpc_closure_run(exec_ctx, bctl->notify_tag, error);
+ grpc_closure_run(exec_ctx, bctl->completion_data.notify_tag.tag, error);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
} else {
/* unrefs bctl->error */
- grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, error,
- finish_batch_completion, bctl, &bctl->cq_completion);
+ grpc_cq_end_op(
+ exec_ctx, bctl->call->cq, bctl->completion_data.notify_tag.tag, error,
+ finish_batch_completion, bctl, &bctl->completion_data.cq_completion);
}
}
@@ -1394,11 +1401,13 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
if (bctl == NULL) {
return GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
}
- bctl->notify_tag = notify_tag;
- bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
+ bctl->completion_data.notify_tag.tag = notify_tag;
+ bctl->completion_data.notify_tag.is_closure =
+ (uint8_t)(is_notify_tag_closure != 0);
- grpc_transport_stream_op *stream_op = &bctl->op;
- memset(stream_op, 0, sizeof(*stream_op));
+ grpc_transport_stream_op_batch *stream_op = &bctl->op;
+ grpc_transport_stream_op_batch_payload *stream_op_payload =
+ &call->stream_op_payload;
stream_op->covered_by_poller = true;
/* rewrite batch ops into a transport op */
@@ -1452,8 +1461,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
- bctl->send_initial_metadata = 1;
- call->sent_initial_metadata = 1;
+ stream_op->send_initial_metadata = true;
+ call->sent_initial_metadata = true;
if (!prepare_application_metadata(
exec_ctx, call, (int)op->data.send_initial_metadata.count,
op->data.send_initial_metadata.metadata, 0, call->is_client,
@@ -1463,9 +1472,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
}
/* TODO(ctiller): just make these the same variable? */
call->metadata_batch[0][0].deadline = call->send_deadline;
- stream_op->send_initial_metadata =
+ stream_op_payload->send_initial_metadata.send_initial_metadata =
&call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
- stream_op->send_initial_metadata_flags = op->flags;
+ stream_op_payload->send_initial_metadata.send_initial_metadata_flags =
+ op->flags;
break;
case GRPC_OP_SEND_MESSAGE:
if (!are_write_flags_valid(op->flags)) {
@@ -1480,8 +1490,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- bctl->send_message = 1;
- call->sending_message = 1;
+ 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,
@@ -1493,7 +1503,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
GRPC_COMPRESS_NONE) {
call->sending_stream.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
}
- stream_op->send_message = &call->sending_stream.base;
+ stream_op_payload->send_message.send_message =
+ &call->sending_stream.base;
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
/* Flag validation: currently allow no flags */
@@ -1509,9 +1520,9 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- bctl->send_final_op = 1;
- call->sent_final_op = 1;
- stream_op->send_trailing_metadata =
+ stream_op->send_trailing_metadata = true;
+ call->sent_final_op = true;
+ stream_op_payload->send_trailing_metadata.send_trailing_metadata =
&call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
@@ -1533,8 +1544,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
- bctl->send_final_op = 1;
- call->sent_final_op = 1;
+ stream_op->send_trailing_metadata = true;
+ call->sent_final_op = true;
GPR_ASSERT(call->send_extra_metadata_count == 0);
call->send_extra_metadata_count = 1;
call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
@@ -1573,7 +1584,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
- stream_op->send_trailing_metadata =
+ stream_op_payload->send_trailing_metadata.send_trailing_metadata =
&call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
break;
case GRPC_OP_RECV_INITIAL_METADATA:
@@ -1590,16 +1601,16 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
from server.c. In that case, it's coming from accept_stream, and in
that case we're not necessarily covered by a poller. */
stream_op->covered_by_poller = call->is_client;
- call->received_initial_metadata = 1;
+ call->received_initial_metadata = true;
call->buffered_metadata[0] =
op->data.recv_initial_metadata.recv_initial_metadata;
grpc_closure_init(&call->receiving_initial_metadata_ready,
receiving_initial_metadata_ready, bctl,
grpc_schedule_on_exec_ctx);
- bctl->recv_initial_metadata = 1;
- stream_op->recv_initial_metadata =
+ stream_op->recv_initial_metadata = true;
+ stream_op_payload->recv_initial_metadata.recv_initial_metadata =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
- stream_op->recv_initial_metadata_ready =
+ stream_op_payload->recv_initial_metadata.recv_initial_metadata_ready =
&call->receiving_initial_metadata_ready;
num_completion_callbacks_needed++;
break;
@@ -1613,13 +1624,14 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- call->receiving_message = 1;
- bctl->recv_message = 1;
+ call->receiving_message = true;
+ stream_op->recv_message = true;
call->receiving_buffer = op->data.recv_message.recv_message;
- stream_op->recv_message = &call->receiving_stream;
+ stream_op_payload->recv_message.recv_message = &call->receiving_stream;
grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready,
bctl, grpc_schedule_on_exec_ctx);
- stream_op->recv_message_ready = &call->receiving_stream_ready;
+ stream_op_payload->recv_message.recv_message_ready =
+ &call->receiving_stream_ready;
num_completion_callbacks_needed++;
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
@@ -1636,16 +1648,17 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- call->requested_final_op = 1;
+ call->requested_final_op = true;
call->buffered_metadata[1] =
op->data.recv_status_on_client.trailing_metadata;
call->final_op.client.status = op->data.recv_status_on_client.status;
call->final_op.client.status_details =
op->data.recv_status_on_client.status_details;
- bctl->recv_final_op = 1;
- stream_op->recv_trailing_metadata =
+ stream_op->recv_trailing_metadata = true;
+ stream_op->collect_stats = true;
+ stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
- stream_op->collect_stats =
+ stream_op_payload->collect_stats.collect_stats =
&call->final_info.stats.transport_stream_stats;
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
@@ -1662,13 +1675,14 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- call->requested_final_op = 1;
+ call->requested_final_op = true;
call->final_op.server.cancelled =
op->data.recv_close_on_server.cancelled;
- bctl->recv_final_op = 1;
- stream_op->recv_trailing_metadata =
+ stream_op->recv_trailing_metadata = true;
+ stream_op->collect_stats = true;
+ stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
- stream_op->collect_stats =
+ stream_op_payload->collect_stats.collect_stats =
&call->final_info.stats.transport_stream_stats;
break;
}
@@ -1680,7 +1694,6 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
}
gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
- stream_op->context = call->context;
grpc_closure_init(&bctl->finish_batch, finish_batch, bctl,
grpc_schedule_on_exec_ctx);
stream_op->on_complete = &bctl->finish_batch;
@@ -1694,26 +1707,26 @@ done:
done_with_error:
/* reverse any mutations that occured */
- if (bctl->send_initial_metadata) {
- call->sent_initial_metadata = 0;
+ if (stream_op->send_initial_metadata) {
+ call->sent_initial_metadata = false;
grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][0]);
}
- if (bctl->send_message) {
- call->sending_message = 0;
+ if (stream_op->send_message) {
+ call->sending_message = false;
grpc_byte_stream_destroy(exec_ctx, &call->sending_stream.base);
}
- if (bctl->send_final_op) {
- call->sent_final_op = 0;
+ if (stream_op->send_trailing_metadata) {
+ call->sent_final_op = false;
grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][1]);
}
- if (bctl->recv_initial_metadata) {
- call->received_initial_metadata = 0;
+ if (stream_op->recv_initial_metadata) {
+ call->received_initial_metadata = false;
}
- if (bctl->recv_message) {
- call->receiving_message = 0;
+ if (stream_op->recv_message) {
+ call->receiving_message = false;
}
- if (bctl->recv_final_op) {
- call->requested_final_op = 0;
+ if (stream_op->recv_trailing_metadata) {
+ call->requested_final_op = false;
}
goto done;
}
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index d6c7aee40d..b3ba826bbc 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -150,17 +150,20 @@ grpc_channel *grpc_channel_create_with_builder(
} else if (0 == strcmp(args->args[i].key,
GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) {
channel->compression_options.default_level.is_set = true;
- GPR_ASSERT(args->args[i].value.integer >= 0 &&
- args->args[i].value.integer < GRPC_COMPRESS_LEVEL_COUNT);
channel->compression_options.default_level.level =
- (grpc_compression_level)args->args[i].value.integer;
+ (grpc_compression_level)grpc_channel_arg_get_integer(
+ &args->args[i],
+ (grpc_integer_options){GRPC_COMPRESS_LEVEL_NONE,
+ GRPC_COMPRESS_LEVEL_NONE,
+ GRPC_COMPRESS_LEVEL_COUNT - 1});
} else if (0 == strcmp(args->args[i].key,
GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) {
channel->compression_options.default_algorithm.is_set = true;
- GPR_ASSERT(args->args[i].value.integer >= 0 &&
- args->args[i].value.integer < GRPC_COMPRESS_ALGORITHMS_COUNT);
channel->compression_options.default_algorithm.algorithm =
- (grpc_compression_algorithm)args->args[i].value.integer;
+ (grpc_compression_algorithm)grpc_channel_arg_get_integer(
+ &args->args[i],
+ (grpc_integer_options){GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE,
+ GRPC_COMPRESS_ALGORITHMS_COUNT - 1});
} else if (0 ==
strcmp(args->args[i].key,
GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
@@ -194,8 +197,14 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
size_t grpc_channel_get_call_size_estimate(grpc_channel *channel) {
#define ROUND_UP_SIZE 256
+ /* We round up our current estimate to the NEXT value of ROUND_UP_SIZE.
+ This ensures:
+ 1. a consistent size allocation when our estimate is drifting slowly
+ (which is common) - which tends to help most allocators reuse memory
+ 2. a small amount of allowed growth over the estimate without hitting
+ the arena size doubling case, reducing overall memory usage */
return ((size_t)gpr_atm_no_barrier_load(&channel->call_size_estimate) +
- ROUND_UP_SIZE) &
+ 2 * ROUND_UP_SIZE) &
~(size_t)(ROUND_UP_SIZE - 1);
}
diff --git a/src/core/lib/surface/completion_queue_factory.c b/src/core/lib/surface/completion_queue_factory.c
new file mode 100644
index 0000000000..db67a5192b
--- /dev/null
+++ b/src/core/lib/surface/completion_queue_factory.c
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/surface/completion_queue_factory.h"
+#include "src/core/lib/surface/completion_queue.h"
+
+#include <grpc/support/log.h>
+
+/* TODO (sreek) - Currently this does not use the attributes arg. This will be
+ added in a future PR */
+static grpc_completion_queue* default_create(
+ const grpc_completion_queue_factory* factory,
+ const grpc_completion_queue_attributes* attributes) {
+ return grpc_completion_queue_create(NULL);
+}
+
+static grpc_completion_queue_factory_vtable default_vtable = {default_create};
+
+static const grpc_completion_queue_factory g_default_cq_factory = {
+ "Default Factory", NULL, &default_vtable};
+
+const grpc_completion_queue_factory* grpc_completion_queue_factory_lookup(
+ const grpc_completion_queue_attributes* attributes) {
+ /* As we add more fields to grpc_completion_queue_attributes, we may have to
+ change this assert to:
+ GPR_ASSERT (attributes->version >= 1 &&
+ attributes->version <= GRPC_CQ_CURRENT_VERSION) */
+ GPR_ASSERT(attributes->version == 1);
+
+ /* The default factory can handle version 1 of the attributes structure. We
+ may have to change this as more fields are added to the structure */
+ return &g_default_cq_factory;
+}
+
+grpc_completion_queue* grpc_completion_queue_create_for_next(void* reserved) {
+ GPR_ASSERT(!reserved);
+ grpc_completion_queue_attributes attr = {1, GRPC_CQ_NEXT,
+ GRPC_CQ_DEFAULT_POLLING};
+ return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr);
+}
+
+grpc_completion_queue* grpc_completion_queue_create_for_pluck(void* reserved) {
+ GPR_ASSERT(!reserved);
+ grpc_completion_queue_attributes attr = {1, GRPC_CQ_PLUCK,
+ GRPC_CQ_DEFAULT_POLLING};
+ return g_default_cq_factory.vtable->create(&g_default_cq_factory, &attr);
+}
diff --git a/src/core/lib/tsi/ssl_types.h b/src/core/lib/surface/completion_queue_factory.h
index 0a988effd0..57e90b5090 100644
--- a/src/core/lib/tsi/ssl_types.h
+++ b/src/core/lib/surface/completion_queue_factory.h
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2017, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,25 +31,21 @@
*
*/
-#ifndef GRPC_CORE_LIB_TSI_SSL_TYPES_H
-#define GRPC_CORE_LIB_TSI_SSL_TYPES_H
+#ifndef GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H
+#define GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H
-/* A collection of macros to cast between various integer types that are
- * used differently between BoringSSL and OpenSSL:
- * TSI_INT_AS_SIZE(x): convert 'int x' to a length parameter for an OpenSSL
- * function
- * TSI_SIZE_AS_SIZE(x): convert 'size_t x' to a length parameter for an OpenSSL
- * function
- */
+#include <grpc/grpc.h>
+#include "src/core/lib/surface/completion_queue.h"
-#include <openssl/ssl.h>
+typedef struct grpc_completion_queue_factory_vtable {
+ grpc_completion_queue* (*create)(const grpc_completion_queue_factory*,
+ const grpc_completion_queue_attributes*);
+} grpc_completion_queue_factory_vtable;
-#ifdef OPENSSL_IS_BORINGSSL
-#define TSI_INT_AS_SIZE(x) ((size_t)(x))
-#define TSI_SIZE_AS_SIZE(x) (x)
-#else
-#define TSI_INT_AS_SIZE(x) (x)
-#define TSI_SIZE_AS_SIZE(x) ((int)(x))
-#endif
+struct grpc_completion_queue_factory {
+ const char* name;
+ void* data; /* Factory specific data */
+ grpc_completion_queue_factory_vtable* vtable;
+};
-#endif /* GRPC_CORE_LIB_TSI_SSL_TYPES_H */
+#endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H */
diff --git a/src/core/lib/surface/init_secure.c b/src/core/lib/surface/init_secure.c
index 46b9a8f922..921ef87e36 100644
--- a/src/core/lib/surface/init_secure.c
+++ b/src/core/lib/surface/init_secure.c
@@ -43,7 +43,7 @@
#include "src/core/lib/security/transport/security_connector.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/surface/channel_init.h"
-#include "src/core/lib/tsi/transport_security_interface.h"
+#include "src/core/tsi/transport_security_interface.h"
void grpc_security_pre_init(void) {
grpc_register_tracer("secure_endpoint", &grpc_trace_secure_endpoint);
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 0c408aa288..82428c42c0 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -80,16 +80,18 @@ static void fill_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
mdb->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
}
-static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+static void lame_start_transport_stream_op_batch(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ grpc_transport_stream_op_batch *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
- if (op->recv_initial_metadata != NULL) {
- fill_metadata(exec_ctx, elem, op->recv_initial_metadata);
- } else if (op->recv_trailing_metadata != NULL) {
- fill_metadata(exec_ctx, elem, op->recv_trailing_metadata);
+ if (op->recv_initial_metadata) {
+ fill_metadata(exec_ctx, elem,
+ op->payload->recv_initial_metadata.recv_initial_metadata);
+ } else if (op->recv_trailing_metadata) {
+ fill_metadata(exec_ctx, elem,
+ op->payload->recv_trailing_metadata.recv_trailing_metadata);
}
- grpc_transport_stream_op_finish_with_failure(
+ grpc_transport_stream_op_batch_finish_with_failure(
exec_ctx, op,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("lame client channel"));
}
@@ -148,7 +150,7 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {}
const grpc_channel_filter grpc_lame_filter = {
- lame_start_transport_stream_op,
+ lame_start_transport_stream_op_batch,
lame_start_transport_op,
sizeof(call_data),
init_call_elem,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index a123c9ca43..191ee75252 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -154,8 +154,7 @@ struct call_data {
grpc_completion_queue *cq_new;
grpc_metadata_batch *recv_initial_metadata;
- bool recv_idempotent_request;
- bool recv_cacheable_request;
+ uint32_t recv_initial_metadata_flags;
grpc_metadata_array initial_metadata;
request_matcher *request_matcher;
@@ -498,13 +497,7 @@ static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
rc->data.batch.details->host = grpc_slice_ref_internal(calld->host);
rc->data.batch.details->method = grpc_slice_ref_internal(calld->path);
rc->data.batch.details->deadline = calld->deadline;
- rc->data.batch.details->flags =
- (calld->recv_idempotent_request
- ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
- : 0) |
- (calld->recv_cacheable_request
- ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST
- : 0);
+ rc->data.batch.details->flags = calld->recv_initial_metadata_flags;
break;
case REGISTERED_CALL:
*rc->data.registered.deadline = calld->deadline;
@@ -632,7 +625,8 @@ static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
if (!grpc_slice_eq(rm->host, calld->host)) continue;
if (!grpc_slice_eq(rm->method, calld->path)) continue;
if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
- !calld->recv_idempotent_request) {
+ 0 == (calld->recv_initial_metadata_flags &
+ GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) {
continue;
}
finish_start_new_rpc(exec_ctx, server, elem,
@@ -649,7 +643,8 @@ static void start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
if (rm->has_host) continue;
if (!grpc_slice_eq(rm->method, calld->path)) continue;
if ((rm->flags & GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) &&
- !calld->recv_idempotent_request) {
+ 0 == (calld->recv_initial_metadata_flags &
+ GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST)) {
continue;
}
finish_start_new_rpc(exec_ctx, server, elem,
@@ -781,22 +776,25 @@ static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
}
static void server_mutate_op(grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
call_data *calld = elem->call_data;
- if (op->recv_initial_metadata != NULL) {
- GPR_ASSERT(op->recv_idempotent_request == NULL);
- calld->recv_initial_metadata = op->recv_initial_metadata;
- calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
- op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata;
- op->recv_idempotent_request = &calld->recv_idempotent_request;
- op->recv_cacheable_request = &calld->recv_cacheable_request;
+ if (op->recv_initial_metadata) {
+ GPR_ASSERT(op->payload->recv_initial_metadata.recv_flags == NULL);
+ calld->recv_initial_metadata =
+ op->payload->recv_initial_metadata.recv_initial_metadata;
+ calld->on_done_recv_initial_metadata =
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+ &calld->server_on_recv_initial_metadata;
+ op->payload->recv_initial_metadata.recv_flags =
+ &calld->recv_initial_metadata_flags;
}
}
-static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_transport_stream_op *op) {
+static void server_start_transport_stream_op_batch(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ grpc_transport_stream_op_batch *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
server_mutate_op(elem, op);
grpc_call_next_op(exec_ctx, elem, op);
@@ -960,7 +958,7 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
}
const grpc_channel_filter grpc_server_top_filter = {
- server_start_transport_stream_op,
+ server_start_transport_stream_op_batch,
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h
index bcaf899910..df8d1f6fc0 100644
--- a/src/core/lib/transport/bdp_estimator.h
+++ b/src/core/lib/transport/bdp_estimator.h
@@ -73,4 +73,4 @@ void grpc_bdp_estimator_start_ping(grpc_bdp_estimator *estimator);
// Completes a previously started ping
void grpc_bdp_estimator_complete_ping(grpc_bdp_estimator *estimator);
-#endif
+#endif /* GRPC_CORE_LIB_TRANSPORT_BDP_ESTIMATOR_H */
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index d56cb31ee0..82c4e004b7 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -170,7 +170,7 @@ int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
grpc_stream *stream,
- grpc_transport_stream_op *op) {
+ grpc_transport_stream_op_batch *op) {
transport->vtable->perform_stream_op(exec_ctx, transport, stream, op);
}
@@ -213,14 +213,23 @@ grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx,
return transport->vtable->get_endpoint(exec_ctx, transport);
}
-void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
- grpc_transport_stream_op *op,
- grpc_error *error) {
- grpc_closure_sched(exec_ctx, op->recv_message_ready, GRPC_ERROR_REF(error));
- grpc_closure_sched(exec_ctx, op->recv_initial_metadata_ready,
- GRPC_ERROR_REF(error));
+void grpc_transport_stream_op_batch_finish_with_failure(
+ grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op,
+ grpc_error *error) {
+ if (op->recv_message) {
+ grpc_closure_sched(exec_ctx, op->payload->recv_message.recv_message_ready,
+ GRPC_ERROR_REF(error));
+ }
+ if (op->recv_initial_metadata) {
+ grpc_closure_sched(
+ exec_ctx,
+ op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+ GRPC_ERROR_REF(error));
+ }
grpc_closure_sched(exec_ctx, op->on_complete, error);
- GRPC_ERROR_UNREF(op->cancel_error);
+ if (op->cancel_stream) {
+ GRPC_ERROR_UNREF(op->payload->cancel_stream.cancel_error);
+ }
}
typedef struct {
@@ -249,7 +258,8 @@ grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) {
typedef struct {
grpc_closure outer_on_complete;
grpc_closure *inner_on_complete;
- grpc_transport_stream_op op;
+ grpc_transport_stream_op_batch op;
+ grpc_transport_stream_op_batch_payload payload;
} made_transport_stream_op;
static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg,
@@ -260,13 +270,13 @@ static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg,
grpc_closure_run(exec_ctx, c, GRPC_ERROR_REF(error));
}
-grpc_transport_stream_op *grpc_make_transport_stream_op(
+grpc_transport_stream_op_batch *grpc_make_transport_stream_op(
grpc_closure *on_complete) {
- made_transport_stream_op *op = gpr_malloc(sizeof(*op));
+ made_transport_stream_op *op = gpr_zalloc(sizeof(*op));
+ op->op.payload = &op->payload;
grpc_closure_init(&op->outer_on_complete, destroy_made_transport_stream_op,
op, grpc_schedule_on_exec_ctx);
op->inner_on_complete = on_complete;
- memset(&op->op, 0, sizeof(op->op));
op->op.on_complete = &op->outer_on_complete;
return &op->op;
}
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 950b18aeda..93369cc689 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -109,55 +109,98 @@ void grpc_transport_move_stats(grpc_transport_stream_stats *from,
grpc_transport_stream_stats *to);
typedef struct {
+ void *extra_arg;
grpc_closure closure;
- void *args[2];
-} grpc_transport_private_op_data;
+} grpc_handler_private_op_data;
+
+typedef struct grpc_transport_stream_op_batch_payload
+ grpc_transport_stream_op_batch_payload;
/* Transport stream op: a set of operations to perform on a transport
against a single stream */
-typedef struct grpc_transport_stream_op {
+typedef struct grpc_transport_stream_op_batch {
/** Should be enqueued when all requested operations (excluding recv_message
and recv_initial_metadata which have their own closures) in a given batch
have been completed. */
grpc_closure *on_complete;
+ /** Values for the stream op (fields set are determined by flags above) */
+ grpc_transport_stream_op_batch_payload *payload;
+
/** Is the completion of this op covered by a poller (if false: the op should
complete independently of some pollset being polled) */
- bool covered_by_poller;
+ bool covered_by_poller : 1;
- /** Send initial metadata to the peer, from the provided metadata batch.
- idempotent_request MUST be set if this is non-null */
- grpc_metadata_batch *send_initial_metadata;
- /** Iff send_initial_metadata != NULL, flags associated with
- send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */
- uint32_t send_initial_metadata_flags;
+ /** Send initial metadata to the peer, from the provided metadata batch. */
+ bool send_initial_metadata : 1;
/** Send trailing metadata to the peer, from the provided metadata batch. */
- grpc_metadata_batch *send_trailing_metadata;
+ bool send_trailing_metadata : 1;
/** Send message data to the peer, from the provided byte stream. */
- grpc_byte_stream *send_message;
+ bool send_message : 1;
/** Receive initial metadata from the stream, into provided metadata batch. */
- grpc_metadata_batch *recv_initial_metadata;
- bool *recv_idempotent_request;
- bool *recv_cacheable_request;
- /** Should be enqueued when initial metadata is ready to be processed. */
- grpc_closure *recv_initial_metadata_ready;
+ bool recv_initial_metadata : 1;
/** Receive message data from the stream, into provided byte stream. */
- grpc_byte_stream **recv_message;
- /** Should be enqueued when one message is ready to be processed. */
- grpc_closure *recv_message_ready;
+ bool recv_message : 1;
/** Receive trailing metadata from the stream, into provided metadata batch.
*/
- grpc_metadata_batch *recv_trailing_metadata;
+ bool recv_trailing_metadata : 1;
/** Collect any stats into provided buffer, zero internal stat counters */
- grpc_transport_stream_stats *collect_stats;
+ bool collect_stats : 1;
+
+ /** Cancel this stream with the provided error */
+ bool cancel_stream : 1;
+
+ /***************************************************************************
+ * remaining fields are initialized and used at the discretion of the
+ * current handler of the op */
- /** If != GRPC_ERROR_NONE, forcefully close this stream.
+ grpc_handler_private_op_data handler_private;
+} grpc_transport_stream_op_batch;
+
+struct grpc_transport_stream_op_batch_payload {
+ struct {
+ grpc_metadata_batch *send_initial_metadata;
+ /** Iff send_initial_metadata != NULL, flags associated with
+ send_initial_metadata: a bitfield of GRPC_INITIAL_METADATA_xxx */
+ uint32_t send_initial_metadata_flags;
+ } send_initial_metadata;
+
+ struct {
+ grpc_metadata_batch *send_trailing_metadata;
+ } send_trailing_metadata;
+
+ struct {
+ grpc_byte_stream *send_message;
+ } send_message;
+
+ struct {
+ grpc_metadata_batch *recv_initial_metadata;
+ uint32_t *recv_flags;
+ /** Should be enqueued when initial metadata is ready to be processed. */
+ grpc_closure *recv_initial_metadata_ready;
+ } recv_initial_metadata;
+
+ struct {
+ grpc_byte_stream **recv_message;
+ /** Should be enqueued when one message is ready to be processed. */
+ grpc_closure *recv_message_ready;
+ } recv_message;
+
+ struct {
+ grpc_metadata_batch *recv_trailing_metadata;
+ } recv_trailing_metadata;
+
+ struct {
+ grpc_transport_stream_stats *collect_stats;
+ } collect_stats;
+
+ /** Forcefully close this stream.
The HTTP2 semantics should be:
- server side: if cancel_error has GRPC_ERROR_INT_GRPC_STATUS, and
trailing metadata has not been sent, send trailing metadata with status
@@ -167,17 +210,13 @@ typedef struct grpc_transport_stream_op {
convert to a HTTP2 error code using
grpc_chttp2_grpc_status_to_http2_error. Send a RST_STREAM with this
error. */
- grpc_error *cancel_error;
+ struct {
+ grpc_error *cancel_error;
+ } cancel_stream;
/* Indexes correspond to grpc_context_index enum values */
grpc_call_context_element *context;
-
- /***************************************************************************
- * remaining fields are initialized and used at the discretion of the
- * current handler of the op */
-
- grpc_transport_private_op_data handler_private;
-} grpc_transport_stream_op;
+};
/** Transport op: a set of operations to perform on a transport as a whole */
typedef struct grpc_transport_op {
@@ -210,7 +249,7 @@ typedef struct grpc_transport_op {
* remaining fields are initialized and used at the discretion of the
* transport implementation */
- grpc_transport_private_op_data transport_private;
+ grpc_handler_private_op_data handler_private;
} grpc_transport_op;
/* Returns the amount of memory required to store a grpc_stream for this
@@ -250,11 +289,11 @@ void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_stream *stream,
grpc_closure *then_schedule_closure);
-void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
- grpc_transport_stream_op *op,
- grpc_error *error);
+void grpc_transport_stream_op_batch_finish_with_failure(
+ grpc_exec_ctx *exec_ctx, grpc_transport_stream_op_batch *op,
+ grpc_error *error);
-char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
+char *grpc_transport_stream_op_batch_string(grpc_transport_stream_op_batch *op);
char *grpc_transport_op_string(grpc_transport_op *op);
/* Send a batch of operations on a transport
@@ -265,11 +304,12 @@ char *grpc_transport_op_string(grpc_transport_op *op);
transport - the transport on which to initiate the stream
stream - the stream on which to send the operations. This must be
non-NULL and previously initialized by the same transport.
- op - a grpc_transport_stream_op specifying the op to perform */
+ op - a grpc_transport_stream_op_batch specifying the op to perform
+ */
void grpc_transport_perform_stream_op(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
grpc_stream *stream,
- grpc_transport_stream_op *op);
+ grpc_transport_stream_op_batch *op);
void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
@@ -301,9 +341,10 @@ grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx,
/* Allocate a grpc_transport_op, and preconfigure the on_consumed closure to
\a on_consumed and then delete the returned transport op */
grpc_transport_op *grpc_make_transport_op(grpc_closure *on_consumed);
-/* Allocate a grpc_transport_stream_op, and preconfigure the on_consumed closure
+/* Allocate a grpc_transport_stream_op_batch, and preconfigure the on_consumed
+ closure
to \a on_consumed and then delete the returned transport op */
-grpc_transport_stream_op *grpc_make_transport_stream_op(
+grpc_transport_stream_op_batch *grpc_make_transport_stream_op(
grpc_closure *on_consumed);
#ifdef __cplusplus
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 6f688bf8d2..bbb19a34bd 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -59,7 +59,8 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_perform_stream_op */
void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
- grpc_stream *stream, grpc_transport_stream_op *op);
+ grpc_stream *stream,
+ grpc_transport_stream_op_batch *op);
/* implementation of grpc_transport_perform_op */
void (*perform_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 28360e3784..3a2a793e01 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -71,7 +71,8 @@ static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
}
}
-char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
+char *grpc_transport_stream_op_batch_string(
+ grpc_transport_stream_op_batch *op) {
char *tmp;
char *out;
@@ -81,45 +82,49 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) {
gpr_strvec_add(
&b, gpr_strdup(op->covered_by_poller ? "[COVERED]" : "[UNCOVERED]"));
- if (op->send_initial_metadata != NULL) {
+ if (op->send_initial_metadata) {
gpr_strvec_add(&b, gpr_strdup(" "));
gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA{"));
- put_metadata_list(&b, *op->send_initial_metadata);
+ put_metadata_list(
+ &b, *op->payload->send_initial_metadata.send_initial_metadata);
gpr_strvec_add(&b, gpr_strdup("}"));
}
- if (op->send_message != NULL) {
+ if (op->send_message) {
gpr_strvec_add(&b, gpr_strdup(" "));
gpr_asprintf(&tmp, "SEND_MESSAGE:flags=0x%08x:len=%d",
- op->send_message->flags, op->send_message->length);
+ op->payload->send_message.send_message->flags,
+ op->payload->send_message.send_message->length);
gpr_strvec_add(&b, tmp);
}
- if (op->send_trailing_metadata != NULL) {
+ if (op->send_trailing_metadata) {
gpr_strvec_add(&b, gpr_strdup(" "));
gpr_strvec_add(&b, gpr_strdup("SEND_TRAILING_METADATA{"));
- put_metadata_list(&b, *op->send_trailing_metadata);
+ put_metadata_list(
+ &b, *op->payload->send_trailing_metadata.send_trailing_metadata);
gpr_strvec_add(&b, gpr_strdup("}"));
}
- if (op->recv_initial_metadata != NULL) {
+ if (op->recv_initial_metadata) {
gpr_strvec_add(&b, gpr_strdup(" "));
gpr_strvec_add(&b, gpr_strdup("RECV_INITIAL_METADATA"));
}
- if (op->recv_message != NULL) {
+ if (op->recv_message) {
gpr_strvec_add(&b, gpr_strdup(" "));
gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE"));
}
- if (op->recv_trailing_metadata != NULL) {
+ if (op->recv_trailing_metadata) {
gpr_strvec_add(&b, gpr_strdup(" "));
gpr_strvec_add(&b, gpr_strdup("RECV_TRAILING_METADATA"));
}
- if (op->cancel_error != GRPC_ERROR_NONE) {
+ if (op->cancel_stream) {
gpr_strvec_add(&b, gpr_strdup(" "));
- const char *msg = grpc_error_string(op->cancel_error);
+ const char *msg =
+ grpc_error_string(op->payload->cancel_stream.cancel_error);
gpr_asprintf(&tmp, "CANCEL:%s", msg);
gpr_strvec_add(&b, tmp);
@@ -204,8 +209,9 @@ char *grpc_transport_op_string(grpc_transport_op *op) {
}
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
- grpc_call_element *elem, grpc_transport_stream_op *op) {
- char *str = grpc_transport_stream_op_string(op);
+ grpc_call_element *elem,
+ grpc_transport_stream_op_batch *op) {
+ char *str = grpc_transport_stream_op_batch_string(op);
gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str);
gpr_free(str);
}
diff --git a/src/core/lib/tsi/README.md b/src/core/lib/tsi/README.md
deleted file mode 100644
index 3ca3c1ef38..0000000000
--- a/src/core/lib/tsi/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# Transport Security Interface
-An abstraction library over crypto and auth modules (typically OpenSSL)
diff --git a/src/core/lib/tsi/fake_transport_security.c b/src/core/lib/tsi/fake_transport_security.c
deleted file mode 100644
index bbe323df3b..0000000000
--- a/src/core/lib/tsi/fake_transport_security.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/tsi/fake_transport_security.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
-#include "src/core/lib/tsi/transport_security.h"
-
-/* --- Constants. ---*/
-#define TSI_FAKE_FRAME_HEADER_SIZE 4
-#define TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE 64
-#define TSI_FAKE_DEFAULT_FRAME_SIZE 16384
-
-/* --- Structure definitions. ---*/
-
-/* a frame is encoded like this:
- | size | data |
- where the size field value is the size of the size field plus the size of
- the data encoded in little endian on 4 bytes. */
-typedef struct {
- unsigned char *data;
- size_t size;
- size_t allocated_size;
- size_t offset;
- int needs_draining;
-} tsi_fake_frame;
-
-typedef enum {
- TSI_FAKE_CLIENT_INIT = 0,
- TSI_FAKE_SERVER_INIT = 1,
- TSI_FAKE_CLIENT_FINISHED = 2,
- TSI_FAKE_SERVER_FINISHED = 3,
- TSI_FAKE_HANDSHAKE_MESSAGE_MAX = 4
-} tsi_fake_handshake_message;
-
-typedef struct {
- tsi_handshaker base;
- int is_client;
- tsi_fake_handshake_message next_message_to_send;
- int needs_incoming_message;
- tsi_fake_frame incoming;
- tsi_fake_frame outgoing;
- tsi_result result;
-} tsi_fake_handshaker;
-
-typedef struct {
- tsi_frame_protector base;
- tsi_fake_frame protect_frame;
- tsi_fake_frame unprotect_frame;
- size_t max_frame_size;
-} tsi_fake_frame_protector;
-
-/* --- Utils. ---*/
-
-static const char *tsi_fake_handshake_message_strings[] = {
- "CLIENT_INIT", "SERVER_INIT", "CLIENT_FINISHED", "SERVER_FINISHED"};
-
-static const char *tsi_fake_handshake_message_to_string(int msg) {
- if (msg < 0 || msg >= TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
- gpr_log(GPR_ERROR, "Invalid message %d", msg);
- return "UNKNOWN";
- }
- return tsi_fake_handshake_message_strings[msg];
-}
-
-static tsi_result tsi_fake_handshake_message_from_string(
- const char *msg_string, tsi_fake_handshake_message *msg) {
- tsi_fake_handshake_message i;
- for (i = 0; i < TSI_FAKE_HANDSHAKE_MESSAGE_MAX; i++) {
- if (strncmp(msg_string, tsi_fake_handshake_message_strings[i],
- strlen(tsi_fake_handshake_message_strings[i])) == 0) {
- *msg = i;
- return TSI_OK;
- }
- }
- gpr_log(GPR_ERROR, "Invalid handshake message.");
- return TSI_DATA_CORRUPTED;
-}
-
-static uint32_t load32_little_endian(const unsigned char *buf) {
- return ((uint32_t)(buf[0]) | (uint32_t)(buf[1] << 8) |
- (uint32_t)(buf[2] << 16) | (uint32_t)(buf[3] << 24));
-}
-
-static void store32_little_endian(uint32_t value, unsigned char *buf) {
- buf[3] = (unsigned char)((value >> 24) & 0xFF);
- buf[2] = (unsigned char)((value >> 16) & 0xFF);
- buf[1] = (unsigned char)((value >> 8) & 0xFF);
- buf[0] = (unsigned char)((value)&0xFF);
-}
-
-static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) {
- frame->offset = 0;
- frame->needs_draining = needs_draining;
- if (!needs_draining) frame->size = 0;
-}
-
-/* Returns 1 if successful, 0 otherwise. */
-static int tsi_fake_frame_ensure_size(tsi_fake_frame *frame) {
- if (frame->data == NULL) {
- frame->allocated_size = frame->size;
- frame->data = gpr_malloc(frame->allocated_size);
- if (frame->data == NULL) return 0;
- } else if (frame->size > frame->allocated_size) {
- unsigned char *new_data = gpr_realloc(frame->data, frame->size);
- if (new_data == NULL) {
- gpr_free(frame->data);
- frame->data = NULL;
- return 0;
- }
- frame->data = new_data;
- frame->allocated_size = frame->size;
- }
- return 1;
-}
-
-/* This method should not be called if frame->needs_framing is not 0. */
-static tsi_result fill_frame_from_bytes(const unsigned char *incoming_bytes,
- size_t *incoming_bytes_size,
- tsi_fake_frame *frame) {
- size_t available_size = *incoming_bytes_size;
- size_t to_read_size = 0;
- const unsigned char *bytes_cursor = incoming_bytes;
-
- if (frame->needs_draining) return TSI_INTERNAL_ERROR;
- if (frame->data == NULL) {
- frame->allocated_size = TSI_FAKE_FRAME_INITIAL_ALLOCATED_SIZE;
- frame->data = gpr_malloc(frame->allocated_size);
- if (frame->data == NULL) return TSI_OUT_OF_RESOURCES;
- }
-
- if (frame->offset < TSI_FAKE_FRAME_HEADER_SIZE) {
- to_read_size = TSI_FAKE_FRAME_HEADER_SIZE - frame->offset;
- if (to_read_size > available_size) {
- /* Just fill what we can and exit. */
- memcpy(frame->data + frame->offset, bytes_cursor, available_size);
- bytes_cursor += available_size;
- frame->offset += available_size;
- *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
- return TSI_INCOMPLETE_DATA;
- }
- memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
- bytes_cursor += to_read_size;
- frame->offset += to_read_size;
- available_size -= to_read_size;
- frame->size = load32_little_endian(frame->data);
- if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
- }
-
- to_read_size = frame->size - frame->offset;
- if (to_read_size > available_size) {
- memcpy(frame->data + frame->offset, bytes_cursor, available_size);
- frame->offset += available_size;
- bytes_cursor += available_size;
- *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
- return TSI_INCOMPLETE_DATA;
- }
- memcpy(frame->data + frame->offset, bytes_cursor, to_read_size);
- bytes_cursor += to_read_size;
- *incoming_bytes_size = (size_t)(bytes_cursor - incoming_bytes);
- tsi_fake_frame_reset(frame, 1 /* needs_draining */);
- return TSI_OK;
-}
-
-/* This method should not be called if frame->needs_framing is 0. */
-static tsi_result drain_frame_to_bytes(unsigned char *outgoing_bytes,
- size_t *outgoing_bytes_size,
- tsi_fake_frame *frame) {
- size_t to_write_size = frame->size - frame->offset;
- if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
- if (*outgoing_bytes_size < to_write_size) {
- memcpy(outgoing_bytes, frame->data + frame->offset, *outgoing_bytes_size);
- frame->offset += *outgoing_bytes_size;
- return TSI_INCOMPLETE_DATA;
- }
- memcpy(outgoing_bytes, frame->data + frame->offset, to_write_size);
- *outgoing_bytes_size = to_write_size;
- tsi_fake_frame_reset(frame, 0 /* needs_draining */);
- return TSI_OK;
-}
-
-static tsi_result bytes_to_frame(unsigned char *bytes, size_t bytes_size,
- tsi_fake_frame *frame) {
- frame->offset = 0;
- frame->size = bytes_size + TSI_FAKE_FRAME_HEADER_SIZE;
- if (!tsi_fake_frame_ensure_size(frame)) return TSI_OUT_OF_RESOURCES;
- store32_little_endian((uint32_t)frame->size, frame->data);
- memcpy(frame->data + TSI_FAKE_FRAME_HEADER_SIZE, bytes, bytes_size);
- tsi_fake_frame_reset(frame, 1 /* needs draining */);
- return TSI_OK;
-}
-
-static void tsi_fake_frame_destruct(tsi_fake_frame *frame) {
- if (frame->data != NULL) gpr_free(frame->data);
-}
-
-/* --- tsi_frame_protector methods implementation. ---*/
-
-static tsi_result fake_protector_protect(tsi_frame_protector *self,
- const unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size,
- unsigned char *protected_output_frames,
- size_t *protected_output_frames_size) {
- tsi_result result = TSI_OK;
- tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
- unsigned char frame_header[TSI_FAKE_FRAME_HEADER_SIZE];
- tsi_fake_frame *frame = &impl->protect_frame;
- size_t saved_output_size = *protected_output_frames_size;
- size_t drained_size = 0;
- size_t *num_bytes_written = protected_output_frames_size;
- *num_bytes_written = 0;
-
- /* Try to drain first. */
- if (frame->needs_draining) {
- drained_size = saved_output_size - *num_bytes_written;
- result =
- drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
- *num_bytes_written += drained_size;
- protected_output_frames += drained_size;
- if (result != TSI_OK) {
- if (result == TSI_INCOMPLETE_DATA) {
- *unprotected_bytes_size = 0;
- result = TSI_OK;
- }
- return result;
- }
- }
-
- /* Now process the unprotected_bytes. */
- if (frame->needs_draining) return TSI_INTERNAL_ERROR;
- if (frame->size == 0) {
- /* New frame, create a header. */
- size_t written_in_frame_size = 0;
- store32_little_endian((uint32_t)impl->max_frame_size, frame_header);
- written_in_frame_size = TSI_FAKE_FRAME_HEADER_SIZE;
- result = fill_frame_from_bytes(frame_header, &written_in_frame_size, frame);
- if (result != TSI_INCOMPLETE_DATA) {
- gpr_log(GPR_ERROR, "fill_frame_from_bytes returned %s",
- tsi_result_to_string(result));
- return result;
- }
- }
- result =
- fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame);
- if (result != TSI_OK) {
- if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
- return result;
- }
-
- /* Try to drain again. */
- if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
- if (frame->offset != 0) return TSI_INTERNAL_ERROR;
- drained_size = saved_output_size - *num_bytes_written;
- result = drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
- *num_bytes_written += drained_size;
- if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
- return result;
-}
-
-static tsi_result fake_protector_protect_flush(
- tsi_frame_protector *self, unsigned char *protected_output_frames,
- size_t *protected_output_frames_size, size_t *still_pending_size) {
- tsi_result result = TSI_OK;
- tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
- tsi_fake_frame *frame = &impl->protect_frame;
- if (!frame->needs_draining) {
- /* Create a short frame. */
- frame->size = frame->offset;
- frame->offset = 0;
- frame->needs_draining = 1;
- store32_little_endian((uint32_t)frame->size,
- frame->data); /* Overwrite header. */
- }
- result = drain_frame_to_bytes(protected_output_frames,
- protected_output_frames_size, frame);
- if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
- *still_pending_size = frame->size - frame->offset;
- return result;
-}
-
-static tsi_result fake_protector_unprotect(
- tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
- size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size) {
- tsi_result result = TSI_OK;
- tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
- tsi_fake_frame *frame = &impl->unprotect_frame;
- size_t saved_output_size = *unprotected_bytes_size;
- size_t drained_size = 0;
- size_t *num_bytes_written = unprotected_bytes_size;
- *num_bytes_written = 0;
-
- /* Try to drain first. */
- if (frame->needs_draining) {
- /* Go past the header if needed. */
- if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE;
- drained_size = saved_output_size - *num_bytes_written;
- result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
- unprotected_bytes += drained_size;
- *num_bytes_written += drained_size;
- if (result != TSI_OK) {
- if (result == TSI_INCOMPLETE_DATA) {
- *protected_frames_bytes_size = 0;
- result = TSI_OK;
- }
- return result;
- }
- }
-
- /* Now process the protected_bytes. */
- if (frame->needs_draining) return TSI_INTERNAL_ERROR;
- result = fill_frame_from_bytes(protected_frames_bytes,
- protected_frames_bytes_size, frame);
- if (result != TSI_OK) {
- if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
- return result;
- }
-
- /* Try to drain again. */
- if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
- if (frame->offset != 0) return TSI_INTERNAL_ERROR;
- frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */
- drained_size = saved_output_size - *num_bytes_written;
- result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
- *num_bytes_written += drained_size;
- if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
- return result;
-}
-
-static void fake_protector_destroy(tsi_frame_protector *self) {
- tsi_fake_frame_protector *impl = (tsi_fake_frame_protector *)self;
- tsi_fake_frame_destruct(&impl->protect_frame);
- tsi_fake_frame_destruct(&impl->unprotect_frame);
- gpr_free(self);
-}
-
-static const tsi_frame_protector_vtable frame_protector_vtable = {
- fake_protector_protect, fake_protector_protect_flush,
- fake_protector_unprotect, fake_protector_destroy,
-};
-
-/* --- tsi_handshaker methods implementation. ---*/
-
-static tsi_result fake_handshaker_get_bytes_to_send_to_peer(
- tsi_handshaker *self, unsigned char *bytes, size_t *bytes_size) {
- tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
- tsi_result result = TSI_OK;
- if (impl->needs_incoming_message || impl->result == TSI_OK) {
- *bytes_size = 0;
- return TSI_OK;
- }
- if (!impl->outgoing.needs_draining) {
- tsi_fake_handshake_message next_message_to_send =
- impl->next_message_to_send + 2;
- const char *msg_string =
- tsi_fake_handshake_message_to_string(impl->next_message_to_send);
- result = bytes_to_frame((unsigned char *)msg_string, strlen(msg_string),
- &impl->outgoing);
- if (result != TSI_OK) return result;
- if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
- next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX;
- }
- if (tsi_tracing_enabled) {
- gpr_log(GPR_INFO, "%s prepared %s.",
- impl->is_client ? "Client" : "Server",
- tsi_fake_handshake_message_to_string(impl->next_message_to_send));
- }
- impl->next_message_to_send = next_message_to_send;
- }
- result = drain_frame_to_bytes(bytes, bytes_size, &impl->outgoing);
- if (result != TSI_OK) return result;
- if (!impl->is_client &&
- impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
- /* We're done. */
- if (tsi_tracing_enabled) {
- gpr_log(GPR_INFO, "Server is done.");
- }
- impl->result = TSI_OK;
- } else {
- impl->needs_incoming_message = 1;
- }
- return TSI_OK;
-}
-
-static tsi_result fake_handshaker_process_bytes_from_peer(
- tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) {
- tsi_result result = TSI_OK;
- tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
- tsi_fake_handshake_message expected_msg = impl->next_message_to_send - 1;
- tsi_fake_handshake_message received_msg;
-
- if (!impl->needs_incoming_message || impl->result == TSI_OK) {
- *bytes_size = 0;
- return TSI_OK;
- }
- result = fill_frame_from_bytes(bytes, bytes_size, &impl->incoming);
- if (result != TSI_OK) return result;
-
- /* We now have a complete frame. */
- result = tsi_fake_handshake_message_from_string(
- (const char *)impl->incoming.data + TSI_FAKE_FRAME_HEADER_SIZE,
- &received_msg);
- if (result != TSI_OK) {
- impl->result = result;
- return result;
- }
- if (received_msg != expected_msg) {
- gpr_log(GPR_ERROR, "Invalid received message (%s instead of %s)",
- tsi_fake_handshake_message_to_string(received_msg),
- tsi_fake_handshake_message_to_string(expected_msg));
- }
- if (tsi_tracing_enabled) {
- gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server",
- tsi_fake_handshake_message_to_string(received_msg));
- }
- tsi_fake_frame_reset(&impl->incoming, 0 /* needs_draining */);
- impl->needs_incoming_message = 0;
- if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
- /* We're done. */
- if (tsi_tracing_enabled) {
- gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server");
- }
- impl->result = TSI_OK;
- }
- return TSI_OK;
-}
-
-static tsi_result fake_handshaker_get_result(tsi_handshaker *self) {
- tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
- return impl->result;
-}
-
-static tsi_result fake_handshaker_extract_peer(tsi_handshaker *self,
- tsi_peer *peer) {
- tsi_result result = tsi_construct_peer(1, peer);
- if (result != TSI_OK) return result;
- result = tsi_construct_string_peer_property_from_cstring(
- TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_FAKE_CERTIFICATE_TYPE,
- &peer->properties[0]);
- if (result != TSI_OK) tsi_peer_destruct(peer);
- return result;
-}
-
-static tsi_result fake_handshaker_create_frame_protector(
- tsi_handshaker *self, size_t *max_protected_frame_size,
- tsi_frame_protector **protector) {
- *protector = tsi_create_fake_protector(max_protected_frame_size);
- if (*protector == NULL) return TSI_OUT_OF_RESOURCES;
- return TSI_OK;
-}
-
-static void fake_handshaker_destroy(tsi_handshaker *self) {
- tsi_fake_handshaker *impl = (tsi_fake_handshaker *)self;
- tsi_fake_frame_destruct(&impl->incoming);
- tsi_fake_frame_destruct(&impl->outgoing);
- gpr_free(self);
-}
-
-static const tsi_handshaker_vtable handshaker_vtable = {
- fake_handshaker_get_bytes_to_send_to_peer,
- fake_handshaker_process_bytes_from_peer,
- fake_handshaker_get_result,
- fake_handshaker_extract_peer,
- fake_handshaker_create_frame_protector,
- fake_handshaker_destroy,
-};
-
-tsi_handshaker *tsi_create_fake_handshaker(int is_client) {
- tsi_fake_handshaker *impl = gpr_zalloc(sizeof(*impl));
- impl->base.vtable = &handshaker_vtable;
- impl->is_client = is_client;
- impl->result = TSI_HANDSHAKE_IN_PROGRESS;
- if (is_client) {
- impl->needs_incoming_message = 0;
- impl->next_message_to_send = TSI_FAKE_CLIENT_INIT;
- } else {
- impl->needs_incoming_message = 1;
- impl->next_message_to_send = TSI_FAKE_SERVER_INIT;
- }
- return &impl->base;
-}
-
-tsi_frame_protector *tsi_create_fake_protector(
- size_t *max_protected_frame_size) {
- tsi_fake_frame_protector *impl = gpr_zalloc(sizeof(*impl));
- impl->max_frame_size = (max_protected_frame_size == NULL)
- ? TSI_FAKE_DEFAULT_FRAME_SIZE
- : *max_protected_frame_size;
- impl->base.vtable = &frame_protector_vtable;
- return &impl->base;
-}
diff --git a/src/core/lib/tsi/fake_transport_security.h b/src/core/lib/tsi/fake_transport_security.h
deleted file mode 100644
index 54a9469b58..0000000000
--- a/src/core/lib/tsi/fake_transport_security.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H
-#define GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H
-
-#include "src/core/lib/tsi/transport_security_interface.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
-#define TSI_FAKE_CERTIFICATE_TYPE "FAKE"
-
-/* Creates a fake handshaker that will create a fake frame protector.
-
- No cryptography is performed in these objects. They just simulate handshake
- messages going back and forth for the handshaker and do some framing on
- cleartext data for the protector. */
-tsi_handshaker *tsi_create_fake_handshaker(int is_client);
-
-/* Creates a protector directly without going through the handshake phase. */
-tsi_frame_protector *tsi_create_fake_protector(
- size_t *max_protected_frame_size);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_CORE_LIB_TSI_FAKE_TRANSPORT_SECURITY_H */
diff --git a/src/core/lib/tsi/ssl_transport_security.c b/src/core/lib/tsi/ssl_transport_security.c
deleted file mode 100644
index 53aabdb926..0000000000
--- a/src/core/lib/tsi/ssl_transport_security.c
+++ /dev/null
@@ -1,1572 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/tsi/ssl_transport_security.h"
-
-#include <grpc/support/port_platform.h>
-
-#include <limits.h>
-#include <string.h>
-
-/* TODO(jboeuf): refactor inet_ntop into a portability header. */
-/* Note: for whomever reads this and tries to refactor this, this
- can't be in grpc, it has to be in gpr. */
-#ifdef GPR_WINDOWS
-#include <ws2tcpip.h>
-#else
-#include <arpa/inet.h>
-#endif
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-
-#include <openssl/bio.h>
-#include <openssl/crypto.h> /* For OPENSSL_free */
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
-#include "src/core/lib/tsi/ssl_types.h"
-#include "src/core/lib/tsi/transport_security.h"
-
-/* --- Constants. ---*/
-
-#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
-#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
-
-/* Putting a macro like this and littering the source file with #if is really
- bad practice.
- TODO(jboeuf): refactor all the #if / #endif in a separate module. */
-#ifndef TSI_OPENSSL_ALPN_SUPPORT
-#define TSI_OPENSSL_ALPN_SUPPORT 1
-#endif
-
-/* TODO(jboeuf): I have not found a way to get this number dynamically from the
- SSL structure. This is what we would ultimately want though... */
-#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
-
-/* --- Structure definitions. ---*/
-
-struct tsi_ssl_handshaker_factory {
- tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self,
- const char *server_name_indication,
- tsi_handshaker **handshaker);
- void (*destroy)(tsi_ssl_handshaker_factory *self);
-};
-
-typedef struct {
- tsi_ssl_handshaker_factory base;
- SSL_CTX *ssl_context;
- unsigned char *alpn_protocol_list;
- size_t alpn_protocol_list_length;
-} tsi_ssl_client_handshaker_factory;
-
-typedef struct {
- tsi_ssl_handshaker_factory base;
-
- /* Several contexts to support SNI.
- The tsi_peer array contains the subject names of the server certificates
- associated with the contexts at the same index. */
- SSL_CTX **ssl_contexts;
- tsi_peer *ssl_context_x509_subject_names;
- size_t ssl_context_count;
- unsigned char *alpn_protocol_list;
- size_t alpn_protocol_list_length;
-} tsi_ssl_server_handshaker_factory;
-
-typedef struct {
- tsi_handshaker base;
- SSL *ssl;
- BIO *into_ssl;
- BIO *from_ssl;
- tsi_result result;
-} tsi_ssl_handshaker;
-
-typedef struct {
- tsi_frame_protector base;
- SSL *ssl;
- BIO *into_ssl;
- BIO *from_ssl;
- unsigned char *buffer;
- size_t buffer_size;
- size_t buffer_offset;
-} tsi_ssl_frame_protector;
-
-/* --- Library Initialization. ---*/
-
-static gpr_once init_openssl_once = GPR_ONCE_INIT;
-static gpr_mu *openssl_mutexes = NULL;
-
-static void openssl_locking_cb(int mode, int type, const char *file, int line) {
- if (mode & CRYPTO_LOCK) {
- gpr_mu_lock(&openssl_mutexes[type]);
- } else {
- gpr_mu_unlock(&openssl_mutexes[type]);
- }
-}
-
-static unsigned long openssl_thread_id_cb(void) {
- return (unsigned long)gpr_thd_currentid();
-}
-
-static void init_openssl(void) {
- int i;
- int num_locks;
- SSL_library_init();
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- num_locks = CRYPTO_num_locks();
- GPR_ASSERT(num_locks > 0);
- openssl_mutexes = gpr_malloc((size_t)num_locks * sizeof(gpr_mu));
- for (i = 0; i < CRYPTO_num_locks(); i++) {
- gpr_mu_init(&openssl_mutexes[i]);
- }
- CRYPTO_set_locking_callback(openssl_locking_cb);
- CRYPTO_set_id_callback(openssl_thread_id_cb);
-}
-
-/* --- Ssl utils. ---*/
-
-static const char *ssl_error_string(int error) {
- switch (error) {
- case SSL_ERROR_NONE:
- return "SSL_ERROR_NONE";
- case SSL_ERROR_ZERO_RETURN:
- return "SSL_ERROR_ZERO_RETURN";
- case SSL_ERROR_WANT_READ:
- return "SSL_ERROR_WANT_READ";
- case SSL_ERROR_WANT_WRITE:
- return "SSL_ERROR_WANT_WRITE";
- case SSL_ERROR_WANT_CONNECT:
- return "SSL_ERROR_WANT_CONNECT";
- case SSL_ERROR_WANT_ACCEPT:
- return "SSL_ERROR_WANT_ACCEPT";
- case SSL_ERROR_WANT_X509_LOOKUP:
- return "SSL_ERROR_WANT_X509_LOOKUP";
- case SSL_ERROR_SYSCALL:
- return "SSL_ERROR_SYSCALL";
- case SSL_ERROR_SSL:
- return "SSL_ERROR_SSL";
- default:
- return "Unknown error";
- }
-}
-
-/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
-static void ssl_log_where_info(const SSL *ssl, int where, int flag,
- const char *msg) {
- if ((where & flag) && tsi_tracing_enabled) {
- gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg,
- SSL_state_string_long(ssl), SSL_state_string(ssl));
- }
-}
-
-/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */
-static void ssl_info_callback(const SSL *ssl, int where, int ret) {
- if (ret == 0) {
- gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n");
- return;
- }
-
- ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP");
- ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
- ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
-}
-
-/* Returns 1 if name looks like an IP address, 0 otherwise.
- This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */
-static int looks_like_ip_address(const char *name) {
- size_t i;
- size_t dot_count = 0;
- size_t num_size = 0;
- for (i = 0; i < strlen(name); i++) {
- if (name[i] == ':') {
- /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */
- return 1;
- }
- if (name[i] >= '0' && name[i] <= '9') {
- if (num_size > 3) return 0;
- num_size++;
- } else if (name[i] == '.') {
- if (dot_count > 3 || num_size == 0) return 0;
- dot_count++;
- num_size = 0;
- } else {
- return 0;
- }
- }
- if (dot_count < 3 || num_size == 0) return 0;
- return 1;
-}
-
-/* Gets the subject CN from an X509 cert. */
-static tsi_result ssl_get_x509_common_name(X509 *cert, unsigned char **utf8,
- size_t *utf8_size) {
- int common_name_index = -1;
- X509_NAME_ENTRY *common_name_entry = NULL;
- ASN1_STRING *common_name_asn1 = NULL;
- X509_NAME *subject_name = X509_get_subject_name(cert);
- int utf8_returned_size = 0;
- if (subject_name == NULL) {
- gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
- return TSI_NOT_FOUND;
- }
- common_name_index =
- X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
- if (common_name_index == -1) {
- gpr_log(GPR_ERROR,
- "Could not get common name of subject from certificate.");
- return TSI_NOT_FOUND;
- }
- common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
- if (common_name_entry == NULL) {
- gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
- return TSI_INTERNAL_ERROR;
- }
- common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
- if (common_name_asn1 == NULL) {
- gpr_log(GPR_ERROR,
- "Could not get common name entry asn1 from certificate.");
- return TSI_INTERNAL_ERROR;
- }
- utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1);
- if (utf8_returned_size < 0) {
- gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
- return TSI_OUT_OF_RESOURCES;
- }
- *utf8_size = (size_t)utf8_returned_size;
- return TSI_OK;
-}
-
-/* Gets the subject CN of an X509 cert as a tsi_peer_property. */
-static tsi_result peer_property_from_x509_common_name(
- X509 *cert, tsi_peer_property *property) {
- unsigned char *common_name;
- size_t common_name_size;
- tsi_result result =
- ssl_get_x509_common_name(cert, &common_name, &common_name_size);
- if (result != TSI_OK) {
- if (result == TSI_NOT_FOUND) {
- common_name = NULL;
- common_name_size = 0;
- } else {
- return result;
- }
- }
- result = tsi_construct_string_peer_property(
- TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY,
- common_name == NULL ? "" : (const char *)common_name, common_name_size,
- property);
- OPENSSL_free(common_name);
- return result;
-}
-
-/* Gets the X509 cert in PEM format as a tsi_peer_property. */
-static tsi_result add_pem_certificate(X509 *cert, tsi_peer_property *property) {
- BIO *bio = BIO_new(BIO_s_mem());
- if (!PEM_write_bio_X509(bio, cert)) {
- BIO_free(bio);
- return TSI_INTERNAL_ERROR;
- }
- char *contents;
- long len = BIO_get_mem_data(bio, &contents);
- if (len <= 0) {
- BIO_free(bio);
- return TSI_INTERNAL_ERROR;
- }
- tsi_result result = tsi_construct_string_peer_property(
- TSI_X509_PEM_CERT_PROPERTY, (const char *)contents, (size_t)len,
- property);
- BIO_free(bio);
- return result;
-}
-
-/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
-static tsi_result add_subject_alt_names_properties_to_peer(
- tsi_peer *peer, GENERAL_NAMES *subject_alt_names,
- size_t subject_alt_name_count) {
- size_t i;
- tsi_result result = TSI_OK;
-
- /* Reset for DNS entries filtering. */
- peer->property_count -= subject_alt_name_count;
-
- for (i = 0; i < subject_alt_name_count; i++) {
- GENERAL_NAME *subject_alt_name =
- sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
- /* Filter out the non-dns entries names. */
- if (subject_alt_name->type == GEN_DNS) {
- unsigned char *name = NULL;
- int name_size;
- name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
- if (name_size < 0) {
- gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
- result = TSI_INTERNAL_ERROR;
- break;
- }
- result = tsi_construct_string_peer_property(
- TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char *)name,
- (size_t)name_size, &peer->properties[peer->property_count++]);
- OPENSSL_free(name);
- } else if (subject_alt_name->type == GEN_IPADD) {
- char ntop_buf[INET6_ADDRSTRLEN];
- int af;
-
- if (subject_alt_name->d.iPAddress->length == 4) {
- af = AF_INET;
- } else if (subject_alt_name->d.iPAddress->length == 16) {
- af = AF_INET6;
- } else {
- gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP");
- result = TSI_INTERNAL_ERROR;
- break;
- }
- const char *name = inet_ntop(af, subject_alt_name->d.iPAddress->data,
- ntop_buf, INET6_ADDRSTRLEN);
- if (name == NULL) {
- gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet.");
- result = TSI_INTERNAL_ERROR;
- break;
- }
-
- result = tsi_construct_string_peer_property_from_cstring(
- TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
- &peer->properties[peer->property_count++]);
- }
- if (result != TSI_OK) break;
- }
- return result;
-}
-
-/* Gets information about the peer's X509 cert as a tsi_peer object. */
-static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
- tsi_peer *peer) {
- /* TODO(jboeuf): Maybe add more properties. */
- GENERAL_NAMES *subject_alt_names =
- X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
- int subject_alt_name_count = (subject_alt_names != NULL)
- ? (int)sk_GENERAL_NAME_num(subject_alt_names)
- : 0;
- size_t property_count;
- tsi_result result;
- GPR_ASSERT(subject_alt_name_count >= 0);
- property_count = (include_certificate_type ? (size_t)1 : 0) +
- 2 /* common name, certificate */ +
- (size_t)subject_alt_name_count;
- result = tsi_construct_peer(property_count, peer);
- if (result != TSI_OK) return result;
- do {
- if (include_certificate_type) {
- result = tsi_construct_string_peer_property_from_cstring(
- TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
- &peer->properties[0]);
- if (result != TSI_OK) break;
- }
- result = peer_property_from_x509_common_name(
- cert, &peer->properties[include_certificate_type ? 1 : 0]);
- if (result != TSI_OK) break;
-
- result = add_pem_certificate(
- cert, &peer->properties[include_certificate_type ? 2 : 1]);
- if (result != TSI_OK) break;
-
- if (subject_alt_name_count != 0) {
- result = add_subject_alt_names_properties_to_peer(
- peer, subject_alt_names, (size_t)subject_alt_name_count);
- if (result != TSI_OK) break;
- }
- } while (0);
-
- if (subject_alt_names != NULL) {
- sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
- }
- if (result != TSI_OK) tsi_peer_destruct(peer);
- return result;
-}
-
-/* Logs the SSL error stack. */
-static void log_ssl_error_stack(void) {
- unsigned long err;
- while ((err = ERR_get_error()) != 0) {
- char details[256];
- ERR_error_string_n((uint32_t)err, details, sizeof(details));
- gpr_log(GPR_ERROR, "%s", details);
- }
-}
-
-/* Performs an SSL_read and handle errors. */
-static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size) {
- int read_from_ssl;
- GPR_ASSERT(*unprotected_bytes_size <= INT_MAX);
- read_from_ssl =
- SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size);
- if (read_from_ssl == 0) {
- gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly.");
- return TSI_INTERNAL_ERROR;
- }
- if (read_from_ssl < 0) {
- read_from_ssl = SSL_get_error(ssl, read_from_ssl);
- switch (read_from_ssl) {
- case SSL_ERROR_WANT_READ:
- /* We need more data to finish the frame. */
- *unprotected_bytes_size = 0;
- return TSI_OK;
- case SSL_ERROR_WANT_WRITE:
- gpr_log(
- GPR_ERROR,
- "Peer tried to renegotiate SSL connection. This is unsupported.");
- return TSI_UNIMPLEMENTED;
- case SSL_ERROR_SSL:
- gpr_log(GPR_ERROR, "Corruption detected.");
- log_ssl_error_stack();
- return TSI_DATA_CORRUPTED;
- default:
- gpr_log(GPR_ERROR, "SSL_read failed with error %s.",
- ssl_error_string(read_from_ssl));
- return TSI_PROTOCOL_FAILURE;
- }
- }
- *unprotected_bytes_size = (size_t)read_from_ssl;
- return TSI_OK;
-}
-
-/* Performs an SSL_write and handle errors. */
-static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes,
- size_t unprotected_bytes_size) {
- int ssl_write_result;
- GPR_ASSERT(unprotected_bytes_size <= INT_MAX);
- ssl_write_result =
- SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size);
- if (ssl_write_result < 0) {
- ssl_write_result = SSL_get_error(ssl, ssl_write_result);
- if (ssl_write_result == SSL_ERROR_WANT_READ) {
- gpr_log(GPR_ERROR,
- "Peer tried to renegotiate SSL connection. This is unsupported.");
- return TSI_UNIMPLEMENTED;
- } else {
- gpr_log(GPR_ERROR, "SSL_write failed with error %s.",
- ssl_error_string(ssl_write_result));
- return TSI_INTERNAL_ERROR;
- }
- }
- return TSI_OK;
-}
-
-/* Loads an in-memory PEM certificate chain into the SSL context. */
-static tsi_result ssl_ctx_use_certificate_chain(
- SSL_CTX *context, const unsigned char *pem_cert_chain,
- size_t pem_cert_chain_size) {
- tsi_result result = TSI_OK;
- X509 *certificate = NULL;
- BIO *pem;
- GPR_ASSERT(pem_cert_chain_size <= INT_MAX);
- pem = BIO_new_mem_buf((void *)pem_cert_chain, (int)pem_cert_chain_size);
- if (pem == NULL) return TSI_OUT_OF_RESOURCES;
-
- do {
- certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
- if (certificate == NULL) {
- result = TSI_INVALID_ARGUMENT;
- break;
- }
- if (!SSL_CTX_use_certificate(context, certificate)) {
- result = TSI_INVALID_ARGUMENT;
- break;
- }
- while (1) {
- X509 *certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, "");
- if (certificate_authority == NULL) {
- ERR_clear_error();
- break; /* Done reading. */
- }
- if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
- X509_free(certificate_authority);
- result = TSI_INVALID_ARGUMENT;
- break;
- }
- /* We don't need to free certificate_authority as its ownership has been
- transfered to the context. That is not the case for certificate though.
- */
- }
- } while (0);
-
- if (certificate != NULL) X509_free(certificate);
- BIO_free(pem);
- return result;
-}
-
-/* Loads an in-memory PEM private key into the SSL context. */
-static tsi_result ssl_ctx_use_private_key(SSL_CTX *context,
- const unsigned char *pem_key,
- size_t pem_key_size) {
- tsi_result result = TSI_OK;
- EVP_PKEY *private_key = NULL;
- BIO *pem;
- GPR_ASSERT(pem_key_size <= INT_MAX);
- pem = BIO_new_mem_buf((void *)pem_key, (int)pem_key_size);
- if (pem == NULL) return TSI_OUT_OF_RESOURCES;
- do {
- private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, "");
- if (private_key == NULL) {
- result = TSI_INVALID_ARGUMENT;
- break;
- }
- if (!SSL_CTX_use_PrivateKey(context, private_key)) {
- result = TSI_INVALID_ARGUMENT;
- break;
- }
- } while (0);
- if (private_key != NULL) EVP_PKEY_free(private_key);
- BIO_free(pem);
- return result;
-}
-
-/* Loads in-memory PEM verification certs into the SSL context and optionally
- returns the verification cert names (root_names can be NULL). */
-static tsi_result ssl_ctx_load_verification_certs(
- SSL_CTX *context, const unsigned char *pem_roots, size_t pem_roots_size,
- STACK_OF(X509_NAME) * *root_names) {
- tsi_result result = TSI_OK;
- size_t num_roots = 0;
- X509 *root = NULL;
- X509_NAME *root_name = NULL;
- BIO *pem;
- X509_STORE *root_store;
- GPR_ASSERT(pem_roots_size <= INT_MAX);
- pem = BIO_new_mem_buf((void *)pem_roots, (int)pem_roots_size);
- root_store = SSL_CTX_get_cert_store(context);
- if (root_store == NULL) return TSI_INVALID_ARGUMENT;
- if (pem == NULL) return TSI_OUT_OF_RESOURCES;
- if (root_names != NULL) {
- *root_names = sk_X509_NAME_new_null();
- if (*root_names == NULL) return TSI_OUT_OF_RESOURCES;
- }
-
- while (1) {
- root = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
- if (root == NULL) {
- ERR_clear_error();
- break; /* We're at the end of stream. */
- }
- if (root_names != NULL) {
- root_name = X509_get_subject_name(root);
- if (root_name == NULL) {
- gpr_log(GPR_ERROR, "Could not get name from root certificate.");
- result = TSI_INVALID_ARGUMENT;
- break;
- }
- root_name = X509_NAME_dup(root_name);
- if (root_name == NULL) {
- result = TSI_OUT_OF_RESOURCES;
- break;
- }
- sk_X509_NAME_push(*root_names, root_name);
- root_name = NULL;
- }
- if (!X509_STORE_add_cert(root_store, root)) {
- gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
- result = TSI_INTERNAL_ERROR;
- break;
- }
- X509_free(root);
- num_roots++;
- }
-
- if (num_roots == 0) {
- gpr_log(GPR_ERROR, "Could not load any root certificate.");
- result = TSI_INVALID_ARGUMENT;
- }
-
- if (result != TSI_OK) {
- if (root != NULL) X509_free(root);
- if (root_names != NULL) {
- sk_X509_NAME_pop_free(*root_names, X509_NAME_free);
- *root_names = NULL;
- if (root_name != NULL) X509_NAME_free(root_name);
- }
- }
- BIO_free(pem);
- return result;
-}
-
-/* Populates the SSL context with a private key and a cert chain, and sets the
- cipher list and the ephemeral ECDH key. */
-static tsi_result populate_ssl_context(
- SSL_CTX *context, const unsigned char *pem_private_key,
- size_t pem_private_key_size, const unsigned char *pem_certificate_chain,
- size_t pem_certificate_chain_size, const char *cipher_list) {
- tsi_result result = TSI_OK;
- if (pem_certificate_chain != NULL) {
- result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain,
- pem_certificate_chain_size);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Invalid cert chain file.");
- return result;
- }
- }
- if (pem_private_key != NULL) {
- result =
- ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size);
- if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
- gpr_log(GPR_ERROR, "Invalid private key.");
- return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
- }
- }
- if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) {
- gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list);
- return TSI_INVALID_ARGUMENT;
- }
- {
- EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
- if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
- gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
- EC_KEY_free(ecdh);
- return TSI_INTERNAL_ERROR;
- }
- SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
- EC_KEY_free(ecdh);
- }
- return TSI_OK;
-}
-
-/* Extracts the CN and the SANs from an X509 cert as a peer object. */
-static tsi_result extract_x509_subject_names_from_pem_cert(
- const unsigned char *pem_cert, size_t pem_cert_size, tsi_peer *peer) {
- tsi_result result = TSI_OK;
- X509 *cert = NULL;
- BIO *pem;
- GPR_ASSERT(pem_cert_size <= INT_MAX);
- pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size);
- if (pem == NULL) return TSI_OUT_OF_RESOURCES;
-
- cert = PEM_read_bio_X509(pem, NULL, NULL, "");
- if (cert == NULL) {
- gpr_log(GPR_ERROR, "Invalid certificate");
- result = TSI_INVALID_ARGUMENT;
- } else {
- result = peer_from_x509(cert, 0, peer);
- }
- if (cert != NULL) X509_free(cert);
- BIO_free(pem);
- return result;
-}
-
-/* Builds the alpn protocol name list according to rfc 7301. */
-static tsi_result build_alpn_protocol_name_list(
- const unsigned char **alpn_protocols,
- const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
- unsigned char **protocol_name_list, size_t *protocol_name_list_length) {
- uint16_t i;
- unsigned char *current;
- *protocol_name_list = NULL;
- *protocol_name_list_length = 0;
- if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
- for (i = 0; i < num_alpn_protocols; i++) {
- if (alpn_protocols_lengths[i] == 0) {
- gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
- return TSI_INVALID_ARGUMENT;
- }
- *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1;
- }
- *protocol_name_list = gpr_malloc(*protocol_name_list_length);
- if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES;
- current = *protocol_name_list;
- for (i = 0; i < num_alpn_protocols; i++) {
- *(current++) = alpn_protocols_lengths[i];
- memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]);
- current += alpn_protocols_lengths[i];
- }
- /* Safety check. */
- if ((current < *protocol_name_list) ||
- ((uintptr_t)(current - *protocol_name_list) !=
- *protocol_name_list_length)) {
- return TSI_INTERNAL_ERROR;
- }
- return TSI_OK;
-}
-
-// The verification callback is used for clients that don't really care about
-// the server's certificate, but we need to pull it anyway, in case a higher
-// layer wants to look at it. In this case the verification may fail, but
-// we don't really care.
-static int NullVerifyCallback(int preverify_ok, X509_STORE_CTX *ctx) {
- return 1;
-}
-
-/* --- tsi_frame_protector methods implementation. ---*/
-
-static tsi_result ssl_protector_protect(tsi_frame_protector *self,
- const unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size,
- unsigned char *protected_output_frames,
- size_t *protected_output_frames_size) {
- tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
- int read_from_ssl;
- size_t available;
- tsi_result result = TSI_OK;
-
- /* First see if we have some pending data in the SSL BIO. */
- int pending_in_ssl = (int)BIO_pending(impl->from_ssl);
- if (pending_in_ssl > 0) {
- *unprotected_bytes_size = 0;
- GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
- read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
- (int)*protected_output_frames_size);
- if (read_from_ssl < 0) {
- gpr_log(GPR_ERROR,
- "Could not read from BIO even though some data is pending");
- return TSI_INTERNAL_ERROR;
- }
- *protected_output_frames_size = (size_t)read_from_ssl;
- return TSI_OK;
- }
-
- /* Now see if we can send a complete frame. */
- available = impl->buffer_size - impl->buffer_offset;
- if (available > *unprotected_bytes_size) {
- /* If we cannot, just copy the data in our internal buffer. */
- memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes,
- *unprotected_bytes_size);
- impl->buffer_offset += *unprotected_bytes_size;
- *protected_output_frames_size = 0;
- return TSI_OK;
- }
-
- /* If we can, prepare the buffer, send it to SSL_write and read. */
- memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available);
- result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size);
- if (result != TSI_OK) return result;
-
- GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
- read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
- (int)*protected_output_frames_size);
- if (read_from_ssl < 0) {
- gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
- return TSI_INTERNAL_ERROR;
- }
- *protected_output_frames_size = (size_t)read_from_ssl;
- *unprotected_bytes_size = available;
- impl->buffer_offset = 0;
- return TSI_OK;
-}
-
-static tsi_result ssl_protector_protect_flush(
- tsi_frame_protector *self, unsigned char *protected_output_frames,
- size_t *protected_output_frames_size, size_t *still_pending_size) {
- tsi_result result = TSI_OK;
- tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
- int read_from_ssl = 0;
- int pending;
-
- if (impl->buffer_offset != 0) {
- result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset);
- if (result != TSI_OK) return result;
- impl->buffer_offset = 0;
- }
-
- pending = (int)BIO_pending(impl->from_ssl);
- GPR_ASSERT(pending >= 0);
- *still_pending_size = (size_t)pending;
- if (*still_pending_size == 0) return TSI_OK;
-
- GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
- read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
- (int)*protected_output_frames_size);
- if (read_from_ssl <= 0) {
- gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
- return TSI_INTERNAL_ERROR;
- }
- *protected_output_frames_size = (size_t)read_from_ssl;
- pending = (int)BIO_pending(impl->from_ssl);
- GPR_ASSERT(pending >= 0);
- *still_pending_size = (size_t)pending;
- return TSI_OK;
-}
-
-static tsi_result ssl_protector_unprotect(
- tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
- size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size) {
- tsi_result result = TSI_OK;
- int written_into_ssl = 0;
- size_t output_bytes_size = *unprotected_bytes_size;
- size_t output_bytes_offset = 0;
- tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
-
- /* First, try to read remaining data from ssl. */
- result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
- if (result != TSI_OK) return result;
- if (*unprotected_bytes_size == output_bytes_size) {
- /* We have read everything we could and cannot process any more input. */
- *protected_frames_bytes_size = 0;
- return TSI_OK;
- }
- output_bytes_offset = *unprotected_bytes_size;
- unprotected_bytes += output_bytes_offset;
- *unprotected_bytes_size = output_bytes_size - output_bytes_offset;
-
- /* Then, try to write some data to ssl. */
- GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX);
- written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes,
- (int)*protected_frames_bytes_size);
- if (written_into_ssl < 0) {
- gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
- written_into_ssl);
- return TSI_INTERNAL_ERROR;
- }
- *protected_frames_bytes_size = (size_t)written_into_ssl;
-
- /* Now try to read some data again. */
- result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
- if (result == TSI_OK) {
- /* Don't forget to output the total number of bytes read. */
- *unprotected_bytes_size += output_bytes_offset;
- }
- return result;
-}
-
-static void ssl_protector_destroy(tsi_frame_protector *self) {
- tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
- if (impl->buffer != NULL) gpr_free(impl->buffer);
- if (impl->ssl != NULL) SSL_free(impl->ssl);
- gpr_free(self);
-}
-
-static const tsi_frame_protector_vtable frame_protector_vtable = {
- ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect,
- ssl_protector_destroy,
-};
-
-/* --- tsi_handshaker methods implementation. ---*/
-
-static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
- unsigned char *bytes,
- size_t *bytes_size) {
- tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
- int bytes_read_from_ssl = 0;
- if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 ||
- *bytes_size > INT_MAX) {
- return TSI_INVALID_ARGUMENT;
- }
- GPR_ASSERT(*bytes_size <= INT_MAX);
- bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size);
- if (bytes_read_from_ssl < 0) {
- *bytes_size = 0;
- if (!BIO_should_retry(impl->from_ssl)) {
- impl->result = TSI_INTERNAL_ERROR;
- return impl->result;
- } else {
- return TSI_OK;
- }
- }
- *bytes_size = (size_t)bytes_read_from_ssl;
- return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
-}
-
-static tsi_result ssl_handshaker_get_result(tsi_handshaker *self) {
- tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
- if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
- SSL_is_init_finished(impl->ssl)) {
- impl->result = TSI_OK;
- }
- return impl->result;
-}
-
-static tsi_result ssl_handshaker_process_bytes_from_peer(
- tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) {
- tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
- int bytes_written_into_ssl_size = 0;
- if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) {
- return TSI_INVALID_ARGUMENT;
- }
- GPR_ASSERT(*bytes_size <= INT_MAX);
- bytes_written_into_ssl_size =
- BIO_write(impl->into_ssl, bytes, (int)*bytes_size);
- if (bytes_written_into_ssl_size < 0) {
- gpr_log(GPR_ERROR, "Could not write to memory BIO.");
- impl->result = TSI_INTERNAL_ERROR;
- return impl->result;
- }
- *bytes_size = (size_t)bytes_written_into_ssl_size;
-
- if (!tsi_handshaker_is_in_progress(self)) {
- impl->result = TSI_OK;
- return impl->result;
- } else {
- /* Get ready to get some bytes from SSL. */
- int ssl_result = SSL_do_handshake(impl->ssl);
- ssl_result = SSL_get_error(impl->ssl, ssl_result);
- switch (ssl_result) {
- case SSL_ERROR_WANT_READ:
- if (BIO_pending(impl->from_ssl) == 0) {
- /* We need more data. */
- return TSI_INCOMPLETE_DATA;
- } else {
- return TSI_OK;
- }
- case SSL_ERROR_NONE:
- return TSI_OK;
- default: {
- char err_str[256];
- ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str));
- gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.",
- ssl_error_string(ssl_result), err_str);
- impl->result = TSI_PROTOCOL_FAILURE;
- return impl->result;
- }
- }
- }
-}
-
-static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self,
- tsi_peer *peer) {
- tsi_result result = TSI_OK;
- const unsigned char *alpn_selected = NULL;
- unsigned int alpn_selected_len;
- tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
- X509 *peer_cert = SSL_get_peer_certificate(impl->ssl);
- if (peer_cert != NULL) {
- result = peer_from_x509(peer_cert, 1, peer);
- X509_free(peer_cert);
- if (result != TSI_OK) return result;
- }
-#if TSI_OPENSSL_ALPN_SUPPORT
- SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len);
-#endif /* TSI_OPENSSL_ALPN_SUPPORT */
- if (alpn_selected == NULL) {
- /* Try npn. */
- SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected,
- &alpn_selected_len);
- }
- if (alpn_selected != NULL) {
- size_t i;
- tsi_peer_property *new_properties =
- gpr_zalloc(sizeof(*new_properties) * (peer->property_count + 1));
- for (i = 0; i < peer->property_count; i++) {
- new_properties[i] = peer->properties[i];
- }
- result = tsi_construct_string_peer_property(
- TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected,
- alpn_selected_len, &new_properties[peer->property_count]);
- if (result != TSI_OK) {
- gpr_free(new_properties);
- return result;
- }
- if (peer->properties != NULL) gpr_free(peer->properties);
- peer->property_count++;
- peer->properties = new_properties;
- }
- return result;
-}
-
-static tsi_result ssl_handshaker_create_frame_protector(
- tsi_handshaker *self, size_t *max_output_protected_frame_size,
- tsi_frame_protector **protector) {
- size_t actual_max_output_protected_frame_size =
- TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
- tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
- tsi_ssl_frame_protector *protector_impl = gpr_zalloc(sizeof(*protector_impl));
-
- if (max_output_protected_frame_size != NULL) {
- if (*max_output_protected_frame_size >
- TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) {
- *max_output_protected_frame_size =
- TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
- } else if (*max_output_protected_frame_size <
- TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) {
- *max_output_protected_frame_size =
- TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND;
- }
- actual_max_output_protected_frame_size = *max_output_protected_frame_size;
- }
- protector_impl->buffer_size =
- actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
- protector_impl->buffer = gpr_malloc(protector_impl->buffer_size);
- if (protector_impl->buffer == NULL) {
- gpr_log(GPR_ERROR,
- "Could not allocated buffer for tsi_ssl_frame_protector.");
- gpr_free(protector_impl);
- return TSI_INTERNAL_ERROR;
- }
-
- /* Transfer ownership of ssl to the frame protector. It is OK as the caller
- * cannot call anything else but destroy on the handshaker after this call. */
- protector_impl->ssl = impl->ssl;
- impl->ssl = NULL;
- protector_impl->into_ssl = impl->into_ssl;
- protector_impl->from_ssl = impl->from_ssl;
-
- protector_impl->base.vtable = &frame_protector_vtable;
- *protector = &protector_impl->base;
- return TSI_OK;
-}
-
-static void ssl_handshaker_destroy(tsi_handshaker *self) {
- tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
- SSL_free(impl->ssl); /* The BIO objects are owned by ssl */
- gpr_free(impl);
-}
-
-static const tsi_handshaker_vtable handshaker_vtable = {
- ssl_handshaker_get_bytes_to_send_to_peer,
- ssl_handshaker_process_bytes_from_peer,
- ssl_handshaker_get_result,
- ssl_handshaker_extract_peer,
- ssl_handshaker_create_frame_protector,
- ssl_handshaker_destroy,
-};
-
-/* --- tsi_ssl_handshaker_factory common methods. --- */
-
-tsi_result tsi_ssl_handshaker_factory_create_handshaker(
- tsi_ssl_handshaker_factory *self, const char *server_name_indication,
- tsi_handshaker **handshaker) {
- if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT;
- return self->create_handshaker(self, server_name_indication, handshaker);
-}
-
-void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) {
- if (self == NULL) return;
- self->destroy(self);
-}
-
-static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client,
- const char *server_name_indication,
- tsi_handshaker **handshaker) {
- SSL *ssl = SSL_new(ctx);
- BIO *into_ssl = NULL;
- BIO *from_ssl = NULL;
- tsi_ssl_handshaker *impl = NULL;
- *handshaker = NULL;
- if (ctx == NULL) {
- gpr_log(GPR_ERROR, "SSL Context is null. Should never happen.");
- return TSI_INTERNAL_ERROR;
- }
- if (ssl == NULL) {
- return TSI_OUT_OF_RESOURCES;
- }
- SSL_set_info_callback(ssl, ssl_info_callback);
-
- into_ssl = BIO_new(BIO_s_mem());
- from_ssl = BIO_new(BIO_s_mem());
- if (into_ssl == NULL || from_ssl == NULL) {
- gpr_log(GPR_ERROR, "BIO_new failed.");
- SSL_free(ssl);
- if (into_ssl != NULL) BIO_free(into_ssl);
- if (from_ssl != NULL) BIO_free(into_ssl);
- return TSI_OUT_OF_RESOURCES;
- }
- SSL_set_bio(ssl, into_ssl, from_ssl);
- if (is_client) {
- int ssl_result;
- SSL_set_connect_state(ssl);
- if (server_name_indication != NULL) {
- if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) {
- gpr_log(GPR_ERROR, "Invalid server name indication %s.",
- server_name_indication);
- SSL_free(ssl);
- return TSI_INTERNAL_ERROR;
- }
- }
- ssl_result = SSL_do_handshake(ssl);
- ssl_result = SSL_get_error(ssl, ssl_result);
- if (ssl_result != SSL_ERROR_WANT_READ) {
- gpr_log(GPR_ERROR,
- "Unexpected error received from first SSL_do_handshake call: %s",
- ssl_error_string(ssl_result));
- SSL_free(ssl);
- return TSI_INTERNAL_ERROR;
- }
- } else {
- SSL_set_accept_state(ssl);
- }
-
- impl = gpr_zalloc(sizeof(*impl));
- impl->ssl = ssl;
- impl->into_ssl = into_ssl;
- impl->from_ssl = from_ssl;
- impl->result = TSI_HANDSHAKE_IN_PROGRESS;
- impl->base.vtable = &handshaker_vtable;
- *handshaker = &impl->base;
- return TSI_OK;
-}
-
-static int select_protocol_list(const unsigned char **out,
- unsigned char *outlen,
- const unsigned char *client_list,
- size_t client_list_len,
- const unsigned char *server_list,
- size_t server_list_len) {
- const unsigned char *client_current = client_list;
- while ((unsigned int)(client_current - client_list) < client_list_len) {
- unsigned char client_current_len = *(client_current++);
- const unsigned char *server_current = server_list;
- while ((server_current >= server_list) &&
- (uintptr_t)(server_current - server_list) < server_list_len) {
- unsigned char server_current_len = *(server_current++);
- if ((client_current_len == server_current_len) &&
- !memcmp(client_current, server_current, server_current_len)) {
- *out = server_current;
- *outlen = server_current_len;
- return SSL_TLSEXT_ERR_OK;
- }
- server_current += server_current_len;
- }
- client_current += client_current_len;
- }
- return SSL_TLSEXT_ERR_NOACK;
-}
-
-/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */
-
-static tsi_result ssl_client_handshaker_factory_create_handshaker(
- tsi_ssl_handshaker_factory *self, const char *server_name_indication,
- tsi_handshaker **handshaker) {
- tsi_ssl_client_handshaker_factory *impl =
- (tsi_ssl_client_handshaker_factory *)self;
- return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication,
- handshaker);
-}
-
-static void ssl_client_handshaker_factory_destroy(
- tsi_ssl_handshaker_factory *self) {
- tsi_ssl_client_handshaker_factory *impl =
- (tsi_ssl_client_handshaker_factory *)self;
- if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context);
- if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list);
- gpr_free(impl);
-}
-
-static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out,
- unsigned char *outlen,
- const unsigned char *in,
- unsigned int inlen,
- void *arg) {
- tsi_ssl_client_handshaker_factory *factory =
- (tsi_ssl_client_handshaker_factory *)arg;
- return select_protocol_list((const unsigned char **)out, outlen,
- factory->alpn_protocol_list,
- factory->alpn_protocol_list_length, in, inlen);
-}
-
-/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
-
-static tsi_result ssl_server_handshaker_factory_create_handshaker(
- tsi_ssl_handshaker_factory *self, const char *server_name_indication,
- tsi_handshaker **handshaker) {
- tsi_ssl_server_handshaker_factory *impl =
- (tsi_ssl_server_handshaker_factory *)self;
- if (impl->ssl_context_count == 0 || server_name_indication != NULL) {
- return TSI_INVALID_ARGUMENT;
- }
- /* Create the handshaker with the first context. We will switch if needed
- because of SNI in ssl_server_handshaker_factory_servername_callback. */
- return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker);
-}
-
-static void ssl_server_handshaker_factory_destroy(
- tsi_ssl_handshaker_factory *self) {
- tsi_ssl_server_handshaker_factory *impl =
- (tsi_ssl_server_handshaker_factory *)self;
- size_t i;
- for (i = 0; i < impl->ssl_context_count; i++) {
- if (impl->ssl_contexts[i] != NULL) {
- SSL_CTX_free(impl->ssl_contexts[i]);
- tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]);
- }
- }
- if (impl->ssl_contexts != NULL) gpr_free(impl->ssl_contexts);
- if (impl->ssl_context_x509_subject_names != NULL) {
- gpr_free(impl->ssl_context_x509_subject_names);
- }
- if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list);
- gpr_free(impl);
-}
-
-static int does_entry_match_name(const char *entry, size_t entry_length,
- const char *name) {
- const char *dot;
- const char *name_subdomain = NULL;
- size_t name_length = strlen(name);
- size_t name_subdomain_length;
- if (entry_length == 0) return 0;
-
- /* Take care of '.' terminations. */
- if (name[name_length - 1] == '.') {
- name_length--;
- }
- if (entry[entry_length - 1] == '.') {
- entry_length--;
- if (entry_length == 0) return 0;
- }
-
- if ((name_length == entry_length) &&
- strncmp(name, entry, entry_length) == 0) {
- return 1; /* Perfect match. */
- }
- if (entry[0] != '*') return 0;
-
- /* Wildchar subdomain matching. */
- if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
- gpr_log(GPR_ERROR, "Invalid wildchar entry.");
- return 0;
- }
- name_subdomain = strchr(name, '.');
- if (name_subdomain == NULL) return 0;
- name_subdomain_length = strlen(name_subdomain);
- if (name_subdomain_length < 2) return 0;
- name_subdomain++; /* Starts after the dot. */
- name_subdomain_length--;
- entry += 2; /* Remove *. */
- entry_length -= 2;
- dot = strchr(name_subdomain, '.');
- if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) {
- gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain);
- return 0;
- }
- if (name_subdomain[name_subdomain_length - 1] == '.') {
- name_subdomain_length--;
- }
- return ((entry_length > 0) && (name_subdomain_length == entry_length) &&
- strncmp(entry, name_subdomain, entry_length) == 0);
-}
-
-static int ssl_server_handshaker_factory_servername_callback(SSL *ssl, int *ap,
- void *arg) {
- tsi_ssl_server_handshaker_factory *impl =
- (tsi_ssl_server_handshaker_factory *)arg;
- size_t i = 0;
- const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
- if (servername == NULL || strlen(servername) == 0) {
- return SSL_TLSEXT_ERR_NOACK;
- }
-
- for (i = 0; i < impl->ssl_context_count; i++) {
- if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i],
- servername)) {
- SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]);
- return SSL_TLSEXT_ERR_OK;
- }
- }
- gpr_log(GPR_ERROR, "No match found for server name: %s.", servername);
- return SSL_TLSEXT_ERR_ALERT_WARNING;
-}
-
-#if TSI_OPENSSL_ALPN_SUPPORT
-static int server_handshaker_factory_alpn_callback(
- SSL *ssl, const unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen, void *arg) {
- tsi_ssl_server_handshaker_factory *factory =
- (tsi_ssl_server_handshaker_factory *)arg;
- return select_protocol_list(out, outlen, in, inlen,
- factory->alpn_protocol_list,
- factory->alpn_protocol_list_length);
-}
-#endif /* TSI_OPENSSL_ALPN_SUPPORT */
-
-static int server_handshaker_factory_npn_advertised_callback(
- SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) {
- tsi_ssl_server_handshaker_factory *factory =
- (tsi_ssl_server_handshaker_factory *)arg;
- *out = factory->alpn_protocol_list;
- GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX);
- *outlen = (unsigned int)factory->alpn_protocol_list_length;
- return SSL_TLSEXT_ERR_OK;
-}
-
-/* --- tsi_ssl_handshaker_factory constructors. --- */
-
-tsi_result tsi_create_ssl_client_handshaker_factory(
- const unsigned char *pem_private_key, size_t pem_private_key_size,
- const unsigned char *pem_cert_chain, size_t pem_cert_chain_size,
- const unsigned char *pem_root_certs, size_t pem_root_certs_size,
- const char *cipher_list, const unsigned char **alpn_protocols,
- const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
- tsi_ssl_handshaker_factory **factory) {
- SSL_CTX *ssl_context = NULL;
- tsi_ssl_client_handshaker_factory *impl = NULL;
- tsi_result result = TSI_OK;
-
- gpr_once_init(&init_openssl_once, init_openssl);
-
- if (factory == NULL) return TSI_INVALID_ARGUMENT;
- *factory = NULL;
- if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT;
-
- ssl_context = SSL_CTX_new(TLSv1_2_method());
- if (ssl_context == NULL) {
- gpr_log(GPR_ERROR, "Could not create ssl context.");
- return TSI_INVALID_ARGUMENT;
- }
-
- impl = gpr_zalloc(sizeof(*impl));
- impl->ssl_context = ssl_context;
-
- do {
- result =
- populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size,
- pem_cert_chain, pem_cert_chain_size, cipher_list);
- if (result != TSI_OK) break;
- result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
- pem_root_certs_size, NULL);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Cannot load server root certificates.");
- break;
- }
-
- if (num_alpn_protocols != 0) {
- result = build_alpn_protocol_name_list(
- alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
- &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
- tsi_result_to_string(result));
- break;
- }
-#if TSI_OPENSSL_ALPN_SUPPORT
- GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX);
- if (SSL_CTX_set_alpn_protos(
- ssl_context, impl->alpn_protocol_list,
- (unsigned int)impl->alpn_protocol_list_length)) {
- gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
- result = TSI_INVALID_ARGUMENT;
- break;
- }
-#endif /* TSI_OPENSSL_ALPN_SUPPORT */
- SSL_CTX_set_next_proto_select_cb(
- ssl_context, client_handshaker_factory_npn_callback, impl);
- }
- } while (0);
- if (result != TSI_OK) {
- ssl_client_handshaker_factory_destroy(&impl->base);
- return result;
- }
- SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
- /* TODO(jboeuf): Add revocation verification. */
-
- impl->base.create_handshaker =
- ssl_client_handshaker_factory_create_handshaker;
- impl->base.destroy = ssl_client_handshaker_factory_destroy;
- *factory = &impl->base;
- return TSI_OK;
-}
-
-tsi_result tsi_create_ssl_server_handshaker_factory(
- const unsigned char **pem_private_keys,
- const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
- const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
- const unsigned char *pem_client_root_certs,
- size_t pem_client_root_certs_size, int force_client_auth,
- const char *cipher_list, const unsigned char **alpn_protocols,
- const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
- tsi_ssl_handshaker_factory **factory) {
- return tsi_create_ssl_server_handshaker_factory_ex(
- pem_private_keys, pem_private_keys_sizes, pem_cert_chains,
- pem_cert_chains_sizes, key_cert_pair_count, pem_client_root_certs,
- pem_client_root_certs_size,
- force_client_auth ? TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
- : TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
- cipher_list, alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
- factory);
-}
-
-tsi_result tsi_create_ssl_server_handshaker_factory_ex(
- const unsigned char **pem_private_keys,
- const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
- const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
- const unsigned char *pem_client_root_certs,
- size_t pem_client_root_certs_size,
- tsi_client_certificate_request_type client_certificate_request,
- const char *cipher_list, const unsigned char **alpn_protocols,
- const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
- tsi_ssl_handshaker_factory **factory) {
- tsi_ssl_server_handshaker_factory *impl = NULL;
- tsi_result result = TSI_OK;
- size_t i = 0;
-
- gpr_once_init(&init_openssl_once, init_openssl);
-
- if (factory == NULL) return TSI_INVALID_ARGUMENT;
- *factory = NULL;
- if (key_cert_pair_count == 0 || pem_private_keys == NULL ||
- pem_cert_chains == NULL) {
- return TSI_INVALID_ARGUMENT;
- }
-
- impl = gpr_zalloc(sizeof(*impl));
- impl->base.create_handshaker =
- ssl_server_handshaker_factory_create_handshaker;
- impl->base.destroy = ssl_server_handshaker_factory_destroy;
- impl->ssl_contexts = gpr_zalloc(key_cert_pair_count * sizeof(SSL_CTX *));
- impl->ssl_context_x509_subject_names =
- gpr_zalloc(key_cert_pair_count * sizeof(tsi_peer));
- if (impl->ssl_contexts == NULL ||
- impl->ssl_context_x509_subject_names == NULL) {
- tsi_ssl_handshaker_factory_destroy(&impl->base);
- return TSI_OUT_OF_RESOURCES;
- }
- impl->ssl_context_count = key_cert_pair_count;
-
- if (num_alpn_protocols > 0) {
- result = build_alpn_protocol_name_list(
- alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
- &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
- if (result != TSI_OK) {
- tsi_ssl_handshaker_factory_destroy(&impl->base);
- return result;
- }
- }
-
- for (i = 0; i < key_cert_pair_count; i++) {
- do {
- impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
- if (impl->ssl_contexts[i] == NULL) {
- gpr_log(GPR_ERROR, "Could not create ssl context.");
- result = TSI_OUT_OF_RESOURCES;
- break;
- }
- result = populate_ssl_context(
- impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i],
- pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list);
- if (result != TSI_OK) break;
-
- if (pem_client_root_certs != NULL) {
- STACK_OF(X509_NAME) *root_names = NULL;
- result = ssl_ctx_load_verification_certs(
- impl->ssl_contexts[i], pem_client_root_certs,
- pem_client_root_certs_size, &root_names);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Invalid verification certs.");
- break;
- }
- SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
- switch (client_certificate_request) {
- case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:
- SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, NULL);
- break;
- case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
- SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER,
- NullVerifyCallback);
- break;
- case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
- SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, NULL);
- break;
- case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
- SSL_CTX_set_verify(
- impl->ssl_contexts[i],
- SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- NullVerifyCallback);
- break;
- case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
- SSL_CTX_set_verify(
- impl->ssl_contexts[i],
- SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
- break;
- }
- /* TODO(jboeuf): Add revocation verification. */
- }
-
- result = extract_x509_subject_names_from_pem_cert(
- pem_cert_chains[i], pem_cert_chains_sizes[i],
- &impl->ssl_context_x509_subject_names[i]);
- if (result != TSI_OK) break;
-
- SSL_CTX_set_tlsext_servername_callback(
- impl->ssl_contexts[i],
- ssl_server_handshaker_factory_servername_callback);
- SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl);
-#if TSI_OPENSSL_ALPN_SUPPORT
- SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i],
- server_handshaker_factory_alpn_callback, impl);
-#endif /* TSI_OPENSSL_ALPN_SUPPORT */
- SSL_CTX_set_next_protos_advertised_cb(
- impl->ssl_contexts[i],
- server_handshaker_factory_npn_advertised_callback, impl);
- } while (0);
-
- if (result != TSI_OK) {
- tsi_ssl_handshaker_factory_destroy(&impl->base);
- return result;
- }
- }
- *factory = &impl->base;
- return TSI_OK;
-}
-
-/* --- tsi_ssl utils. --- */
-
-int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) {
- size_t i = 0;
- size_t san_count = 0;
- const tsi_peer_property *cn_property = NULL;
- int like_ip = looks_like_ip_address(name);
-
- /* Check the SAN first. */
- for (i = 0; i < peer->property_count; i++) {
- const tsi_peer_property *property = &peer->properties[i];
- if (property->name == NULL) continue;
- if (strcmp(property->name,
- TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
- san_count++;
-
- if (!like_ip && does_entry_match_name(property->value.data,
- property->value.length, name)) {
- return 1;
- } else if (like_ip &&
- strncmp(name, property->value.data, property->value.length) ==
- 0 &&
- strlen(name) == property->value.length) {
- /* IP Addresses are exact matches only. */
- return 1;
- }
- } else if (strcmp(property->name,
- TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
- cn_property = property;
- }
- }
-
- /* If there's no SAN, try the CN, but only if its not like an IP Address */
- if (san_count == 0 && cn_property != NULL && !like_ip) {
- if (does_entry_match_name(cn_property->value.data,
- cn_property->value.length, name)) {
- return 1;
- }
- }
-
- return 0; /* Not found. */
-}
diff --git a/src/core/lib/tsi/ssl_transport_security.h b/src/core/lib/tsi/ssl_transport_security.h
deleted file mode 100644
index 7407246118..0000000000
--- a/src/core/lib/tsi/ssl_transport_security.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H
-#define GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H
-
-#include "src/core/lib/tsi/transport_security_interface.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
-#define TSI_X509_CERTIFICATE_TYPE "X509"
-
-/* This property is of type TSI_PEER_PROPERTY_STRING. */
-#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name"
-#define TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY \
- "x509_subject_alternative_name"
-
-#define TSI_X509_PEM_CERT_PROPERTY "x509_pem_cert"
-
-#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
-
-/* --- tsi_ssl_handshaker_factory object ---
-
- This object creates tsi_handshaker objects implemented in terms of the
- TLS 1.2 specificiation. */
-
-typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory;
-
-/* Creates a client handshaker factory.
- - pem_private_key is the buffer containing the PEM encoding of the client's
- private key. This parameter can be NULL if the client does not have a
- private key.
- - pem_private_key_size is the size of the associated buffer.
- - pem_cert_chain is the buffer containing the PEM encoding of the client's
- certificate chain. This parameter can be NULL if the client does not have
- a certificate chain.
- - pem_cert_chain_size is the size of the associated buffer.
- - pem_roots_cert is the buffer containing the PEM encoding of the server
- root certificates. This parameter cannot be NULL.
- - pem_roots_cert_size is the size of the associated buffer.
- - cipher_suites contains an optional list of the ciphers that the client
- supports. The format of this string is described in:
- https://www.openssl.org/docs/apps/ciphers.html.
- This parameter can be set to NULL to use the default set of ciphers.
- TODO(jboeuf): Revisit the format of this parameter.
- - alpn_protocols is an array containing the protocol names that the
- handshakers created with this factory support. This parameter can be NULL.
- - alpn_protocols_lengths is an array containing the lengths of the alpn
- protocols specified in alpn_protocols. This parameter can be NULL.
- - num_alpn_protocols is the number of alpn protocols and associated lengths
- specified. If this parameter is 0, the other alpn parameters must be NULL.
- - factory is the address of the factory pointer to be created.
-
- - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
- where a parameter is invalid. */
-tsi_result tsi_create_ssl_client_handshaker_factory(
- const unsigned char *pem_private_key, size_t pem_private_key_size,
- const unsigned char *pem_cert_chain, size_t pem_cert_chain_size,
- const unsigned char *pem_root_certs, size_t pem_root_certs_size,
- const char *cipher_suites, const unsigned char **alpn_protocols,
- const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
- tsi_ssl_handshaker_factory **factory);
-
-/* Creates a server handshaker factory.
- - version indicates which version of the specification to use.
- - pem_private_keys is an array containing the PEM encoding of the server's
- private keys. This parameter cannot be NULL. The size of the array is
- given by the key_cert_pair_count parameter.
- - pem_private_keys_sizes is the array containing the sizes of the associated
- buffers.
- - pem_cert_chains is an array containing the PEM encoding of the server's
- cert chains. This parameter cannot be NULL. The size of the array is
- given by the key_cert_pair_count parameter.
- - pem_cert_chains_sizes is the array containing the sizes of the associated
- buffers.
- - key_cert_pair_count indicates the number of items in the private_key_files
- and cert_chain_files parameters.
- - pem_client_roots is the buffer containing the PEM encoding of the client
- root certificates. This parameter may be NULL in which case the server will
- not authenticate the client. If not NULL, the force_client_auth parameter
- specifies if the server will accept only authenticated clients or both
- authenticated and non-authenticated clients.
- - pem_client_root_certs_size is the size of the associated buffer.
- - force_client_auth, if set to non-zero will force the client to authenticate
- with an SSL cert. Note that this option is ignored if pem_client_root_certs
- is NULL or pem_client_roots_certs_size is 0
- - cipher_suites contains an optional list of the ciphers that the server
- supports. The format of this string is described in:
- https://www.openssl.org/docs/apps/ciphers.html.
- This parameter can be set to NULL to use the default set of ciphers.
- TODO(jboeuf): Revisit the format of this parameter.
- - alpn_protocols is an array containing the protocol names that the
- handshakers created with this factory support. This parameter can be NULL.
- - alpn_protocols_lengths is an array containing the lengths of the alpn
- protocols specified in alpn_protocols. This parameter can be NULL.
- - num_alpn_protocols is the number of alpn protocols and associated lengths
- specified. If this parameter is 0, the other alpn parameters must be NULL.
- - factory is the address of the factory pointer to be created.
-
- - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
- where a parameter is invalid. */
-tsi_result tsi_create_ssl_server_handshaker_factory(
- const unsigned char **pem_private_keys,
- const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
- const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
- const unsigned char *pem_client_root_certs,
- size_t pem_client_root_certs_size, int force_client_auth,
- const char *cipher_suites, const unsigned char **alpn_protocols,
- const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
- tsi_ssl_handshaker_factory **factory);
-
-/* Same as tsi_create_ssl_server_handshaker_factory method except uses
- tsi_client_certificate_request_type to support more ways to handle client
- certificate authentication.
- - client_certificate_request, if set to non-zero will force the client to
- authenticate with an SSL cert. Note that this option is ignored if
- pem_client_root_certs is NULL or pem_client_roots_certs_size is 0 */
-tsi_result tsi_create_ssl_server_handshaker_factory_ex(
- const unsigned char **pem_private_keys,
- const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains,
- const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count,
- const unsigned char *pem_client_root_certs,
- size_t pem_client_root_certs_size,
- tsi_client_certificate_request_type client_certificate_request,
- const char *cipher_suites, const unsigned char **alpn_protocols,
- const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
- tsi_ssl_handshaker_factory **factory);
-
-/* Creates a handshaker.
- - self is the factory from which the handshaker will be created.
- - server_name_indication indicates the name of the server the client is
- trying to connect to which will be relayed to the server using the SNI
- extension.
- This parameter must be NULL for a server handshaker factory.
- - handhshaker is the address of the handshaker pointer to be created.
-
- - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
- where a parameter is invalid. */
-tsi_result tsi_ssl_handshaker_factory_create_handshaker(
- tsi_ssl_handshaker_factory *self, const char *server_name_indication,
- tsi_handshaker **handshaker);
-
-/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory
- while handshakers created with this factory are still in use. */
-void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self);
-
-/* Util that checks that an ssl peer matches a specific name.
- Still TODO(jboeuf):
- - handle mixed case.
- - handle %encoded chars.
- - handle public suffix wildchar more strictly (e.g. *.co.uk) */
-int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_CORE_LIB_TSI_SSL_TRANSPORT_SECURITY_H */
diff --git a/src/core/lib/tsi/test_creds/BUILD b/src/core/lib/tsi/test_creds/BUILD
deleted file mode 100644
index 5cf04caf17..0000000000
--- a/src/core/lib/tsi/test_creds/BUILD
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2017, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-licenses(["notice"]) # 3-clause BSD
-
-exports_files([
- "ca.pem",
- "server1.key",
- "server1.pem",
-])
diff --git a/src/core/lib/tsi/test_creds/README b/src/core/lib/tsi/test_creds/README
deleted file mode 100644
index eb8482d648..0000000000
--- a/src/core/lib/tsi/test_creds/README
+++ /dev/null
@@ -1,62 +0,0 @@
-The test credentials (CONFIRMEDTESTKEY) have been generated with the following
-commands:
-
-Bad credentials (badclient.* / badserver.*):
-============================================
-
-These are self-signed certificates:
-
-$ openssl req -x509 -newkey rsa:1024 -keyout badserver.key -out badserver.pem \
- -days 3650 -nodes
-
-When prompted for certificate information, everything is default except the
-common name which is set to badserver.test.google.com.
-
-
-Valid test credentials:
-=======================
-
-The ca is self-signed:
-----------------------
-
-$ openssl req -x509 -new -newkey rsa:1024 -nodes -out ca.pem -config ca-openssl.cnf -days 3650 -extensions v3_req
-When prompted for certificate information, everything is default.
-
-client is issued by CA:
------------------------
-
-$ openssl genrsa -out client.key.rsa 1024
-$ openssl pkcs8 -topk8 -in client.key.rsa -out client.key -nocrypt
-$ rm client.key.rsa
-$ openssl req -new -key client.key -out client.csr
-
-When prompted for certificate information, everything is default except the
-common name which is set to testclient.
-
-$ openssl ca -in client.csr -out client.pem
-
-server0 is issued by CA:
-------------------------
-
-$ openssl genrsa -out server0.key.rsa 1024
-$ openssl pkcs8 -topk8 -in server0.key.rsa -out server0.key -nocrypt
-$ rm server0.key.rsa
-$ openssl req -new -key server0.key -out server0.csr
-
-When prompted for certificate information, everything is default except the
-common name which is set to *.test.google.com.au.
-
-$ openssl ca -in server0.csr -out server0.pem
-
-server1 is issued by CA with a special config for subject alternative names:
-----------------------------------------------------------------------------
-
-$ openssl genrsa -out server1.key.rsa 1024
-$ openssl pkcs8 -topk8 -in server1.key.rsa -out server1.key -nocrypt
-$ rm server1.key.rsa
-$ openssl req -new -key server1.key -out server1.csr -config server1-openssl.cnf
-
-When prompted for certificate information, everything is default except the
-common name which is set to *.test.google.com.
-
-$ openssl ca -in server1.csr -out server1.pem
diff --git a/src/core/lib/tsi/test_creds/badclient.key b/src/core/lib/tsi/test_creds/badclient.key
deleted file mode 100644
index 5832685122..0000000000
--- a/src/core/lib/tsi/test_creds/badclient.key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALJfYnFn4nkj52WF
-E5W2qUxCfjsEFyuXYYKS/07UPWsv3gpZhtjXgdeGL+dpwEBC0IRDBfGnkMp6YY5S
-O7rnEz0X3r/fvgYy+dEl2jnaA6zgc7RzMGl9U11d56gP9FiDC2190mvP/hpq2xLZ
-CTbIximpmaoQyxuuH1bbYunesIG/AgMBAAECgYAdqJCEzMIyZE7oaW0tOpcB0BiP
-FYoIvH4BKRH8eHvR476mt+YdDhBP1scGUmYeCT4Ej+RgHv2LPTgVYwT9eciP2+E/
-CBCNRel0Sw9JepwW0r+jWJtDY1pp6YXAgNRGX2UflvUsT+o9lZvagf9moLTMyGvU
-uLFnsyfLim1B4vXvWQJBANouZllXGZoSrZLtR3VgV4tzRQvJxu84kLeIk64Ov47X
-pHVBMTRBfzPEhbBodjr1m5OLaVLqkFcXftzRCrbWoKsCQQDRSoLLXOiLrtJ3DLJC
-rX7Y8wrHZrqk5bMdZLGa/UX8RanhVw3+Xp+urd1711umeNJfzu/MCk4a1KkG/CU0
-rqs9AkA4cSx1DD1JSG+yxMNpsAS1xJomFIrsM9vsPt7FdndDwrF+y+CovhDkGYDk
-RAHh+svGfZg/pQK2JRPimAmHhzqFAkEAu6Ya70s2FUeB3Mu9aJs2CD6hg3dQEVkB
-53DI7TX48d9kGW58VX1xnqS02LyWqAPcW5qm1kLHFLdndaPNmBaj4QJBAJugl367
-9d9t/QLTSuULLaoYv2vJT3s1y9HN89EoaDDEkPVfQu6GVEXgIBtim1sI/VPSzI8H
-aXvaTUwblFWSM70=
------END PRIVATE KEY-----
diff --git a/src/core/lib/tsi/test_creds/badclient.pem b/src/core/lib/tsi/test_creds/badclient.pem
deleted file mode 100644
index 1785970221..0000000000
--- a/src/core/lib/tsi/test_creds/badclient.pem
+++ /dev/null
@@ -1,17 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICoDCCAgmgAwIBAgIJANIz2/zoRiapMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZGNsaWVudC50ZXN0Lmdvb2dsZS5j
-b20wHhcNMTQwNzI4MjAwODI1WhcNMjQwNzI1MjAwODI1WjBpMQswCQYDVQQGEwJB
-VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
-cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRjbGllbnQudGVzdC5nb29nbGUuY29tMIGf
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyX2JxZ+J5I+dlhROVtqlMQn47BBcr
-l2GCkv9O1D1rL94KWYbY14HXhi/nacBAQtCEQwXxp5DKemGOUju65xM9F96/374G
-MvnRJdo52gOs4HO0czBpfVNdXeeoD/RYgwttfdJrz/4aatsS2Qk2yMYpqZmqEMsb
-rh9W22Lp3rCBvwIDAQABo1AwTjAdBgNVHQ4EFgQU523AJMR8Ds9V8fhf7gu1i0MM
-UqAwHwYDVR0jBBgwFoAU523AJMR8Ds9V8fhf7gu1i0MMUqAwDAYDVR0TBAUwAwEB
-/zANBgkqhkiG9w0BAQUFAAOBgQCI/tvSBYH1iyfLaCTBKwpdj36+MkR9EeJJmImx
-X+bjhKWXwsBX4PDMWvdusr++QGUYtyoya+hfYMXRhXua39mD54xgloQNuu9REDwX
-Ffto+aOw3BcYducz6ofxicFK/Y2VeXDurSMpRv5TfGf2Qr6eOOdaRhj6ed7BibHk
-X1VGZA==
------END CERTIFICATE-----
diff --git a/src/core/lib/tsi/test_creds/badserver.key b/src/core/lib/tsi/test_creds/badserver.key
deleted file mode 100644
index abfbde10ff..0000000000
--- a/src/core/lib/tsi/test_creds/badserver.key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKeZ1e1y29cmBKaW
-oIUwJ5neOJUjx+eD/3nRPe+dvLXEd9+db0fG5RYRR0S3mF1Ywuj4PIxlTW2YprUS
-oGSw+tcqWNIzxv94HjwYFkkvER3AblXcDBh0P2zAkzg+nf9AcAsMh0QpDTyrXtMl
-gqryjq1/vkhFofKMMbY+aXJdG6OBAgMBAAECgYAAgaB51S0A22aMMkxN2rVj6530
-JWWHN4jgD1fGj41wZyWNkWYyq1Ep3ed/N6bIMWp1VbqpGe0/9YQba/D8HOTFHGRt
-72YXnP1e/ds8cxU4x4j1vvqSPtXpMmkiXfXijOvCl9mrMH2xjghFAt6/1Nb9xo1m
-VdcOB8OdSuOIw6CI+QJBAN5FZUbS+bRXDWII/FaAih1DBpwCxhYEN+TXPJBxSen6
-kOzGt5g+mB6YqRMZ/qshshwPq7bsgFGfJ2lIdS2t3GsCQQDBCKifV5AAkOdOUrkK
-HvoX3qnVmyIA8CyvWLcIWpfZ76QAYh0q0StedKdOMXaB1jTeSJ2KU1nlss7UD1Yw
-VbrDAkAwjMHpbW3jiVw//Kx5jIwehiRscWKpLnSzBJyTBFvbwsJjJai2lX2OuVO8
-+2GYKb0Iyhd81j3VFkl6grwtpRtPAkB7+n+yt555fpfRKjhGU9b09cHGu7h/OcK5
-bBVCfE0DYHLI/DsXgPiF1g6Onh4rDdUu3xyv9xDKAqnscV099hHZAkEAvcFBfXZs
-tk18N+bUcvXTdZjzZbfLCHlJmwPIspZ8G/6Pn63deg4GVYoCvTwGruah+8y734Ph
-7PskfPgUQlB7Ag==
------END PRIVATE KEY-----
diff --git a/src/core/lib/tsi/test_creds/badserver.pem b/src/core/lib/tsi/test_creds/badserver.pem
deleted file mode 100644
index 983c979f31..0000000000
--- a/src/core/lib/tsi/test_creds/badserver.pem
+++ /dev/null
@@ -1,17 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICoDCCAgmgAwIBAgIJAPdqwqsKNy81MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxIjAgBgNVBAMMGWJhZHNlcnZlci50ZXN0Lmdvb2dsZS5j
-b20wHhcNMTQwNzI4MjAwODU0WhcNMjQwNzI1MjAwODU0WjBpMQswCQYDVQQGEwJB
-VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
-cyBQdHkgTHRkMSIwIAYDVQQDDBliYWRzZXJ2ZXIudGVzdC5nb29nbGUuY29tMIGf
-MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnmdXtctvXJgSmlqCFMCeZ3jiVI8fn
-g/950T3vnby1xHffnW9HxuUWEUdEt5hdWMLo+DyMZU1tmKa1EqBksPrXKljSM8b/
-eB48GBZJLxEdwG5V3AwYdD9swJM4Pp3/QHALDIdEKQ08q17TJYKq8o6tf75IRaHy
-jDG2PmlyXRujgQIDAQABo1AwTjAdBgNVHQ4EFgQU3u/qvHr9knMBeZyAD7mAA/ec
-8cUwHwYDVR0jBBgwFoAU3u/qvHr9knMBeZyAD7mAA/ec8cUwDAYDVR0TBAUwAwEB
-/zANBgkqhkiG9w0BAQUFAAOBgQA/FmR1SGLguxCCfhp4CYCbrAePSyPWDi48gTwj
-vVZf/OMxdVu/H8sBYFf27BjbrEugAw16DElFtgTZ83pLb2BvkUgb6vBUK5sEkgmh
-z88zBsgDp8aCf4STDOLFZMBh/E9ZKkm1zogbEmlTjFp/ceSpa2gNv7OuN4WiorOh
-Wvw40g==
------END CERTIFICATE-----
diff --git a/src/core/lib/tsi/test_creds/ca-openssl.cnf b/src/core/lib/tsi/test_creds/ca-openssl.cnf
deleted file mode 100644
index e97b945e4b..0000000000
--- a/src/core/lib/tsi/test_creds/ca-openssl.cnf
+++ /dev/null
@@ -1,17 +0,0 @@
-[req]
-distinguished_name = req_distinguished_name
-req_extensions = v3_req
-
-[req_distinguished_name]
-countryName = Country Name (2 letter code)
-countryName_default = AU
-stateOrProvinceName = State or Province Name (full name)
-stateOrProvinceName_default = Some-State
-organizationName = Organization Name (eg, company)
-organizationName_default = Internet Widgits Pty Ltd
-commonName = Common Name (eg, YOUR name)
-commonName_default = testca
-
-[v3_req]
-basicConstraints = CA:true
-keyUsage = critical, keyCertSign
diff --git a/src/core/lib/tsi/test_creds/ca.key b/src/core/lib/tsi/test_creds/ca.key
deleted file mode 100644
index 03c4f950e3..0000000000
--- a/src/core/lib/tsi/test_creds/ca.key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMBA3wVeTGHZR1Ry
-e/i+J8a2cu5gXwFV6TnObzGM7bLFCO5i9v4mLo4iFzPsHmWDUxKS3Y8iXbu0eYBl
-LoNY0lSvxDx33O+DuwMmVN+DzSD+Eod9zfvwOWHsazYCZT2PhNxnVWIuJXViY4JA
-HUGodjx+QAi6yCAurUZGvYXGgZSBAgMBAAECgYAxRi8i9BlFlufGSBVoGmydbJOm
-bwLKl9dP3o33ODSP9hok5y6A0w5plWk3AJSF1hPLleK9VcSKYGYnt0clmPVHF35g
-bx2rVK8dOT0mn7rz9Zr70jcSz1ETA2QonHZ+Y+niLmcic9At6hRtWiewblUmyFQm
-GwggIzi7LOyEUHrEcQJBAOXxyQvnLvtKzXiqcsW/K6rExqVJVk+KF0fzzVyMzTJx
-HRBxUVgvGdEJT7j+7P2kcTyafve0BBzDSPIaDyiJ+Y0CQQDWCb7jASFSbu5M3Zcd
-Gkr4ZKN1XO3VLQX10b22bQYdF45hrTN2tnzRvVUR4q86VVnXmiGiTqmLkXcA2WWf
-pHfFAkAhv9olUBo6MeF0i3frBEMRfm41hk0PwZHnMqZ6pgPcGnQMnMU2rzsXzkkQ
-OwJnvAIOxhJKovZTjmofdqmw5odlAkBYVUdRWjsNUTjJwj3GRf6gyq/nFMYWz3EB
-RWFdM1ttkDYzu45ctO2IhfHg4sPceDMO1s6AtKQmNI9/azkUjITdAkApNa9yFRzc
-TBaDNPd5KVd58LVIzoPQ6i7uMHteLXJUWqSroji6S3s4gKMFJ/dO+ZXIlgQgfJJJ
-ZDL4cdrdkeoM
------END PRIVATE KEY-----
diff --git a/src/core/lib/tsi/test_creds/ca.pem b/src/core/lib/tsi/test_creds/ca.pem
deleted file mode 100644
index 6c8511a73c..0000000000
--- a/src/core/lib/tsi/test_creds/ca.pem
+++ /dev/null
@@ -1,15 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
-Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
-YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
-BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
-+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
-g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
-Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
-HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
-sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
-oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
-Dfcog5wrJytaQ6UA0wE=
------END CERTIFICATE-----
diff --git a/src/core/lib/tsi/test_creds/client.key b/src/core/lib/tsi/test_creds/client.key
deleted file mode 100644
index f48d0735d9..0000000000
--- a/src/core/lib/tsi/test_creds/client.key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM
-s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM
-JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT
-NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS
-k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH
-0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS
-W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI
-w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5
-0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5
-/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/
-U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP
-1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd
-9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI
-JiqOszq9GWESErAatg==
------END PRIVATE KEY-----
diff --git a/src/core/lib/tsi/test_creds/client.pem b/src/core/lib/tsi/test_creds/client.pem
deleted file mode 100644
index e332091019..0000000000
--- a/src/core/lib/tsi/test_creds/client.pem
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICHzCCAYgCAQEwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV
-BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
-ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcxNzIzNTYwMloXDTI0MDcxNDIzNTYw
-MlowWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
-GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKdGVzdGNsaWVudDCB
-nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7FRH26G+Ft5VQgyzlZsfSnHSZ6GX
-b7qxmk2PO8TYqKZmkfMwke6RUfQV+S+GzRvz5LlS31U1QCp3cgwkIIAQa1E2hCEz
-W31ivbMByRK9tFpyn4Uv8KP14ObKjTQqxUZp558DgOHg5b5mGRM0pyV1eqRK6PWw
-R/bjglli6pmnr+0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAStSm5PM7ubROiKK6/
-T2FkKlhiTOx+Ryenm3Eio59emq+jXl+1nhPySX5G2PQzSR5vd1dIhwgZSR4Gyttk
-tRZ57k/NI1brUW8joiEOMJA/Mr7H7asx7wIRYDE91Fs8GkKWd5LhoPAQj+qdG35C
-OO+svdkmqH0KZo320ZUqdl2ooQ==
------END CERTIFICATE-----
diff --git a/src/core/lib/tsi/test_creds/server0.key b/src/core/lib/tsi/test_creds/server0.key
deleted file mode 100644
index add153c9ae..0000000000
--- a/src/core/lib/tsi/test_creds/server0.key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANOmffupIGC8YDau
-rOF4eKnHwPszgpkkhWzKsVxhNDBxCVYx4TEjG0XWIO0iyRXupZbUC+7N/8HnEVNa
-8F1jYhng14Iiq99cNQbbnuHHhIztmpocrJTxmnhGzoAnRa1Tb+GnAuRoIHRA/V2c
-VUE9tbikQugFx/SPgXAw6tfWB+YvAgMBAAECgYEAoEq9qzUBgoHoVEGiSPiWWe8g
-5p6yUA1qx2QTQyWTAwT4z0DjjfVKmG99bFsl8+hTnJFnoCp/gnjflEOROwkjp5kG
-m0drqOPx1jeipJjpXYTBu49h+WpZ1PF+KhVtxsIm3OOCvh67iWaKyyOVb5Og8aiR
-jl6dn/TdG/dlGD8AfUECQQDuNMle6p0oU8amC6O9wIMBroxx2nFstzE6O35PLEzG
-/tj0kxxn9Jp2TS9mGaLCzSuXmpjlF4+NOWiBPkrLC2TfAkEA43Xg7uEUkaJAz2/W
-m1lIBTLt+4rIQY/2emh33bDcA+rv8rwwrMMIv17/xPx7bs49YqGG5xufD+Rwl6TL
-qFXYsQJAPrOwagax1aKvwJeBw3oAQhoTKAkLIEXcdGqipe6QSzVcIIz0xjxxyEAr
-AOIwoLxnBCISqwMXq2H4K0UdZPMb2wJAdhdYLY1L6YRMk6XjzImg25oidisKZweA
-FvMv8DgHMj2CUAqmVrt3SivfLH1M9C09L3zfFhOAFHcsgX58gav4MQJBANSBnrHj
-tIq4l8z79CPUIuu3QyeEh+XwY8s5qE5CNTck0U59lzp9NvENHbkx3KO896TTerko
-+8bXHMLkJkHPXms=
------END PRIVATE KEY-----
diff --git a/src/core/lib/tsi/test_creds/server0.pem b/src/core/lib/tsi/test_creds/server0.pem
deleted file mode 100644
index ade75d8563..0000000000
--- a/src/core/lib/tsi/test_creds/server0.pem
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICHDCCAYUCAQQwDQYJKoZIhvcNAQEFBQAwVjELMAkGA1UEBhMCQVUxEzARBgNV
-BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
-ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTE0MDcyMjE3NTk0OVoXDTI0MDcxOTE3NTk0
-OVowVzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFDASBgNVBAoM
-C0dvb2dsZSBJbmMuMR0wGwYDVQQDDBQqLnRlc3QuZ29vZ2xlLmNvbS5hdTCBnzAN
-BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06Z9+6kgYLxgNq6s4Xh4qcfA+zOCmSSF
-bMqxXGE0MHEJVjHhMSMbRdYg7SLJFe6lltQL7s3/wecRU1rwXWNiGeDXgiKr31w1
-Btue4ceEjO2amhyslPGaeEbOgCdFrVNv4acC5GggdED9XZxVQT21uKRC6AXH9I+B
-cDDq19YH5i8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBtfR5qXG9TTI8YcYh7sA4V
-GeNoplp0x6p7OG0NLvbJqAkUnkvjIkk1m1R2AUHhbkxzx6G75JIOoNJcWrCzywBA
-BIsaTdmnNysf/s1hQJuD3IHiVb+7Ji0jhttnJlYcMid4o0tJO/a2E9YUxR+9cg0i
-obb+Ql3qsvKdWBC1dDLDLw==
------END CERTIFICATE-----
diff --git a/src/core/lib/tsi/test_creds/server1-openssl.cnf b/src/core/lib/tsi/test_creds/server1-openssl.cnf
deleted file mode 100644
index 8a02108289..0000000000
--- a/src/core/lib/tsi/test_creds/server1-openssl.cnf
+++ /dev/null
@@ -1,26 +0,0 @@
-[req]
-distinguished_name = req_distinguished_name
-req_extensions = v3_req
-
-[req_distinguished_name]
-countryName = Country Name (2 letter code)
-countryName_default = US
-stateOrProvinceName = State or Province Name (full name)
-stateOrProvinceName_default = Illinois
-localityName = Locality Name (eg, city)
-localityName_default = Chicago
-organizationName = Organization Name (eg, company)
-organizationName_default = Example, Co.
-commonName = Common Name (eg, YOUR name)
-commonName_max = 64
-
-[v3_req]
-basicConstraints = CA:FALSE
-keyUsage = nonRepudiation, digitalSignature, keyEncipherment
-subjectAltName = @alt_names
-
-[alt_names]
-DNS.1 = *.test.google.fr
-DNS.2 = waterzooi.test.google.be
-DNS.3 = *.test.youtube.com
-IP.1 = "192.168.1.3"
diff --git a/src/core/lib/tsi/test_creds/server1.key b/src/core/lib/tsi/test_creds/server1.key
deleted file mode 100644
index 143a5b8765..0000000000
--- a/src/core/lib/tsi/test_creds/server1.key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
-M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
-3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
-AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
-V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
-tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
-dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
-K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
-81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
-DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
-aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
-ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
-XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
-F98XJ7tIFfJq
------END PRIVATE KEY-----
diff --git a/src/core/lib/tsi/test_creds/server1.pem b/src/core/lib/tsi/test_creds/server1.pem
deleted file mode 100644
index f3d43fcc5b..0000000000
--- a/src/core/lib/tsi/test_creds/server1.pem
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
-MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
-ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
-LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
-zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
-9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
-CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
-em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
-CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
-hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
-y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
------END CERTIFICATE-----
diff --git a/src/core/lib/tsi/transport_security.c b/src/core/lib/tsi/transport_security.c
deleted file mode 100644
index 2cbf381c88..0000000000
--- a/src/core/lib/tsi/transport_security.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/lib/tsi/transport_security.h"
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-/* --- Tracing. --- */
-
-int tsi_tracing_enabled = 0;
-
-/* --- tsi_result common implementation. --- */
-
-const char *tsi_result_to_string(tsi_result result) {
- switch (result) {
- case TSI_OK:
- return "TSI_OK";
- case TSI_UNKNOWN_ERROR:
- return "TSI_UNKNOWN_ERROR";
- case TSI_INVALID_ARGUMENT:
- return "TSI_INVALID_ARGUMENT";
- case TSI_PERMISSION_DENIED:
- return "TSI_PERMISSION_DENIED";
- case TSI_INCOMPLETE_DATA:
- return "TSI_INCOMPLETE_DATA";
- case TSI_FAILED_PRECONDITION:
- return "TSI_FAILED_PRECONDITION";
- case TSI_UNIMPLEMENTED:
- return "TSI_UNIMPLEMENTED";
- case TSI_INTERNAL_ERROR:
- return "TSI_INTERNAL_ERROR";
- case TSI_DATA_CORRUPTED:
- return "TSI_DATA_CORRUPTED";
- case TSI_NOT_FOUND:
- return "TSI_NOT_FOUND";
- case TSI_PROTOCOL_FAILURE:
- return "TSI_PROTOCOL_FAILURE";
- case TSI_HANDSHAKE_IN_PROGRESS:
- return "TSI_HANDSHAKE_IN_PROGRESS";
- case TSI_OUT_OF_RESOURCES:
- return "TSI_OUT_OF_RESOURCES";
- default:
- return "UNKNOWN";
- }
-}
-
-/* --- tsi_frame_protector common implementation. ---
-
- Calls specific implementation after state/input validation. */
-
-tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
- const unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size,
- unsigned char *protected_output_frames,
- size_t *protected_output_frames_size) {
- if (self == NULL || unprotected_bytes == NULL ||
- unprotected_bytes_size == NULL || protected_output_frames == NULL ||
- protected_output_frames_size == NULL) {
- return TSI_INVALID_ARGUMENT;
- }
- return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
- protected_output_frames,
- protected_output_frames_size);
-}
-
-tsi_result tsi_frame_protector_protect_flush(
- tsi_frame_protector *self, unsigned char *protected_output_frames,
- size_t *protected_output_frames_size, size_t *still_pending_size) {
- if (self == NULL || protected_output_frames == NULL ||
- protected_output_frames == NULL || still_pending_size == NULL) {
- return TSI_INVALID_ARGUMENT;
- }
- return self->vtable->protect_flush(self, protected_output_frames,
- protected_output_frames_size,
- still_pending_size);
-}
-
-tsi_result tsi_frame_protector_unprotect(
- tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
- size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size) {
- if (self == NULL || protected_frames_bytes == NULL ||
- protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
- unprotected_bytes_size == NULL) {
- return TSI_INVALID_ARGUMENT;
- }
- return self->vtable->unprotect(self, protected_frames_bytes,
- protected_frames_bytes_size, unprotected_bytes,
- unprotected_bytes_size);
-}
-
-void tsi_frame_protector_destroy(tsi_frame_protector *self) {
- if (self == NULL) return;
- self->vtable->destroy(self);
-}
-
-/* --- tsi_handshaker common implementation. ---
-
- Calls specific implementation after state/input validation. */
-
-tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
- unsigned char *bytes,
- size_t *bytes_size) {
- if (self == NULL || bytes == NULL || bytes_size == NULL) {
- return TSI_INVALID_ARGUMENT;
- }
- if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
- return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
-}
-
-tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
- const unsigned char *bytes,
- size_t *bytes_size) {
- if (self == NULL || bytes == NULL || bytes_size == NULL) {
- return TSI_INVALID_ARGUMENT;
- }
- if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
- return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
-}
-
-tsi_result tsi_handshaker_get_result(tsi_handshaker *self) {
- if (self == NULL) return TSI_INVALID_ARGUMENT;
- if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
- return self->vtable->get_result(self);
-}
-
-tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) {
- if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT;
- memset(peer, 0, sizeof(tsi_peer));
- if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
- if (tsi_handshaker_get_result(self) != TSI_OK) {
- return TSI_FAILED_PRECONDITION;
- }
- return self->vtable->extract_peer(self, peer);
-}
-
-tsi_result tsi_handshaker_create_frame_protector(
- tsi_handshaker *self, size_t *max_protected_frame_size,
- tsi_frame_protector **protector) {
- tsi_result result;
- if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
- if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
- if (tsi_handshaker_get_result(self) != TSI_OK) {
- return TSI_FAILED_PRECONDITION;
- }
- result = self->vtable->create_frame_protector(self, max_protected_frame_size,
- protector);
- if (result == TSI_OK) {
- self->frame_protector_created = 1;
- }
- return result;
-}
-
-void tsi_handshaker_destroy(tsi_handshaker *self) {
- if (self == NULL) return;
- self->vtable->destroy(self);
-}
-
-/* --- tsi_peer implementation. --- */
-
-tsi_peer_property tsi_init_peer_property(void) {
- tsi_peer_property property;
- memset(&property, 0, sizeof(tsi_peer_property));
- return property;
-}
-
-static void tsi_peer_destroy_list_property(tsi_peer_property *children,
- size_t child_count) {
- size_t i;
- for (i = 0; i < child_count; i++) {
- tsi_peer_property_destruct(&children[i]);
- }
- gpr_free(children);
-}
-
-void tsi_peer_property_destruct(tsi_peer_property *property) {
- if (property->name != NULL) {
- gpr_free(property->name);
- }
- if (property->value.data != NULL) {
- gpr_free(property->value.data);
- }
- *property = tsi_init_peer_property(); /* Reset everything to 0. */
-}
-
-void tsi_peer_destruct(tsi_peer *self) {
- if (self == NULL) return;
- if (self->properties != NULL) {
- tsi_peer_destroy_list_property(self->properties, self->property_count);
- self->properties = NULL;
- }
- self->property_count = 0;
-}
-
-tsi_result tsi_construct_allocated_string_peer_property(
- const char *name, size_t value_length, tsi_peer_property *property) {
- *property = tsi_init_peer_property();
- if (name != NULL) property->name = gpr_strdup(name);
- if (value_length > 0) {
- property->value.data = gpr_zalloc(value_length);
- property->value.length = value_length;
- }
- return TSI_OK;
-}
-
-tsi_result tsi_construct_string_peer_property_from_cstring(
- const char *name, const char *value, tsi_peer_property *property) {
- return tsi_construct_string_peer_property(name, value, strlen(value),
- property);
-}
-
-tsi_result tsi_construct_string_peer_property(const char *name,
- const char *value,
- size_t value_length,
- tsi_peer_property *property) {
- tsi_result result = tsi_construct_allocated_string_peer_property(
- name, value_length, property);
- if (result != TSI_OK) return result;
- if (value_length > 0) {
- memcpy(property->value.data, value, value_length);
- }
- return TSI_OK;
-}
-
-tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer) {
- memset(peer, 0, sizeof(tsi_peer));
- if (property_count > 0) {
- peer->properties = gpr_zalloc(property_count * sizeof(tsi_peer_property));
- peer->property_count = property_count;
- }
- return TSI_OK;
-}
diff --git a/src/core/lib/tsi/transport_security.h b/src/core/lib/tsi/transport_security.h
deleted file mode 100644
index aaf110ee05..0000000000
--- a/src/core/lib/tsi/transport_security.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H
-#define GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H
-
-#include "src/core/lib/tsi/transport_security_interface.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern int tsi_tracing_enabled;
-
-/* Base for tsi_frame_protector implementations.
- See transport_security_interface.h for documentation. */
-typedef struct {
- tsi_result (*protect)(tsi_frame_protector *self,
- const unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size,
- unsigned char *protected_output_frames,
- size_t *protected_output_frames_size);
- tsi_result (*protect_flush)(tsi_frame_protector *self,
- unsigned char *protected_output_frames,
- size_t *protected_output_frames_size,
- size_t *still_pending_size);
- tsi_result (*unprotect)(tsi_frame_protector *self,
- const unsigned char *protected_frames_bytes,
- size_t *protected_frames_bytes_size,
- unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size);
- void (*destroy)(tsi_frame_protector *self);
-} tsi_frame_protector_vtable;
-
-struct tsi_frame_protector {
- const tsi_frame_protector_vtable *vtable;
-};
-
-/* Base for tsi_handshaker implementations.
- See transport_security_interface.h for documentation. */
-typedef struct {
- tsi_result (*get_bytes_to_send_to_peer)(tsi_handshaker *self,
- unsigned char *bytes,
- size_t *bytes_size);
- tsi_result (*process_bytes_from_peer)(tsi_handshaker *self,
- const unsigned char *bytes,
- size_t *bytes_size);
- tsi_result (*get_result)(tsi_handshaker *self);
- tsi_result (*extract_peer)(tsi_handshaker *self, tsi_peer *peer);
- tsi_result (*create_frame_protector)(tsi_handshaker *self,
- size_t *max_protected_frame_size,
- tsi_frame_protector **protector);
- void (*destroy)(tsi_handshaker *self);
-} tsi_handshaker_vtable;
-
-struct tsi_handshaker {
- const tsi_handshaker_vtable *vtable;
- int frame_protector_created;
-};
-
-/* Peer and property construction/destruction functions. */
-tsi_result tsi_construct_peer(size_t property_count, tsi_peer *peer);
-tsi_peer_property tsi_init_peer_property(void);
-void tsi_peer_property_destruct(tsi_peer_property *property);
-tsi_result tsi_construct_string_peer_property(const char *name,
- const char *value,
- size_t value_length,
- tsi_peer_property *property);
-tsi_result tsi_construct_allocated_string_peer_property(
- const char *name, size_t value_length, tsi_peer_property *property);
-tsi_result tsi_construct_string_peer_property_from_cstring(
- const char *name, const char *value, tsi_peer_property *property);
-
-/* Utils. */
-char *tsi_strdup(const char *src); /* Sadly, no strdup in C89. */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_H */
diff --git a/src/core/lib/tsi/transport_security_interface.h b/src/core/lib/tsi/transport_security_interface.h
deleted file mode 100644
index 3e8c9d7ffe..0000000000
--- a/src/core/lib/tsi/transport_security_interface.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H
-#define GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H
-
-#include <stdint.h>
-#include <stdlib.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* --- tsi result --- */
-
-typedef enum {
- TSI_OK = 0,
- TSI_UNKNOWN_ERROR = 1,
- TSI_INVALID_ARGUMENT = 2,
- TSI_PERMISSION_DENIED = 3,
- TSI_INCOMPLETE_DATA = 4,
- TSI_FAILED_PRECONDITION = 5,
- TSI_UNIMPLEMENTED = 6,
- TSI_INTERNAL_ERROR = 7,
- TSI_DATA_CORRUPTED = 8,
- TSI_NOT_FOUND = 9,
- TSI_PROTOCOL_FAILURE = 10,
- TSI_HANDSHAKE_IN_PROGRESS = 11,
- TSI_OUT_OF_RESOURCES = 12
-} tsi_result;
-
-typedef enum {
- // Default option
- TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
- TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY,
- TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY,
- TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY,
- TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY,
-} tsi_client_certificate_request_type;
-
-const char *tsi_result_to_string(tsi_result result);
-
-/* --- tsi tracing --- */
-
-/* Set this early to avoid races */
-extern int tsi_tracing_enabled;
-
-/* --- tsi_frame_protector object ---
-
- This object protects and unprotects buffers once the handshake is done.
- Implementations of this object must be thread compatible. */
-
-typedef struct tsi_frame_protector tsi_frame_protector;
-
-/* Outputs protected frames.
- - unprotected_bytes is an input only parameter and points to the data
- to be protected.
- - unprotected_bytes_size is an input/output parameter used by the caller to
- specify how many bytes are available in unprotected_bytes. The output
- value is the number of bytes consumed during the call.
- - protected_output_frames points to a buffer allocated by the caller that
- will be written.
- - protected_output_frames_size is an input/output parameter used by the
- caller to specify how many bytes are available in protected_output_frames.
- As an output, this value indicates the number of bytes written.
- - This method returns TSI_OK in case of success or a specific error code in
- case of failure. Note that even if all the input unprotected bytes are
- consumed, they may not have been processed into the returned protected
- output frames. The caller should call the protect_flush method
- to make sure that there are no more protected bytes buffered in the
- protector.
-
- A typical way to call this method would be:
-
- ------------------------------------------------------------------------
- unsigned char protected_buffer[4096];
- size_t protected_buffer_size = sizeof(protected_buffer);
- tsi_result result = TSI_OK;
- while (message_size > 0) {
- size_t protected_buffer_size_to_send = protected_buffer_size;
- size_t processed_message_size = message_size;
- result = tsi_frame_protector_protect(protector,
- message_bytes,
- &processed_message_size,
- protected_buffer,
- &protected_buffer_size_to_send);
- if (result != TSI_OK) break;
- send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
- message_bytes += processed_message_size;
- message_size -= processed_message_size;
-
- // Don't forget to flush.
- if (message_size == 0) {
- size_t still_pending_size;
- do {
- protected_buffer_size_to_send = protected_buffer_size;
- result = tsi_frame_protector_protect_flush(
- protector, protected_buffer,
- &protected_buffer_size_to_send, &still_pending_size);
- if (result != TSI_OK) break;
- send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send);
- } while (still_pending_size > 0);
- }
- }
-
- if (result != TSI_OK) HandleError(result);
- ------------------------------------------------------------------------ */
-tsi_result tsi_frame_protector_protect(tsi_frame_protector *self,
- const unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size,
- unsigned char *protected_output_frames,
- size_t *protected_output_frames_size);
-
-/* Indicates that we need to flush the bytes buffered in the protector and get
- the resulting frame.
- - protected_output_frames points to a buffer allocated by the caller that
- will be written.
- - protected_output_frames_size is an input/output parameter used by the
- caller to specify how many bytes are available in protected_output_frames.
- - still_pending_bytes is an output parameter indicating the number of bytes
- that still need to be flushed from the protector.*/
-tsi_result tsi_frame_protector_protect_flush(
- tsi_frame_protector *self, unsigned char *protected_output_frames,
- size_t *protected_output_frames_size, size_t *still_pending_size);
-
-/* Outputs unprotected bytes.
- - protected_frames_bytes is an input only parameter and points to the
- protected frames to be unprotected.
- - protected_frames_bytes_size is an input/output only parameter used by the
- caller to specify how many bytes are available in protected_bytes. The
- output value is the number of bytes consumed during the call.
- Implementations will buffer up to a frame of protected data.
- - unprotected_bytes points to a buffer allocated by the caller that will be
- written.
- - unprotected_bytes_size is an input/output parameter used by the caller to
- specify how many bytes are available in unprotected_bytes. This
- value is expected to be at most max_protected_frame_size minus overhead
- which means that max_protected_frame_size is a safe bet. The output value
- is the number of bytes actually written.
- If *unprotected_bytes_size is unchanged, there may be more data remaining
- to unprotect, and the caller should call this function again.
-
- - This method returns TSI_OK in case of success. Success includes cases where
- there is not enough data to output a frame in which case
- unprotected_bytes_size will be set to 0 and cases where the internal buffer
- needs to be read before new protected data can be processed in which case
- protected_frames_size will be set to 0. */
-tsi_result tsi_frame_protector_unprotect(
- tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
- size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
- size_t *unprotected_bytes_size);
-
-/* Destroys the tsi_frame_protector object. */
-void tsi_frame_protector_destroy(tsi_frame_protector *self);
-
-/* --- tsi_peer objects ---
-
- tsi_peer objects are a set of properties. The peer owns the properties. */
-
-/* This property is of type TSI_PEER_PROPERTY_STRING. */
-#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type"
-
-/* Property values may contain NULL characters just like C++ strings.
- The length field gives the length of the string. */
-typedef struct tsi_peer_property {
- char *name;
- struct {
- char *data;
- size_t length;
- } value;
-} tsi_peer_property;
-
-typedef struct {
- tsi_peer_property *properties;
- size_t property_count;
-} tsi_peer;
-
-/* Destructs the tsi_peer object. */
-void tsi_peer_destruct(tsi_peer *self);
-
-/* --- tsi_handshaker objects ----
-
- Implementations of this object must be thread compatible.
-
- A typical usage of this object would be:
-
- ------------------------------------------------------------------------
- tsi_result result = TSI_OK;
- unsigned char buf[4096];
- size_t buf_offset;
- size_t buf_size;
- while (1) {
- // See if we need to send some bytes to the peer.
- do {
- size_t buf_size_to_send = sizeof(buf);
- result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf,
- &buf_size_to_send);
- if (buf_size_to_send > 0) send_bytes_to_peer(buf, buf_size_to_send);
- } while (result == TSI_INCOMPLETE_DATA);
- if (result != TSI_OK) return result;
- if (!tsi_handshaker_is_in_progress(handshaker)) break;
-
- do {
- // Read bytes from the peer.
- buf_size = sizeof(buf);
- buf_offset = 0;
- read_bytes_from_peer(buf, &buf_size);
- if (buf_size == 0) break;
-
- // Process the bytes from the peer. We have to be careful as these bytes
- // may contain non-handshake data (protected data). If this is the case,
- // we will exit from the loop with buf_size > 0.
- size_t consumed_by_handshaker = buf_size;
- result = tsi_handshaker_process_bytes_from_peer(
- handshaker, buf, &consumed_by_handshaker);
- buf_size -= consumed_by_handshaker;
- buf_offset += consumed_by_handshaker;
- } while (result == TSI_INCOMPLETE_DATA);
-
- if (result != TSI_OK) return result;
- if (!tsi_handshaker_is_in_progress(handshaker)) break;
- }
-
- // Check the Peer.
- tsi_peer peer;
- do {
- result = tsi_handshaker_extract_peer(handshaker, &peer);
- if (result != TSI_OK) break;
- result = check_peer(&peer);
- } while (0);
- tsi_peer_destruct(&peer);
- if (result != TSI_OK) return result;
-
- // Create the protector.
- tsi_frame_protector* protector = NULL;
- result = tsi_handshaker_create_frame_protector(handshaker, NULL,
- &protector);
- if (result != TSI_OK) return result;
-
- // Do not forget to unprotect outstanding data if any.
- if (buf_size > 0) {
- result = tsi_frame_protector_unprotect(protector, buf + buf_offset,
- buf_size, ..., ...);
- ....
- }
- ...
- ------------------------------------------------------------------------ */
-typedef struct tsi_handshaker tsi_handshaker;
-
-/* Gets bytes that need to be sent to the peer.
- - bytes is the buffer that will be written with the data to be sent to the
- peer.
- - bytes_size is an input/output parameter specifying the capacity of the
- bytes parameter as input and the number of bytes written as output.
- Returns TSI_OK if all the data to send to the peer has been written or if
- nothing has to be sent to the peer (in which base bytes_size outputs to 0),
- otherwise returns TSI_INCOMPLETE_DATA which indicates that this method
- needs to be called again to get all the bytes to send to the peer (there
- was more data to write than the specified bytes_size). In case of a fatal
- error in the handshake, another specific error code is returned. */
-tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
- unsigned char *bytes,
- size_t *bytes_size);
-
-/* Processes bytes received from the peer.
- - bytes is the buffer containing the data.
- - bytes_size is an input/output parameter specifying the size of the data as
- input and the number of bytes consumed as output.
- Return TSI_OK if the handshake has all the data it needs to process,
- otherwise return TSI_INCOMPLETE_DATA which indicates that this method
- needs to be called again to complete the data needed for processing. In
- case of a fatal error in the handshake, another specific error code is
- returned. */
-tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
- const unsigned char *bytes,
- size_t *bytes_size);
-
-/* Gets the result of the handshaker.
- Returns TSI_OK if the hanshake completed successfully and there has been no
- errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet
- but no error has been encountered so far. Otherwise the handshaker failed
- with the returned error. */
-tsi_result tsi_handshaker_get_result(tsi_handshaker *self);
-
-/* Returns 1 if the handshake is in progress, 0 otherwise. */
-#define tsi_handshaker_is_in_progress(h) \
- (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS)
-
-/* This method may return TSI_FAILED_PRECONDITION if
- tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise
- assuming the handshaker is not in a fatal error state.
- The caller is responsible for destructing the peer. */
-tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer);
-
-/* This method creates a tsi_frame_protector object after the handshake phase
- is done. After this method has been called successfully, the only method
- that can be called on this object is Destroy.
- - max_output_protected_frame_size is an input/output parameter specifying the
- desired max output protected frame size as input and outputing the actual
- max output frame size as the output. Passing NULL is OK and will result in
- the implementation choosing the default maximum protected frame size. Note
- that this size only applies to outgoing frames (generated with
- tsi_frame_protector_protect) and not incoming frames (input of
- tsi_frame_protector_unprotect).
- - protector is an output parameter pointing to the newly created
- tsi_frame_protector object.
- This method may return TSI_FAILED_PRECONDITION if
- tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming
- the handshaker is not in a fatal error state.
- The caller is responsible for destroying the protector. */
-tsi_result tsi_handshaker_create_frame_protector(
- tsi_handshaker *self, size_t *max_output_protected_frame_size,
- tsi_frame_protector **protector);
-
-/* This method releases the tsi_handshaker object. After this method is called,
- no other method can be called on the object. */
-void tsi_handshaker_destroy(tsi_handshaker *self);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_CORE_LIB_TSI_TRANSPORT_SECURITY_INTERFACE_H */