diff options
author | Craig Tiller <ctiller@google.com> | 2017-04-27 14:56:56 -0700 |
---|---|---|
committer | Craig Tiller <ctiller@google.com> | 2017-04-27 14:56:56 -0700 |
commit | f7283e01ddefff3d57e30e80a0e1b3530458f400 (patch) | |
tree | 3d5fd7816155142b982d4cfa2a187f05efa1df65 /src/core | |
parent | 1939744de5ac47225fa36586dff342b000d08ddc (diff) | |
parent | 4865c79548d4f83ebae4e10fbaf4c3ba10535c97 (diff) |
Merge github.com:grpc/grpc into trickle_stall
Diffstat (limited to 'src/core')
44 files changed, 1196 insertions, 452 deletions
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c index 10af252531..87549b78f0 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c @@ -98,7 +98,7 @@ grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) { pb_encode(&sizestream, grpc_lb_v1_LoadBalanceRequest_fields, request); encoded_length = sizestream.bytes_written; - slice = grpc_slice_malloc(encoded_length); + slice = GRPC_SLICE_MALLOC(encoded_length); outputstream = pb_ostream_from_buffer(GRPC_SLICE_START_PTR(slice), encoded_length); GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v1_LoadBalanceRequest_fields, diff --git a/src/core/ext/filters/client_channel/subchannel.c b/src/core/ext/filters/client_channel/subchannel.c index 967e571221..b2de85c4a1 100644 --- a/src/core/ext/filters/client_channel/subchannel.c +++ b/src/core/ext/filters/client_channel/subchannel.c @@ -615,7 +615,7 @@ void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx, elem->filter->start_transport_op(exec_ctx, elem, op); } -static void publish_transport_locked(grpc_exec_ctx *exec_ctx, +static bool publish_transport_locked(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { grpc_connected_subchannel *con; grpc_channel_stack *stk; @@ -631,15 +631,16 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, if (!grpc_channel_init_create_stack(exec_ctx, builder, GRPC_CLIENT_SUBCHANNEL)) { grpc_channel_stack_builder_destroy(exec_ctx, builder); - abort(); /* TODO(ctiller): what to do here (previously we just crashed) */ + return false; } grpc_error *error = grpc_channel_stack_builder_finish( exec_ctx, builder, 0, 1, connection_destroy, NULL, (void **)&con); if (error != GRPC_ERROR_NONE) { + grpc_transport_destroy(exec_ctx, c->connecting_result.transport); gpr_log(GPR_ERROR, "error initializing subchannel stack: %s", grpc_error_string(error)); GRPC_ERROR_UNREF(error); - abort(); /* TODO(ctiller): what to do here? */ + return false; } stk = CHANNEL_STACK_FROM_CONNECTION(con); memset(&c->connecting_result, 0, sizeof(c->connecting_result)); @@ -656,7 +657,7 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, grpc_channel_stack_destroy(exec_ctx, stk); gpr_free(con); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); - return; + return false; } /* publish */ @@ -678,6 +679,7 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx, /* signal completion */ grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY, GRPC_ERROR_NONE, "connected"); + return true; } static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, @@ -688,8 +690,9 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, GRPC_SUBCHANNEL_WEAK_REF(c, "connected"); gpr_mu_lock(&c->mu); c->connecting = false; - if (c->connecting_result.transport != NULL) { - publish_transport_locked(exec_ctx, c); + if (c->connecting_result.transport != NULL && + publish_transport_locked(exec_ctx, c)) { + /* do nothing, transport was published */ } else if (c->disconnected) { GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); } else { diff --git a/src/core/ext/filters/http/client/http_client_filter.c b/src/core/ext/filters/http/client/http_client_filter.c index bf5fbc7da7..d8ae080eee 100644 --- a/src/core/ext/filters/http/client/http_client_filter.c +++ b/src/core/ext/filters/http/client/http_client_filter.c @@ -323,7 +323,7 @@ static grpc_error *hc_mutate_op(grpc_exec_ctx *exec_ctx, estimated_len += grpc_base64_estimate_encoded_size( op->payload->send_message.send_message->length, k_url_safe, k_multi_line); - grpc_slice path_with_query_slice = grpc_slice_malloc(estimated_len); + grpc_slice path_with_query_slice = GRPC_SLICE_MALLOC(estimated_len); /* memcopy individual pieces into this slice */ uint8_t *write_ptr = diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.c b/src/core/ext/transport/chttp2/transport/bin_decoder.c index 8c87de112e..21bed18c9a 100644 --- a/src/core/ext/transport/chttp2/transport/bin_decoder.c +++ b/src/core/ext/transport/chttp2/transport/bin_decoder.c @@ -169,7 +169,7 @@ grpc_slice grpc_chttp2_base64_decode(grpc_exec_ctx *exec_ctx, } } } - output = grpc_slice_malloc(output_length); + output = GRPC_SLICE_MALLOC(output_length); ctx.input_cur = GRPC_SLICE_START_PTR(input); ctx.input_end = GRPC_SLICE_END_PTR(input); @@ -193,7 +193,7 @@ grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx, grpc_slice input, size_t output_length) { size_t input_length = GRPC_SLICE_LENGTH(input); - grpc_slice output = grpc_slice_malloc(output_length); + grpc_slice output = GRPC_SLICE_MALLOC(output_length); struct grpc_base64_decode_context ctx; // The length of a base64 string cannot be 4 * n + 1 diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.c b/src/core/ext/transport/chttp2/transport/bin_encoder.c index e301c073f3..3b8ab1f17a 100644 --- a/src/core/ext/transport/chttp2/transport/bin_encoder.c +++ b/src/core/ext/transport/chttp2/transport/bin_encoder.c @@ -66,7 +66,7 @@ grpc_slice grpc_chttp2_base64_encode(grpc_slice input) { size_t input_triplets = input_length / 3; size_t tail_case = input_length % 3; size_t output_length = input_triplets * 4 + tail_xtra[tail_case]; - grpc_slice output = grpc_slice_malloc(output_length); + grpc_slice output = GRPC_SLICE_MALLOC(output_length); uint8_t *in = GRPC_SLICE_START_PTR(input); char *out = (char *)GRPC_SLICE_START_PTR(output); size_t i; @@ -119,7 +119,7 @@ grpc_slice grpc_chttp2_huffman_compress(grpc_slice input) { nbits += grpc_chttp2_huffsyms[*in].length; } - output = grpc_slice_malloc(nbits / 8 + (nbits % 8 != 0)); + output = GRPC_SLICE_MALLOC(nbits / 8 + (nbits % 8 != 0)); out = GRPC_SLICE_START_PTR(output); for (in = GRPC_SLICE_START_PTR(input); in != GRPC_SLICE_END_PTR(input); ++in) { @@ -184,7 +184,7 @@ grpc_slice grpc_chttp2_base64_encode_and_huffman_compress(grpc_slice input) { size_t output_syms = input_triplets * 4 + tail_xtra[tail_case]; size_t max_output_bits = 11 * output_syms; size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0); - grpc_slice output = grpc_slice_malloc(max_output_length); + grpc_slice output = GRPC_SLICE_MALLOC(max_output_length); uint8_t *in = GRPC_SLICE_START_PTR(input); uint8_t *start_out = GRPC_SLICE_START_PTR(output); huff_out out; diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 37311912ab..30738080ee 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -1978,7 +1978,7 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, the time we got around to sending this, so instead we ignore HPACK compression and just write the uncompressed bytes onto the wire. */ if (!s->sent_initial_metadata) { - http_status_hdr = grpc_slice_malloc(13); + http_status_hdr = GRPC_SLICE_MALLOC(13); p = GRPC_SLICE_START_PTR(http_status_hdr); *p++ = 0x00; *p++ = 7; @@ -1996,7 +1996,7 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, GPR_ASSERT(p == GRPC_SLICE_END_PTR(http_status_hdr)); len += (uint32_t)GRPC_SLICE_LENGTH(http_status_hdr); - content_type_hdr = grpc_slice_malloc(31); + content_type_hdr = GRPC_SLICE_MALLOC(31); p = GRPC_SLICE_START_PTR(content_type_hdr); *p++ = 0x00; *p++ = 12; @@ -2033,7 +2033,7 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, len += (uint32_t)GRPC_SLICE_LENGTH(content_type_hdr); } - status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10)); + status_hdr = GRPC_SLICE_MALLOC(15 + (grpc_status >= 10)); p = GRPC_SLICE_START_PTR(status_hdr); *p++ = 0x00; /* literal header, not indexed */ *p++ = 11; /* len(grpc-status) */ @@ -2062,7 +2062,7 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, size_t msg_len = GRPC_SLICE_LENGTH(slice); GPR_ASSERT(msg_len <= UINT32_MAX); uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 1); - message_pfx = grpc_slice_malloc(14 + msg_len_len); + message_pfx = GRPC_SLICE_MALLOC(14 + msg_len_len); p = GRPC_SLICE_START_PTR(message_pfx); *p++ = 0x00; /* literal header, not indexed */ *p++ = 12; /* len(grpc-message) */ @@ -2084,7 +2084,7 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx); len += (uint32_t)msg_len; - hdr = grpc_slice_malloc(9); + hdr = GRPC_SLICE_MALLOC(9); p = GRPC_SLICE_START_PTR(hdr); *p++ = (uint8_t)(len >> 16); *p++ = (uint8_t)(len >> 8); diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c index 9aba3ea445..8cb8489794 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.c +++ b/src/core/ext/transport/chttp2/transport/frame_data.c @@ -92,7 +92,7 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf, uint8_t *p; static const size_t header_size = 9; - hdr = grpc_slice_malloc(header_size); + hdr = GRPC_SLICE_MALLOC(header_size); p = GRPC_SLICE_START_PTR(hdr); GPR_ASSERT(write_bytes < (1 << 24)); *p++ = (uint8_t)(write_bytes >> 16); @@ -106,7 +106,7 @@ void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf, *p++ = (uint8_t)(id); grpc_slice_buffer_add(outbuf, hdr); - grpc_slice_buffer_move_first(inbuf, write_bytes, outbuf); + grpc_slice_buffer_move_first_no_ref(inbuf, write_bytes, outbuf); stats->framing_bytes += header_size; stats->data_bytes += write_bytes; diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.c b/src/core/ext/transport/chttp2/transport/frame_goaway.c index 001271dd22..0f1c8b0772 100644 --- a/src/core/ext/transport/chttp2/transport/frame_goaway.c +++ b/src/core/ext/transport/chttp2/transport/frame_goaway.c @@ -163,7 +163,7 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx, void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, grpc_slice debug_data, grpc_slice_buffer *slice_buffer) { - grpc_slice header = grpc_slice_malloc(9 + 4 + 4); + grpc_slice header = GRPC_SLICE_MALLOC(9 + 4 + 4); uint8_t *p = GRPC_SLICE_START_PTR(header); uint32_t frame_length; GPR_ASSERT(GRPC_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4); diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c index 6016e43127..f09ca60739 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.c +++ b/src/core/ext/transport/chttp2/transport/frame_ping.c @@ -43,7 +43,7 @@ static bool g_disable_ping_ack = false; grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) { - grpc_slice slice = grpc_slice_malloc(9 + 8); + grpc_slice slice = GRPC_SLICE_MALLOC(9 + 8); uint8_t *p = GRPC_SLICE_START_PTR(slice); *p++ = 0; diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c index 225f15c77c..e0caa50e92 100644 --- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c +++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c @@ -44,7 +44,7 @@ grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code, grpc_transport_one_way_stats *stats) { static const size_t frame_size = 13; - grpc_slice slice = grpc_slice_malloc(frame_size); + grpc_slice slice = GRPC_SLICE_MALLOC(frame_size); stats->framing_bytes += frame_size; uint8_t *p = GRPC_SLICE_START_PTR(slice); diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c index 4f2b827832..e3cd70d3f3 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.c +++ b/src/core/ext/transport/chttp2/transport/frame_settings.c @@ -70,7 +70,7 @@ grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, n += (new[i] != old[i] || (force_mask & (1u << i)) != 0); } - output = grpc_slice_malloc(9 + 6 * n); + output = GRPC_SLICE_MALLOC(9 + 6 * n); p = fill_header(GRPC_SLICE_START_PTR(output), 6 * n, 0); for (i = 0; i < count; i++) { @@ -91,7 +91,7 @@ grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, } grpc_slice grpc_chttp2_settings_ack_create(void) { - grpc_slice output = grpc_slice_malloc(9); + grpc_slice output = GRPC_SLICE_MALLOC(9); fill_header(GRPC_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK); return output; } diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c index b76b6f6f47..8ed72dddca 100644 --- a/src/core/ext/transport/chttp2/transport/frame_window_update.c +++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c @@ -41,7 +41,7 @@ grpc_slice grpc_chttp2_window_update_create( uint32_t id, uint32_t window_update, grpc_transport_one_way_stats *stats) { static const size_t frame_size = 13; - grpc_slice slice = grpc_slice_malloc(frame_size); + grpc_slice slice = GRPC_SLICE_MALLOC(frame_size); stats->header_bytes += frame_size; uint8_t *p = GRPC_SLICE_START_PTR(slice); diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c index b1bc677a7a..8fdd4ee77c 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c +++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c @@ -123,7 +123,7 @@ static void finish_frame(framer_state *st, int is_header_boundary, output before beginning */ static void begin_frame(framer_state *st) { st->header_idx = - grpc_slice_buffer_add_indexed(st->output, grpc_slice_malloc(9)); + grpc_slice_buffer_add_indexed(st->output, GRPC_SLICE_MALLOC(9)); st->output_length_at_start_of_frame = st->output->length; } diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c index 7896c70f9e..d4e89d6a6c 100644 --- a/src/core/ext/transport/cronet/transport/cronet_transport.c +++ b/src/core/ext/transport/cronet/transport/cronet_transport.c @@ -1177,7 +1177,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx, } else if (stream_state->rs.remaining_bytes == 0) { CRONET_LOG(GPR_DEBUG, "read operation complete"); grpc_slice read_data_slice = - grpc_slice_malloc((uint32_t)stream_state->rs.length_field); + GRPC_SLICE_MALLOC((uint32_t)stream_state->rs.length_field); uint8_t *dst_p = GRPC_SLICE_START_PTR(read_data_slice); memcpy(dst_p, stream_state->rs.read_buffer, (size_t)stream_state->rs.length_field); diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c index 22caf24373..d8985268eb 100644 --- a/src/core/lib/channel/connected_channel.c +++ b/src/core/lib/channel/connected_channel.c @@ -128,7 +128,9 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem) { channel_data *cd = (channel_data *)elem->channel_data; - grpc_transport_destroy(exec_ctx, cd->transport); + if (cd->transport) { + grpc_transport_destroy(exec_ctx, cd->transport); + } } static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) { diff --git a/src/core/lib/compression/message_compress.c b/src/core/lib/compression/message_compress.c index 49beb953b0..fd3d1e6fcc 100644 --- a/src/core/lib/compression/message_compress.c +++ b/src/core/lib/compression/message_compress.c @@ -50,7 +50,7 @@ static int zlib_body(grpc_exec_ctx* exec_ctx, z_stream* zs, int r; int flush; size_t i; - grpc_slice outbuf = grpc_slice_malloc(OUTPUT_BLOCK_SIZE); + grpc_slice outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE); const uInt uint_max = ~(uInt)0; GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max); @@ -65,7 +65,7 @@ static int zlib_body(grpc_exec_ctx* exec_ctx, z_stream* zs, do { if (zs->avail_out == 0) { grpc_slice_buffer_add_indexed(output, outbuf); - outbuf = grpc_slice_malloc(OUTPUT_BLOCK_SIZE); + outbuf = GRPC_SLICE_MALLOC(OUTPUT_BLOCK_SIZE); GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max); zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf); zs->next_out = GRPC_SLICE_START_PTR(outbuf); diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c index 9eab1360a4..76946434f0 100644 --- a/src/core/lib/http/httpcli_security_connector.c +++ b/src/core/lib/http/httpcli_security_connector.c @@ -106,9 +106,8 @@ static grpc_security_connector_vtable httpcli_ssl_vtable = { httpcli_ssl_destroy, httpcli_ssl_check_peer}; static grpc_security_status httpcli_ssl_channel_security_connector_create( - grpc_exec_ctx *exec_ctx, const unsigned char *pem_root_certs, - size_t pem_root_certs_size, const char *secure_peer_name, - grpc_channel_security_connector **sc) { + grpc_exec_ctx *exec_ctx, const char *pem_root_certs, + const char *secure_peer_name, grpc_channel_security_connector **sc) { tsi_result result = TSI_OK; grpc_httpcli_ssl_channel_security_connector *c; @@ -126,8 +125,7 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create( c->secure_peer_name = gpr_strdup(secure_peer_name); } result = tsi_create_ssl_client_handshaker_factory( - NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL, - 0, &c->handshaker_factory); + NULL, pem_root_certs, NULL, NULL, 0, &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); @@ -173,10 +171,9 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg, void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint)) { grpc_channel_security_connector *sc = NULL; - const unsigned char *pem_root_certs = NULL; on_done_closure *c = gpr_malloc(sizeof(*c)); - size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); - if (pem_root_certs == NULL || pem_root_certs_size == 0) { + const char *pem_root_certs = grpc_get_default_ssl_roots(); + if (pem_root_certs == NULL) { gpr_log(GPR_ERROR, "Could not get default pem root certs."); on_done(exec_ctx, arg, NULL); gpr_free(c); @@ -186,8 +183,7 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg, c->arg = arg; c->handshake_mgr = grpc_handshake_manager_create(); GPR_ASSERT(httpcli_ssl_channel_security_connector_create( - exec_ctx, pem_root_certs, pem_root_certs_size, host, &sc) == - GRPC_SECURITY_OK); + exec_ctx, pem_root_certs, host, &sc) == GRPC_SECURITY_OK); grpc_channel_security_connector_add_handshakers(exec_ctx, sc, c->handshake_mgr); grpc_handshake_manager_do_handshake( diff --git a/src/core/lib/iomgr/socket_mutator.h b/src/core/lib/iomgr/socket_mutator.h index 2f5b6c248e..28b1710ec4 100644 --- a/src/core/lib/iomgr/socket_mutator.h +++ b/src/core/lib/iomgr/socket_mutator.h @@ -37,6 +37,8 @@ #include <grpc/impl/codegen/grpc_types.h> #include <grpc/support/sync.h> +#include <stdbool.h> + #ifdef __cplusplus extern "C" { #endif diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c index f74aa68793..bdd4dd07af 100644 --- a/src/core/lib/iomgr/tcp_windows.c +++ b/src/core/lib/iomgr/tcp_windows.c @@ -219,7 +219,7 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, tcp->read_slices = read_slices; grpc_slice_buffer_reset_and_unref_internal(exec_ctx, read_slices); - tcp->read_slice = grpc_slice_malloc(8192); + tcp->read_slice = GRPC_SLICE_MALLOC(8192); buffer.len = (ULONG)GRPC_SLICE_LENGTH( tcp->read_slice); // we know slice size fits in 32bit. diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.c b/src/core/lib/security/credentials/ssl/ssl_credentials.c index b63bb6b6e9..7c35ebe684 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.c +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.c @@ -40,28 +40,24 @@ #include <grpc/support/alloc.h> #include <grpc/support/log.h> +#include <grpc/support/string_util.h> // -// Utils +// SSL Channel Credentials. // -static void ssl_copy_key_material(const char *input, unsigned char **output, - size_t *output_size) { - *output_size = strlen(input); - *output = gpr_malloc(*output_size); - memcpy(*output, input, *output_size); +static void ssl_config_pem_key_cert_pair_destroy( + tsi_ssl_pem_key_cert_pair *kp) { + if (kp == NULL) return; + gpr_free((void *)kp->private_key); + gpr_free((void *)kp->cert_chain); } -// -// SSL Channel Credentials. -// - static void ssl_destruct(grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds) { grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; - if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); - if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key); - if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain); + gpr_free(c->config.pem_root_certs); + ssl_config_pem_key_cert_pair_destroy(&c->config.pem_key_cert_pair); } static grpc_security_status ssl_create_security_connector( @@ -102,18 +98,15 @@ static void ssl_build_config(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, grpc_ssl_config *config) { if (pem_root_certs != NULL) { - ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, - &config->pem_root_certs_size); + config->pem_root_certs = gpr_strdup(pem_root_certs); } if (pem_key_cert_pair != NULL) { GPR_ASSERT(pem_key_cert_pair->private_key != NULL); GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL); - ssl_copy_key_material(pem_key_cert_pair->private_key, - &config->pem_private_key, - &config->pem_private_key_size); - ssl_copy_key_material(pem_key_cert_pair->cert_chain, - &config->pem_cert_chain, - &config->pem_cert_chain_size); + config->pem_key_cert_pair.cert_chain = + gpr_strdup(pem_key_cert_pair->cert_chain); + config->pem_key_cert_pair.private_key = + gpr_strdup(pem_key_cert_pair->private_key); } } @@ -143,22 +136,10 @@ static void ssl_server_destruct(grpc_exec_ctx *exec_ctx, grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; size_t i; for (i = 0; i < c->config.num_key_cert_pairs; i++) { - if (c->config.pem_private_keys[i] != NULL) { - gpr_free(c->config.pem_private_keys[i]); - } - if (c->config.pem_cert_chains[i] != NULL) { - gpr_free(c->config.pem_cert_chains[i]); - } - } - if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys); - if (c->config.pem_private_keys_sizes != NULL) { - gpr_free(c->config.pem_private_keys_sizes); - } - if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains); - if (c->config.pem_cert_chains_sizes != NULL) { - gpr_free(c->config.pem_cert_chains_sizes); + ssl_config_pem_key_cert_pair_destroy(&c->config.pem_key_cert_pairs[i]); } - if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs); + gpr_free(c->config.pem_key_cert_pairs); + gpr_free(c->config.pem_root_certs); } static grpc_security_status ssl_server_create_security_connector( @@ -179,30 +160,21 @@ static void ssl_build_server_config( size_t i; config->client_certificate_request = client_certificate_request; if (pem_root_certs != NULL) { - ssl_copy_key_material(pem_root_certs, &config->pem_root_certs, - &config->pem_root_certs_size); + config->pem_root_certs = gpr_strdup(pem_root_certs); } if (num_key_cert_pairs > 0) { GPR_ASSERT(pem_key_cert_pairs != NULL); - config->pem_private_keys = - gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); - config->pem_cert_chains = - gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *)); - config->pem_private_keys_sizes = - gpr_malloc(num_key_cert_pairs * sizeof(size_t)); - config->pem_cert_chains_sizes = - gpr_malloc(num_key_cert_pairs * sizeof(size_t)); + config->pem_key_cert_pairs = + gpr_zalloc(num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair)); } config->num_key_cert_pairs = num_key_cert_pairs; for (i = 0; i < num_key_cert_pairs; i++) { GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL); GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL); - ssl_copy_key_material(pem_key_cert_pairs[i].private_key, - &config->pem_private_keys[i], - &config->pem_private_keys_sizes[i]); - ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain, - &config->pem_cert_chains[i], - &config->pem_cert_chains_sizes[i]); + config->pem_key_cert_pairs[i].cert_chain = + gpr_strdup(pem_key_cert_pairs[i].cert_chain); + config->pem_key_cert_pairs[i].private_key = + gpr_strdup(pem_key_cert_pairs[i].private_key); } } diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c index f526653ffa..1f0daf7325 100644 --- a/src/core/lib/security/transport/client_auth_filter.c +++ b/src/core/lib/security/transport/client_auth_filter.c @@ -343,8 +343,16 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, grpc_channel_element_args *args) { grpc_security_connector *sc = grpc_security_connector_find_in_args(args->channel_args); + if (sc == NULL) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Security connector missing from client auth filter args"); + } grpc_auth_context *auth_context = grpc_find_auth_context_in_args(args->channel_args); + if (auth_context == NULL) { + return GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Auth context missing from client auth filter args"); + } /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; @@ -353,8 +361,6 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, handle the case that there's no 'next' filter to call on the up or down path */ GPR_ASSERT(!args->is_last); - GPR_ASSERT(sc != NULL); - GPR_ASSERT(auth_context != NULL); /* initialize members */ chand->security_connector = diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c index 24da949e48..0d5c7432c6 100644 --- a/src/core/lib/security/transport/secure_endpoint.c +++ b/src/core/lib/security/transport/secure_endpoint.c @@ -130,7 +130,7 @@ static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur, uint8_t **end) { grpc_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); - ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + ep->read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer); *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer); } @@ -252,7 +252,7 @@ static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur, uint8_t **end) { grpc_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer); - ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + ep->write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer); *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer); } @@ -415,8 +415,8 @@ grpc_endpoint *grpc_secure_endpoint_create( grpc_slice_buffer_add(&ep->leftover_bytes, grpc_slice_ref_internal(leftover_slices[i])); } - ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); - ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + ep->write_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); + ep->read_staging_buffer = GRPC_SLICE_MALLOC(STAGING_BUFFER_SIZE); grpc_slice_buffer_init(&ep->output_buffer); grpc_slice_buffer_init(&ep->source_buffer); ep->read_buffer = NULL; diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c index b15196e677..30431a4e4a 100644 --- a/src/core/lib/security/transport/security_connector.c +++ b/src/core/lib/security/transport/security_connector.c @@ -78,9 +78,8 @@ void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) { /* Defines the cipher suites that we accept by default. All these cipher suites are compliant with HTTP2. */ -#define GRPC_SSL_CIPHER_SUITES \ - "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \ - "SHA384:ECDHE-RSA-AES256-GCM-SHA384" +#define GRPC_SSL_CIPHER_SUITES \ + "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384" static gpr_once cipher_suites_once = GPR_ONCE_INIT; static const char *cipher_suites = NULL; @@ -695,6 +694,7 @@ static grpc_security_connector_vtable ssl_channel_vtable = { static grpc_security_connector_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_check_peer}; +/* returns a NULL terminated slice. */ static grpc_slice compute_default_pem_root_certs_once(void) { grpc_slice result = grpc_empty_slice(); @@ -703,7 +703,7 @@ static grpc_slice compute_default_pem_root_certs_once(void) { gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); if (default_root_certs_path != NULL) { GRPC_LOG_IF_ERROR("load_file", - grpc_load_file(default_root_certs_path, 0, &result)); + grpc_load_file(default_root_certs_path, 1, &result)); gpr_free(default_root_certs_path); } @@ -714,15 +714,18 @@ static grpc_slice compute_default_pem_root_certs_once(void) { ovrd_res = ssl_roots_override_cb(&pem_root_certs); if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) { GPR_ASSERT(pem_root_certs != NULL); - result = grpc_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free); + result = grpc_slice_from_copied_buffer( + pem_root_certs, + strlen(pem_root_certs) + 1); // NULL terminator. } + gpr_free(pem_root_certs); } /* Fall back to installed certs if needed. */ if (GRPC_SLICE_IS_EMPTY(result) && ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) { GRPC_LOG_IF_ERROR("load_file", - grpc_load_file(installed_roots_path, 0, &result)); + grpc_load_file(installed_roots_path, 1, &result)); } return result; } @@ -762,13 +765,14 @@ get_tsi_client_certificate_request_type( } } -size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { +const char *grpc_get_default_ssl_roots(void) { /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in loading all the roots once for the lifetime of the process. */ static gpr_once once = GPR_ONCE_INIT; gpr_once_init(&once, init_default_pem_root_certs); - *pem_root_certs = GRPC_SLICE_START_PTR(default_pem_root_certs); - return GRPC_SLICE_LENGTH(default_pem_root_certs); + return GRPC_SLICE_IS_EMPTY(default_pem_root_certs) + ? NULL + : (const char *)GRPC_SLICE_START_PTR(default_pem_root_certs); } grpc_security_status grpc_ssl_channel_security_connector_create( @@ -776,22 +780,16 @@ grpc_security_status grpc_ssl_channel_security_connector_create( const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const unsigned char **alpn_protocol_strings = + const char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); - unsigned char *alpn_protocol_string_lengths = - gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_channel_security_connector *c; size_t i; - const unsigned char *pem_root_certs; - size_t pem_root_certs_size; + const char *pem_root_certs; char *port; for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = - (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); - alpn_protocol_string_lengths[i] = - (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); + alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); } if (config == NULL || target_name == NULL) { @@ -799,14 +797,13 @@ grpc_security_status grpc_ssl_channel_security_connector_create( goto error; } if (config->pem_root_certs == NULL) { - pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); - if (pem_root_certs == NULL || pem_root_certs_size == 0) { + pem_root_certs = grpc_get_default_ssl_roots(); + if (pem_root_certs == NULL) { gpr_log(GPR_ERROR, "Could not get default pem root certs."); goto error; } } else { pem_root_certs = config->pem_root_certs; - pem_root_certs_size = config->pem_root_certs_size; } c = gpr_zalloc(sizeof(grpc_ssl_channel_security_connector)); @@ -823,11 +820,12 @@ grpc_security_status grpc_ssl_channel_security_connector_create( if (overridden_target_name != NULL) { c->overridden_target_name = gpr_strdup(overridden_target_name); } + + bool has_key_cert_pair = config->pem_key_cert_pair.private_key != NULL && + config->pem_key_cert_pair.cert_chain != NULL; result = tsi_create_ssl_client_handshaker_factory( - config->pem_private_key, config->pem_private_key_size, - config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs, - pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings, - alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols, + has_key_cert_pair ? &config->pem_key_cert_pair : NULL, pem_root_certs, + ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", @@ -838,12 +836,10 @@ grpc_security_status grpc_ssl_channel_security_connector_create( } *sc = &c->base; gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; error: gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_ERROR; } @@ -851,19 +847,14 @@ grpc_security_status grpc_ssl_server_security_connector_create( grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const unsigned char **alpn_protocol_strings = + const char **alpn_protocol_strings = gpr_malloc(sizeof(const char *) * num_alpn_protocols); - unsigned char *alpn_protocol_string_lengths = - gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_server_security_connector *c; size_t i; for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = - (const unsigned char *)grpc_chttp2_get_alpn_version_index(i); - alpn_protocol_string_lengths[i] = - (unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i)); + alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); } if (config == NULL || config->num_key_cert_pairs == 0) { @@ -876,15 +867,11 @@ grpc_security_status grpc_ssl_server_security_connector_create( c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.base.vtable = &ssl_server_vtable; result = tsi_create_ssl_server_handshaker_factory_ex( - (const unsigned char **)config->pem_private_keys, - config->pem_private_keys_sizes, - (const unsigned char **)config->pem_cert_chains, - config->pem_cert_chains_sizes, config->num_key_cert_pairs, - config->pem_root_certs, config->pem_root_certs_size, - get_tsi_client_certificate_request_type( - config->client_certificate_request), - ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_string_lengths, - (uint16_t)num_alpn_protocols, &c->handshaker_factory); + config->pem_key_cert_pairs, config->num_key_cert_pairs, + config->pem_root_certs, get_tsi_client_certificate_request_type( + config->client_certificate_request), + ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, + &c->handshaker_factory); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", tsi_result_to_string(result)); @@ -895,11 +882,9 @@ grpc_security_status grpc_ssl_server_security_connector_create( c->base.add_handshakers = ssl_server_add_handshakers; *sc = &c->base; gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_OK; error: gpr_free((void *)alpn_protocol_strings); - gpr_free(alpn_protocol_string_lengths); return GRPC_SECURITY_ERROR; } diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h index cf56cb3183..d74f6739c0 100644 --- a/src/core/lib/security/transport/security_connector.h +++ b/src/core/lib/security/transport/security_connector.h @@ -34,11 +34,14 @@ #ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H +#include <stdbool.h> + #include <grpc/grpc_security.h> #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/tsi/ssl_transport_security.h" #include "src/core/tsi/transport_security_interface.h" /* --- status enum. --- */ @@ -184,13 +187,10 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create( void); /* Config for ssl clients. */ + typedef struct { - unsigned char *pem_private_key; - size_t pem_private_key_size; - unsigned char *pem_cert_chain; - size_t pem_cert_chain_size; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; + tsi_ssl_pem_key_cert_pair pem_key_cert_pair; + char *pem_root_certs; } grpc_ssl_config; /* Creates an SSL channel_security_connector. @@ -211,21 +211,17 @@ grpc_security_status grpc_ssl_channel_security_connector_create( const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc); -/* Gets the default ssl roots. */ -size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); +/* Gets the default ssl roots. Returns NULL if not found. */ +const char *grpc_get_default_ssl_roots(void); /* Exposed for TESTING ONLY!. */ grpc_slice grpc_get_default_ssl_roots_for_testing(void); /* Config for ssl servers. */ typedef struct { - unsigned char **pem_private_keys; - size_t *pem_private_keys_sizes; - unsigned char **pem_cert_chains; - size_t *pem_cert_chains_sizes; + tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs; size_t num_key_cert_pairs; - unsigned char *pem_root_certs; - size_t pem_root_certs_size; + char *pem_root_certs; grpc_ssl_client_certificate_request_type client_certificate_request; } grpc_ssl_server_config; diff --git a/src/core/lib/slice/b64.c b/src/core/lib/slice/b64.c index 2007cc4810..d9091646e0 100644 --- a/src/core/lib/slice/b64.c +++ b/src/core/lib/slice/b64.c @@ -202,7 +202,7 @@ static int decode_group(const unsigned char *codes, size_t num_codes, grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx *exec_ctx, const char *b64, size_t b64_len, int url_safe) { - grpc_slice result = grpc_slice_malloc(b64_len); + grpc_slice result = GRPC_SLICE_MALLOC(b64_len); unsigned char *current = GRPC_SLICE_START_PTR(result); size_t result_size = 0; unsigned char codes[4]; diff --git a/src/core/lib/slice/percent_encoding.c b/src/core/lib/slice/percent_encoding.c index c76c58d371..a77c69763f 100644 --- a/src/core/lib/slice/percent_encoding.c +++ b/src/core/lib/slice/percent_encoding.c @@ -71,7 +71,7 @@ grpc_slice grpc_percent_encode_slice(grpc_slice slice, return grpc_slice_ref_internal(slice); } // second pass: actually encode - grpc_slice out = grpc_slice_malloc(output_length); + grpc_slice out = GRPC_SLICE_MALLOC(output_length); uint8_t *q = GRPC_SLICE_START_PTR(out); for (p = slice_start; p < slice_end; p++) { if (is_unreserved_character(*p, unreserved_bytes)) { @@ -125,7 +125,7 @@ bool grpc_strict_percent_decode_slice(grpc_slice slice_in, return true; } p = GRPC_SLICE_START_PTR(slice_in); - *slice_out = grpc_slice_malloc(out_length); + *slice_out = GRPC_SLICE_MALLOC(out_length); uint8_t *q = GRPC_SLICE_START_PTR(*slice_out); while (p != in_end) { if (*p == '%') { @@ -163,7 +163,7 @@ grpc_slice grpc_permissive_percent_decode_slice(grpc_slice slice_in) { return grpc_slice_ref_internal(slice_in); } p = GRPC_SLICE_START_PTR(slice_in); - grpc_slice out = grpc_slice_malloc(out_length); + grpc_slice out = GRPC_SLICE_MALLOC(out_length); uint8_t *q = GRPC_SLICE_START_PTR(out); while (p != in_end) { if (*p == '%') { diff --git a/src/core/lib/slice/slice.c b/src/core/lib/slice/slice.c index a2fcbbdbdf..b90738fd1a 100644 --- a/src/core/lib/slice/slice.c +++ b/src/core/lib/slice/slice.c @@ -55,6 +55,13 @@ grpc_slice grpc_empty_slice(void) { return out; } +grpc_slice grpc_slice_copy(grpc_slice s) { + grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s)); + memcpy(GRPC_SLICE_START_PTR(out), GRPC_SLICE_START_PTR(s), + GRPC_SLICE_LENGTH(s)); + return out; +} + grpc_slice grpc_slice_ref_internal(grpc_slice slice) { if (slice.refcount) { slice.refcount->vtable->ref(slice.refcount); @@ -198,7 +205,7 @@ grpc_slice grpc_slice_new_with_len(void *p, size_t len, grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t length) { if (length == 0) return grpc_empty_slice(); - grpc_slice slice = grpc_slice_malloc(length); + grpc_slice slice = GRPC_SLICE_MALLOC(length); memcpy(GRPC_SLICE_START_PTR(slice), source, length); return slice; } @@ -228,35 +235,42 @@ static const grpc_slice_refcount_vtable malloc_vtable = { malloc_ref, malloc_unref, grpc_slice_default_eq_impl, grpc_slice_default_hash_impl}; +grpc_slice grpc_slice_malloc_large(size_t length) { + grpc_slice slice; + + /* Memory layout used by the slice created here: + + +-----------+----------------------------------------------------------+ + | refcount | bytes | + +-----------+----------------------------------------------------------+ + + refcount is a malloc_refcount + bytes is an array of bytes of the requested length + Both parts are placed in the same allocation returned from gpr_malloc */ + malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); + + /* Initial refcount on rc is 1 - and it's up to the caller to release + this reference. */ + gpr_ref_init(&rc->refs, 1); + + rc->base.vtable = &malloc_vtable; + rc->base.sub_refcount = &rc->base; + + /* Build up the slice to be returned. */ + /* The slices refcount points back to the allocated block. */ + slice.refcount = &rc->base; + /* The data bytes are placed immediately after the refcount struct */ + slice.data.refcounted.bytes = (uint8_t *)(rc + 1); + /* And the length of the block is set to the requested length */ + slice.data.refcounted.length = length; + return slice; +} + grpc_slice grpc_slice_malloc(size_t length) { grpc_slice slice; if (length > sizeof(slice.data.inlined.bytes)) { - /* Memory layout used by the slice created here: - - +-----------+----------------------------------------------------------+ - | refcount | bytes | - +-----------+----------------------------------------------------------+ - - refcount is a malloc_refcount - bytes is an array of bytes of the requested length - Both parts are placed in the same allocation returned from gpr_malloc */ - malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); - - /* Initial refcount on rc is 1 - and it's up to the caller to release - this reference. */ - gpr_ref_init(&rc->refs, 1); - - rc->base.vtable = &malloc_vtable; - rc->base.sub_refcount = &rc->base; - - /* Build up the slice to be returned. */ - /* The slices refcount points back to the allocated block. */ - slice.refcount = &rc->base; - /* The data bytes are placed immediately after the refcount struct */ - slice.data.refcounted.bytes = (uint8_t *)(rc + 1); - /* And the length of the block is set to the requested length */ - slice.data.refcounted.length = length; + return grpc_slice_malloc_large(length); } else { /* small slice: just inline the data */ slice.refcount = NULL; @@ -306,7 +320,8 @@ grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) { return subset; } -grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { +grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice *source, size_t split, + grpc_slice_ref_whom ref_whom) { grpc_slice tail; if (source->refcount == NULL) { @@ -320,28 +335,46 @@ grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { } else { size_t tail_length = source->data.refcounted.length - split; GPR_ASSERT(source->data.refcounted.length >= split); - if (tail_length < sizeof(tail.data.inlined.bytes)) { + if (tail_length < sizeof(tail.data.inlined.bytes) && + ref_whom != GRPC_SLICE_REF_TAIL) { /* Copy out the bytes - it'll be cheaper than refcounting */ tail.refcount = NULL; tail.data.inlined.length = (uint8_t)tail_length; memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split, tail_length); + source->refcount = source->refcount->sub_refcount; } else { /* Build the result */ - tail.refcount = source->refcount->sub_refcount; - /* Bump the refcount */ - tail.refcount->vtable->ref(tail.refcount); + switch (ref_whom) { + case GRPC_SLICE_REF_TAIL: + tail.refcount = source->refcount->sub_refcount; + source->refcount = &noop_refcount; + break; + case GRPC_SLICE_REF_HEAD: + tail.refcount = &noop_refcount; + source->refcount = source->refcount->sub_refcount; + break; + case GRPC_SLICE_REF_BOTH: + tail.refcount = source->refcount->sub_refcount; + source->refcount = source->refcount->sub_refcount; + /* Bump the refcount */ + tail.refcount->vtable->ref(tail.refcount); + break; + } /* Point into the source array */ tail.data.refcounted.bytes = source->data.refcounted.bytes + split; tail.data.refcounted.length = tail_length; } - source->refcount = source->refcount->sub_refcount; source->data.refcounted.length = split; } return tail; } +grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { + return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH); +} + grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) { grpc_slice head; @@ -459,7 +492,7 @@ int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) { } grpc_slice grpc_slice_dup(grpc_slice a) { - grpc_slice copy = grpc_slice_malloc(GRPC_SLICE_LENGTH(a)); + grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a)); memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a), GRPC_SLICE_LENGTH(a)); return copy; diff --git a/src/core/lib/slice/slice_buffer.c b/src/core/lib/slice/slice_buffer.c index c96b9c3b28..e8d41ca0f7 100644 --- a/src/core/lib/slice/slice_buffer.c +++ b/src/core/lib/slice/slice_buffer.c @@ -253,16 +253,18 @@ void grpc_slice_buffer_move_into(grpc_slice_buffer *src, src->length = 0; } -void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, - grpc_slice_buffer *dst) { - size_t output_len = dst->length + n; - size_t new_input_len = src->length - n; +static void slice_buffer_move_first_maybe_ref(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst, + bool incref) { GPR_ASSERT(src->length >= n); if (src->length == n) { grpc_slice_buffer_move_into(src, dst); return; } + size_t output_len = dst->length + n; + size_t new_input_len = src->length - n; + while (src->count > 0) { grpc_slice slice = grpc_slice_buffer_take_first(src); size_t slice_len = GRPC_SLICE_LENGTH(slice); @@ -272,11 +274,18 @@ void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, } else if (n == slice_len) { grpc_slice_buffer_add(dst, slice); break; - } else { /* n < slice_len */ - grpc_slice_buffer_undo_take_first(src, grpc_slice_split_tail(&slice, n)); + } else if (incref) { /* n < slice_len */ + grpc_slice_buffer_undo_take_first( + src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_BOTH)); GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n); grpc_slice_buffer_add(dst, slice); break; + } else { /* n < slice_len */ + grpc_slice_buffer_undo_take_first( + src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_TAIL)); + GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n); + grpc_slice_buffer_add_indexed(dst, slice); + break; } } GPR_ASSERT(dst->length == output_len); @@ -284,6 +293,16 @@ void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, GPR_ASSERT(src->count > 0); } +void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst) { + slice_buffer_move_first_maybe_ref(src, n, dst, true); +} + +void grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst) { + slice_buffer_move_first_maybe_ref(src, n, dst, false); +} + void grpc_slice_buffer_move_first_into_buffer(grpc_exec_ctx *exec_ctx, grpc_slice_buffer *src, size_t n, void *dst) { diff --git a/src/core/lib/support/atomic.h b/src/core/lib/support/atomic.h new file mode 100644 index 0000000000..2226189b68 --- /dev/null +++ b/src/core/lib/support/atomic.h @@ -0,0 +1,45 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_ATOMIC_H +#define GRPC_CORE_LIB_SUPPORT_ATOMIC_H + +#include <grpc/support/port_platform.h> + +#ifdef GPR_HAS_CXX11_ATOMIC +#include "src/core/lib/support/atomic_with_std.h" +#else +#include "src/core/lib/support/atomic_with_atm.h" +#endif + +#endif /* GRPC_CORE_LIB_SUPPORT_ATOMIC_H */ diff --git a/src/core/lib/support/atomic_with_atm.h b/src/core/lib/support/atomic_with_atm.h new file mode 100644 index 0000000000..55727f1dee --- /dev/null +++ b/src/core/lib/support/atomic_with_atm.h @@ -0,0 +1,70 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_ATM_H +#define GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_ATM_H + +#include <grpc/support/atm.h> + +namespace grpc_core { + +enum MemoryOrderRelaxed { memory_order_relaxed }; + +template <class T> +class atomic; + +template <> +class atomic<bool> { + public: + atomic() { gpr_atm_no_barrier_store(&x_, static_cast<gpr_atm>(false)); } + explicit atomic(bool x) { + gpr_atm_no_barrier_store(&x_, static_cast<gpr_atm>(x)); + } + + bool compare_exchange_strong(bool& expected, bool update, MemoryOrderRelaxed, + MemoryOrderRelaxed) { + if (!gpr_atm_no_barrier_cas(&x_, static_cast<gpr_atm>(expected), + static_cast<gpr_atm>(update))) { + expected = gpr_atm_no_barrier_load(&x_) != 0; + return false; + } + return true; + } + + private: + gpr_atm x_; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_ATM_H */ diff --git a/src/core/lib/support/atomic_with_std.h b/src/core/lib/support/atomic_with_std.h new file mode 100644 index 0000000000..7e9c19efe8 --- /dev/null +++ b/src/core/lib/support/atomic_with_std.h @@ -0,0 +1,48 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_STD_H +#define GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_STD_H + +#include <atomic> + +namespace grpc_core { + +template <class T> +using atomic = std::atomic<T>; + +typedef std::memory_order memory_order; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SUPPORT_ATOMIC_WITH_STD_H */ diff --git a/src/core/lib/support/avl.c b/src/core/lib/support/avl.c index acf8fd5a55..ffa10c1e4f 100644 --- a/src/core/lib/support/avl.c +++ b/src/core/lib/support/avl.c @@ -205,8 +205,8 @@ static gpr_avl_node *rebalance(const gpr_avl_vtable *vtable, void *key, } } -static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key, void *value) { +static gpr_avl_node *add_key(const gpr_avl_vtable *vtable, gpr_avl_node *node, + void *key, void *value) { long cmp; if (node == NULL) { return new_node(key, value, NULL, NULL); @@ -217,17 +217,17 @@ static gpr_avl_node *add(const gpr_avl_vtable *vtable, gpr_avl_node *node, } else if (cmp > 0) { return rebalance( vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), - add(vtable, node->left, key, value), ref_node(node->right)); + add_key(vtable, node->left, key, value), ref_node(node->right)); } else { return rebalance(vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), ref_node(node->left), - add(vtable, node->right, key, value)); + add_key(vtable, node->right, key, value)); } } gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value) { gpr_avl_node *old_root = avl.root; - avl.root = add(avl.vtable, avl.root, key, value); + avl.root = add_key(avl.vtable, avl.root, key, value); assert_invariants(avl.root); unref_node(avl.vtable, old_root); return avl; @@ -247,8 +247,8 @@ static gpr_avl_node *in_order_tail(gpr_avl_node *node) { return node; } -static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node, - void *key) { +static gpr_avl_node *remove_key(const gpr_avl_vtable *vtable, + gpr_avl_node *node, void *key) { long cmp; if (node == NULL) { return NULL; @@ -263,27 +263,27 @@ static gpr_avl_node *remove(const gpr_avl_vtable *vtable, gpr_avl_node *node, gpr_avl_node *h = in_order_head(node->right); return rebalance(vtable, vtable->copy_key(h->key), vtable->copy_value(h->value), ref_node(node->left), - remove(vtable, node->right, h->key)); + remove_key(vtable, node->right, h->key)); } else { gpr_avl_node *h = in_order_tail(node->left); return rebalance( vtable, vtable->copy_key(h->key), vtable->copy_value(h->value), - remove(vtable, node->left, h->key), ref_node(node->right)); + remove_key(vtable, node->left, h->key), ref_node(node->right)); } } else if (cmp > 0) { - return rebalance(vtable, vtable->copy_key(node->key), - vtable->copy_value(node->value), - remove(vtable, node->left, key), ref_node(node->right)); + return rebalance( + vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), + remove_key(vtable, node->left, key), ref_node(node->right)); } else { return rebalance(vtable, vtable->copy_key(node->key), vtable->copy_value(node->value), ref_node(node->left), - remove(vtable, node->right, key)); + remove_key(vtable, node->right, key)); } } gpr_avl gpr_avl_remove(gpr_avl avl, void *key) { gpr_avl_node *old_root = avl.root; - avl.root = remove(avl.vtable, avl.root, key); + avl.root = remove_key(avl.vtable, avl.root, key); assert_invariants(avl.root); unref_node(avl.vtable, old_root); return avl; diff --git a/src/core/lib/support/memory.h b/src/core/lib/support/memory.h new file mode 100644 index 0000000000..6eff94eff7 --- /dev/null +++ b/src/core/lib/support/memory.h @@ -0,0 +1,74 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_CORE_LIB_SUPPORT_MEMORY_H +#define GRPC_CORE_LIB_SUPPORT_MEMORY_H + +#include <grpc/support/alloc.h> + +#include <memory> +#include <utility> + +namespace grpc_core { + +// Alternative to new, since we cannot use it (for fear of libstdc++) +template <typename T, typename... Args> +inline T* New(Args&&... args) { + void* p = gpr_malloc(sizeof(T)); + return new (p) T(std::forward<Args>(args)...); +} + +// Alternative to delete, since we cannot use it (for fear of libstdc++) +template <typename T> +inline void Delete(T* p) { + p->~T(); + gpr_free(p); +} + +template <typename T> +class DefaultDelete { + public: + void operator()(T* p) { Delete(p); } +}; + +template <typename T, typename Deleter = DefaultDelete<T>> +using UniquePtr = std::unique_ptr<T, Deleter>; + +template <typename T, typename... Args> +inline UniquePtr<T> MakeUnique(Args&&... args) { + return UniquePtr<T>(New<T>(std::forward<Args>(args)...)); +} + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_SUPPORT_MEMORY_H */ diff --git a/src/core/lib/surface/byte_buffer_reader.c b/src/core/lib/surface/byte_buffer_reader.c index 1a6ccdaddb..539b014278 100644 --- a/src/core/lib/surface/byte_buffer_reader.c +++ b/src/core/lib/surface/byte_buffer_reader.c @@ -124,7 +124,7 @@ grpc_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) { grpc_slice in_slice; size_t bytes_read = 0; const size_t input_size = grpc_byte_buffer_length(reader->buffer_out); - grpc_slice out_slice = grpc_slice_malloc(input_size); + grpc_slice out_slice = GRPC_SLICE_MALLOC(input_size); uint8_t *const outbuf = GRPC_SLICE_START_PTR(out_slice); /* just an alias */ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.cc index 82428c42c0..88f4eaac08 100644 --- a/src/core/lib/surface/lame_client.c +++ b/src/core/lib/surface/lame_client.cc @@ -31,39 +31,50 @@ * */ -#include "src/core/lib/surface/lame_client.h" - #include <grpc/grpc.h> #include <string.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> + +#include "src/core/lib/support/atomic.h" + +extern "C" { #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/lame_client.h" #include "src/core/lib/transport/static_metadata.h" +} -typedef struct { +namespace grpc_core { + +namespace { + +struct CallData { grpc_linked_mdelem status; grpc_linked_mdelem details; - gpr_atm filled_metadata; -} call_data; + grpc_core::atomic<bool> filled_metadata; +}; -typedef struct { +struct ChannelData { grpc_status_code error_code; const char *error_message; -} channel_data; +}; static void fill_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_metadata_batch *mdb) { - call_data *calld = elem->call_data; - if (!gpr_atm_no_barrier_cas(&calld->filled_metadata, 0, 1)) { + CallData *calld = static_cast<CallData *>(elem->call_data); + bool expected = false; + if (!calld->filled_metadata.compare_exchange_strong( + expected, true, grpc_core::memory_order_relaxed, + grpc_core::memory_order_relaxed)) { return; } - channel_data *chand = elem->channel_data; + ChannelData *chand = static_cast<ChannelData *>(elem->channel_data); char tmp[GPR_LTOA_MIN_BUFSIZE]; gpr_ltoa(chand->error_code, tmp); calld->status.md = grpc_mdelem_from_slices( @@ -83,7 +94,6 @@ static void fill_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, 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) { fill_metadata(exec_ctx, elem, op->payload->recv_initial_metadata.recv_initial_metadata); @@ -127,8 +137,6 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx, static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, const grpc_call_element_args *args) { - call_data *calld = elem->call_data; - gpr_atm_no_barrier_store(&calld->filled_metadata, 0); return GRPC_ERROR_NONE; } @@ -149,18 +157,22 @@ static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx, 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_batch, - lame_start_transport_op, - sizeof(call_data), - init_call_elem, +} // namespace + +} // namespace grpc_core + +extern "C" const grpc_channel_filter grpc_lame_filter = { + grpc_core::lame_start_transport_stream_op_batch, + grpc_core::lame_start_transport_op, + sizeof(grpc_core::CallData), + grpc_core::init_call_elem, grpc_call_stack_ignore_set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - lame_get_peer, - lame_get_channel_info, + grpc_core::destroy_call_elem, + sizeof(grpc_core::ChannelData), + grpc_core::init_channel_elem, + grpc_core::destroy_channel_elem, + grpc_core::lame_get_peer, + grpc_core::lame_get_channel_info, "lame-client", }; @@ -171,7 +183,6 @@ grpc_channel *grpc_lame_client_channel_create(const char *target, const char *error_message) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_channel_element *elem; - channel_data *chand; grpc_channel *channel = grpc_channel_create(&exec_ctx, target, NULL, GRPC_CLIENT_LAME_CHANNEL, NULL); elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0); @@ -180,7 +191,7 @@ grpc_channel *grpc_lame_client_channel_create(const char *target, "error_message=%s)", 3, (target, (int)error_code, error_message)); GPR_ASSERT(elem->filter == &grpc_lame_filter); - chand = (channel_data *)elem->channel_data; + auto chand = static_cast<grpc_core::ChannelData *>(elem->channel_data); chand->error_code = error_code; chand->error_message = error_message; grpc_exec_ctx_finish(&exec_ctx); diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c index 3793845559..cddc595e4c 100644 --- a/src/core/lib/surface/version.c +++ b/src/core/lib/surface/version.c @@ -38,4 +38,4 @@ const char *grpc_version_string(void) { return "4.0.0-dev"; } -const char *grpc_g_stands_for(void) { return "gentle"; } +const char *grpc_g_stands_for(void) { return "gregarious"; } diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c index 822fad51cb..1836beefc4 100644 --- a/src/core/tsi/fake_transport_security.c +++ b/src/core/tsi/fake_transport_security.c @@ -499,6 +499,7 @@ static const tsi_handshaker_vtable handshaker_vtable = { fake_handshaker_extract_peer, fake_handshaker_create_frame_protector, fake_handshaker_destroy, + NULL, }; tsi_handshaker *tsi_create_fake_handshaker(int is_client) { diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c index 5f4705db92..e1d634a1fa 100644 --- a/src/core/tsi/ssl_transport_security.c +++ b/src/core/tsi/ssl_transport_security.c @@ -479,9 +479,9 @@ static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes, } /* 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) { +static tsi_result ssl_ctx_use_certificate_chain(SSL_CTX *context, + const char *pem_cert_chain, + size_t pem_cert_chain_size) { tsi_result result = TSI_OK; X509 *certificate = NULL; BIO *pem; @@ -522,8 +522,7 @@ static tsi_result ssl_ctx_use_certificate_chain( } /* 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, +static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, const char *pem_key, size_t pem_key_size) { tsi_result result = TSI_OK; EVP_PKEY *private_key = NULL; @@ -549,9 +548,11 @@ static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, /* 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) { +static tsi_result ssl_ctx_load_verification_certs(SSL_CTX *context, + const 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; @@ -618,24 +619,25 @@ static tsi_result ssl_ctx_load_verification_certs( /* 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) { + SSL_CTX *context, const tsi_ssl_pem_key_cert_pair *key_cert_pair, + 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 (key_cert_pair != NULL) { + if (key_cert_pair->cert_chain != NULL) { + result = ssl_ctx_use_certificate_chain(context, key_cert_pair->cert_chain, + strlen(key_cert_pair->cert_chain)); + 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 (key_cert_pair->private_key != NULL) { + result = ssl_ctx_use_private_key(context, key_cert_pair->private_key, + strlen(key_cert_pair->private_key)); + 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)) { @@ -656,13 +658,12 @@ static tsi_result populate_ssl_context( } /* 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) { +static tsi_result extract_x509_subject_names_from_pem_cert(const char *pem_cert, + 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); + pem = BIO_new_mem_buf((void *)pem_cert, (int)strlen(pem_cert)); if (pem == NULL) return TSI_OUT_OF_RESOURCES; cert = PEM_read_bio_X509(pem, NULL, NULL, ""); @@ -679,8 +680,7 @@ static tsi_result extract_x509_subject_names_from_pem_cert( /* 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, + const char **alpn_protocols, uint16_t num_alpn_protocols, unsigned char **protocol_name_list, size_t *protocol_name_list_length) { uint16_t i; unsigned char *current; @@ -688,19 +688,21 @@ static tsi_result build_alpn_protocol_name_list( *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."); + size_t length = alpn_protocols[i] == NULL ? 0 : strlen(alpn_protocols[i]); + if (length == 0 || length > 255) { + gpr_log(GPR_ERROR, "Invalid protocol name length: %d.", (int)length); return TSI_INVALID_ARGUMENT; } - *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1; + *protocol_name_list_length += length + 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]; + size_t length = strlen(alpn_protocols[i]); + *(current++) = (uint8_t)length; /* max checked above. */ + memcpy(current, alpn_protocols[i], length); + current += length; } /* Safety check. */ if ((current < *protocol_name_list) || @@ -1040,6 +1042,7 @@ static const tsi_handshaker_vtable handshaker_vtable = { ssl_handshaker_extract_peer, ssl_handshaker_create_frame_protector, ssl_handshaker_destroy, + NULL, }; /* --- tsi_ssl_handshaker_factory common methods. --- */ @@ -1280,11 +1283,9 @@ static int server_handshaker_factory_npn_advertised_callback( /* --- 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, + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pair, + const char *pem_root_certs, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, tsi_ssl_client_handshaker_factory **factory) { SSL_CTX *ssl_context = NULL; tsi_ssl_client_handshaker_factory *impl = NULL; @@ -1307,20 +1308,19 @@ tsi_result tsi_create_ssl_client_handshaker_factory( do { result = - populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size, - pem_cert_chain, pem_cert_chain_size, cipher_list); + populate_ssl_context(ssl_context, pem_key_cert_pair, cipher_suites); if (result != TSI_OK) break; result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs, - pem_root_certs_size, NULL); + strlen(pem_root_certs), 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); + result = build_alpn_protocol_name_list(alpn_protocols, 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)); @@ -1352,34 +1352,24 @@ tsi_result tsi_create_ssl_client_handshaker_factory( } 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, + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, + int force_client_auth, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, tsi_ssl_server_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, + pem_key_cert_pairs, num_key_cert_pairs, pem_client_root_certs, 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); + cipher_suites, alpn_protocols, 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, + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, 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_server_handshaker_factory **factory) { + const char *cipher_suites, const char **alpn_protocols, + uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory) { tsi_ssl_server_handshaker_factory *impl = NULL; tsi_result result = TSI_OK; size_t i = 0; @@ -1388,33 +1378,32 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex( if (factory == NULL) return TSI_INVALID_ARGUMENT; *factory = NULL; - if (key_cert_pair_count == 0 || pem_private_keys == NULL || - pem_cert_chains == NULL) { + if (num_key_cert_pairs == 0 || pem_key_cert_pairs == NULL) { return TSI_INVALID_ARGUMENT; } impl = gpr_zalloc(sizeof(*impl)); - impl->ssl_contexts = gpr_zalloc(key_cert_pair_count * sizeof(SSL_CTX *)); + impl->ssl_contexts = gpr_zalloc(num_key_cert_pairs * sizeof(SSL_CTX *)); impl->ssl_context_x509_subject_names = - gpr_zalloc(key_cert_pair_count * sizeof(tsi_peer)); + gpr_zalloc(num_key_cert_pairs * sizeof(tsi_peer)); if (impl->ssl_contexts == NULL || impl->ssl_context_x509_subject_names == NULL) { tsi_ssl_server_handshaker_factory_destroy(impl); return TSI_OUT_OF_RESOURCES; } - impl->ssl_context_count = key_cert_pair_count; + impl->ssl_context_count = num_key_cert_pairs; 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); + result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols, + &impl->alpn_protocol_list, + &impl->alpn_protocol_list_length); if (result != TSI_OK) { tsi_ssl_server_handshaker_factory_destroy(impl); return result; } } - for (i = 0; i < key_cert_pair_count; i++) { + for (i = 0; i < num_key_cert_pairs; i++) { do { impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method()); if (impl->ssl_contexts[i] == NULL) { @@ -1422,16 +1411,15 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex( 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); + result = populate_ssl_context(impl->ssl_contexts[i], + &pem_key_cert_pairs[i], cipher_suites); 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); + strlen(pem_client_root_certs), &root_names); if (result != TSI_OK) { gpr_log(GPR_ERROR, "Invalid verification certs."); break; @@ -1464,7 +1452,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex( } result = extract_x509_subject_names_from_pem_cert( - pem_cert_chains[i], pem_cert_chains_sizes[i], + pem_key_cert_pairs[i].cert_chain, &impl->ssl_context_x509_subject_names[i]); if (result != TSI_OK) break; diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h index 48dcaec121..3117571d9f 100644 --- a/src/core/tsi/ssl_transport_security.h +++ b/src/core/tsi/ssl_transport_security.h @@ -60,27 +60,32 @@ extern "C" { typedef struct tsi_ssl_client_handshaker_factory tsi_ssl_client_handshaker_factory; +/* Object that holds a private key / certificate chain pair in PEM format. */ +typedef struct { + /* private_key is the NULL-terminated string containing the PEM encoding of + the client's private key. */ + const char *private_key; + + /* cert_chain is the NULL-terminated string containing the PEM encoding of + the client's certificate chain. */ + const char *cert_chain; +} tsi_ssl_pem_key_cert_pair; + /* 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. + - pem_key_cert_pair is a pointer to the object containing client's private + key and certificate chain. This parameter can be NULL if the client does + not have such a key/cert pair. + - pem_roots_cert is the NULL-terminated string containing the PEM encoding of + the client root certificates. This parameter may be NULL if the server does + not want the client to be authenticated with SSL. - 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. + - alpn_protocols is an array containing the NULL terminated protocol names + that the handshakers created with this factory support. 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. @@ -88,11 +93,9 @@ typedef struct tsi_ssl_client_handshaker_factory - 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, + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pair, + const char *pem_root_certs, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, tsi_ssl_client_handshaker_factory **factory); /* Creates a client handshaker. @@ -122,37 +125,19 @@ typedef struct tsi_ssl_server_handshaker_factory tsi_ssl_server_handshaker_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 + - pem_key_cert_pairs is an array private key / certificate chains of the + server. + - num_key_cert_pairs is the number of items in the pem_key_cert_pairs array. + - pem_root_certs is the NULL-terminated string containing the PEM encoding + of the server root certificates. - 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. + - alpn_protocols is an array containing the NULL terminated protocol names + that the handshakers created with this factory support. 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. @@ -160,13 +145,10 @@ typedef struct tsi_ssl_server_handshaker_factory - 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, + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, + int force_client_auth, const char *cipher_suites, + const char **alpn_protocols, uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory); /* Same as tsi_create_ssl_server_handshaker_factory method except uses @@ -176,15 +158,11 @@ tsi_result tsi_create_ssl_server_handshaker_factory( 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, + const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs, const char *pem_client_root_certs, 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_server_handshaker_factory **factory); + const char *cipher_suites, const char **alpn_protocols, + uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory); /* Creates a server handshaker. - self is the factory from which the handshaker will be created. diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c index 67ebe1b1f3..b11c00c43c 100644 --- a/src/core/tsi/transport_security.c +++ b/src/core/tsi/transport_security.c @@ -73,6 +73,8 @@ const char *tsi_result_to_string(tsi_result result) { return "TSI_HANDSHAKE_IN_PROGRESS"; case TSI_OUT_OF_RESOURCES: return "TSI_OUT_OF_RESOURCES"; + case TSI_ASYNC: + return "TSI_ASYNC"; default: return "UNKNOWN"; } @@ -92,6 +94,9 @@ tsi_result tsi_frame_protector_protect(tsi_frame_protector *self, protected_output_frames_size == NULL) { return TSI_INVALID_ARGUMENT; } + if (self->vtable == NULL || self->vtable->protect == NULL) { + return TSI_UNIMPLEMENTED; + } return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size, protected_output_frames, protected_output_frames_size); @@ -104,6 +109,9 @@ tsi_result tsi_frame_protector_protect_flush( protected_output_frames_size == NULL || still_pending_size == NULL) { return TSI_INVALID_ARGUMENT; } + if (self->vtable == NULL || self->vtable->protect_flush == NULL) { + return TSI_UNIMPLEMENTED; + } return self->vtable->protect_flush(self, protected_output_frames, protected_output_frames_size, still_pending_size); @@ -118,6 +126,9 @@ tsi_result tsi_frame_protector_unprotect( unprotected_bytes_size == NULL) { return TSI_INVALID_ARGUMENT; } + if (self->vtable == NULL || self->vtable->unprotect == NULL) { + return TSI_UNIMPLEMENTED; + } return self->vtable->unprotect(self, protected_frames_bytes, protected_frames_bytes_size, unprotected_bytes, unprotected_bytes_size); @@ -139,6 +150,9 @@ tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, return TSI_INVALID_ARGUMENT; } if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (self->vtable == NULL || self->vtable->get_bytes_to_send_to_peer == NULL) { + return TSI_UNIMPLEMENTED; + } return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size); } @@ -149,12 +163,18 @@ tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self, return TSI_INVALID_ARGUMENT; } if (self->frame_protector_created) return TSI_FAILED_PRECONDITION; + if (self->vtable == NULL || self->vtable->process_bytes_from_peer == NULL) { + return TSI_UNIMPLEMENTED; + } 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; + if (self->vtable == NULL || self->vtable->get_result == NULL) { + return TSI_UNIMPLEMENTED; + } return self->vtable->get_result(self); } @@ -165,6 +185,9 @@ tsi_result tsi_handshaker_extract_peer(tsi_handshaker *self, tsi_peer *peer) { if (tsi_handshaker_get_result(self) != TSI_OK) { return TSI_FAILED_PRECONDITION; } + if (self->vtable == NULL || self->vtable->extract_peer == NULL) { + return TSI_UNIMPLEMENTED; + } return self->vtable->extract_peer(self, peer); } @@ -177,19 +200,77 @@ tsi_result tsi_handshaker_create_frame_protector( if (tsi_handshaker_get_result(self) != TSI_OK) { return TSI_FAILED_PRECONDITION; } + if (self->vtable == NULL || self->vtable->create_frame_protector == NULL) { + return TSI_UNIMPLEMENTED; + } result = self->vtable->create_frame_protector(self, max_protected_frame_size, protector); if (result == TSI_OK) { - self->frame_protector_created = 1; + self->frame_protector_created = true; } return result; } +tsi_result tsi_handshaker_next( + tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, unsigned char **bytes_to_send, + size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data) { + if (self == NULL) return TSI_INVALID_ARGUMENT; + if (self->handshaker_result_created) return TSI_FAILED_PRECONDITION; + if (self->vtable == NULL || self->vtable->next == NULL) { + return TSI_UNIMPLEMENTED; + } + return self->vtable->next(self, received_bytes, received_bytes_size, + bytes_to_send, bytes_to_send_size, + handshaker_result, cb, user_data); +} + void tsi_handshaker_destroy(tsi_handshaker *self) { if (self == NULL) return; self->vtable->destroy(self); } +/* --- tsi_handshaker_result implementation. --- */ + +tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result *self, + tsi_peer *peer) { + if (self == NULL || peer == NULL) return TSI_INVALID_ARGUMENT; + memset(peer, 0, sizeof(tsi_peer)); + if (self->vtable == NULL || self->vtable->extract_peer == NULL) { + return TSI_UNIMPLEMENTED; + } + return self->vtable->extract_peer(self, peer); +} + +tsi_result tsi_handshaker_result_create_frame_protector( + const tsi_handshaker_result *self, size_t *max_protected_frame_size, + tsi_frame_protector **protector) { + if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT; + if (self->vtable == NULL || self->vtable->create_frame_protector == NULL) { + return TSI_UNIMPLEMENTED; + } + return self->vtable->create_frame_protector(self, max_protected_frame_size, + protector); +} + +tsi_result tsi_handshaker_result_get_unused_bytes( + const tsi_handshaker_result *self, unsigned char **bytes, + size_t *bytes_size) { + if (self == NULL || bytes == NULL || bytes_size == NULL) { + return TSI_INVALID_ARGUMENT; + } + if (self->vtable == NULL || self->vtable->get_unused_bytes == NULL) { + return TSI_UNIMPLEMENTED; + } + return self->vtable->get_unused_bytes(self, bytes, bytes_size); +} + +void tsi_handshaker_result_destroy(tsi_handshaker_result *self) { + if (self == NULL) return; + self->vtable->destroy(self); +} + /* --- tsi_peer implementation. --- */ tsi_peer_property tsi_init_peer_property(void) { diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h index 491fa1a8bd..a4c9cbc001 100644 --- a/src/core/tsi/transport_security.h +++ b/src/core/tsi/transport_security.h @@ -34,6 +34,8 @@ #ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_H #define GRPC_CORE_TSI_TRANSPORT_SECURITY_H +#include <stdbool.h> + #include "src/core/tsi/transport_security_interface.h" #ifdef __cplusplus @@ -81,11 +83,33 @@ typedef struct { size_t *max_protected_frame_size, tsi_frame_protector **protector); void (*destroy)(tsi_handshaker *self); + tsi_result (*next)(tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, unsigned char **bytes_to_send, + size_t *bytes_to_send_size, + tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data); } tsi_handshaker_vtable; struct tsi_handshaker { const tsi_handshaker_vtable *vtable; - int frame_protector_created; + bool frame_protector_created; + bool handshaker_result_created; +}; + +/* Base for tsi_handshaker_result implementations. + See transport_security_interface.h for documentation. */ +typedef struct { + tsi_result (*extract_peer)(const tsi_handshaker_result *self, tsi_peer *peer); + tsi_result (*create_frame_protector)(const tsi_handshaker_result *self, + size_t *max_output_protected_frame_size, + tsi_frame_protector **protector); + tsi_result (*get_unused_bytes)(const tsi_handshaker_result *self, + unsigned char **bytes, size_t *bytes_size); + void (*destroy)(tsi_handshaker_result *self); +} tsi_handshaker_result_vtable; + +struct tsi_handshaker_result { + const tsi_handshaker_result_vtable *vtable; }; /* Peer and property construction/destruction functions. */ diff --git a/src/core/tsi/transport_security_adapter.c b/src/core/tsi/transport_security_adapter.c new file mode 100644 index 0000000000..9f2147b530 --- /dev/null +++ b/src/core/tsi/transport_security_adapter.c @@ -0,0 +1,236 @@ +/* + * + * 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/tsi/transport_security_adapter.h" + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include "src/core/tsi/transport_security.h" + +#define TSI_ADAPTER_INITIAL_BUFFER_SIZE 256 + +/* --- tsi_adapter_handshaker_result implementation ---*/ + +typedef struct { + tsi_handshaker_result base; + tsi_handshaker *wrapped; + unsigned char *unused_bytes; + size_t unused_bytes_size; +} tsi_adapter_handshaker_result; + +static tsi_result adapter_result_extract_peer(const tsi_handshaker_result *self, + tsi_peer *peer) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + return tsi_handshaker_extract_peer(impl->wrapped, peer); +} + +static tsi_result adapter_result_create_frame_protector( + const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + return tsi_handshaker_create_frame_protector( + impl->wrapped, max_output_protected_frame_size, protector); +} + +static tsi_result adapter_result_get_unused_bytes( + const tsi_handshaker_result *self, unsigned char **bytes, + size_t *byte_size) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + *bytes = impl->unused_bytes; + *byte_size = impl->unused_bytes_size; + return TSI_OK; +} + +static void adapter_result_destroy(tsi_handshaker_result *self) { + tsi_adapter_handshaker_result *impl = (tsi_adapter_handshaker_result *)self; + tsi_handshaker_destroy(impl->wrapped); + gpr_free(impl->unused_bytes); + gpr_free(self); +} + +static const tsi_handshaker_result_vtable result_vtable = { + adapter_result_extract_peer, adapter_result_create_frame_protector, + adapter_result_get_unused_bytes, adapter_result_destroy, +}; + +/* Ownership of wrapped tsi_handshaker is transferred to the result object. */ +static tsi_result tsi_adapter_create_handshaker_result( + tsi_handshaker *wrapped, const unsigned char *unused_bytes, + size_t unused_bytes_size, tsi_handshaker_result **handshaker_result) { + if (wrapped == NULL || (unused_bytes_size > 0 && unused_bytes == NULL)) { + return TSI_INVALID_ARGUMENT; + } + tsi_adapter_handshaker_result *impl = gpr_zalloc(sizeof(*impl)); + impl->base.vtable = &result_vtable; + impl->wrapped = wrapped; + impl->unused_bytes_size = unused_bytes_size; + if (unused_bytes_size > 0) { + impl->unused_bytes = gpr_malloc(unused_bytes_size); + memcpy(impl->unused_bytes, unused_bytes, unused_bytes_size); + } else { + impl->unused_bytes = NULL; + } + *handshaker_result = &impl->base; + return TSI_OK; +} + +/* --- tsi_adapter_handshaker implementation ---*/ + +typedef struct { + tsi_handshaker base; + tsi_handshaker *wrapped; + unsigned char *adapter_buffer; + size_t adapter_buffer_size; +} tsi_adapter_handshaker; + +static tsi_result adapter_get_bytes_to_send_to_peer(tsi_handshaker *self, + unsigned char *bytes, + size_t *bytes_size) { + return tsi_handshaker_get_bytes_to_send_to_peer( + tsi_adapter_handshaker_get_wrapped(self), bytes, bytes_size); +} + +static tsi_result adapter_process_bytes_from_peer(tsi_handshaker *self, + const unsigned char *bytes, + size_t *bytes_size) { + return tsi_handshaker_process_bytes_from_peer( + tsi_adapter_handshaker_get_wrapped(self), bytes, bytes_size); +} + +static tsi_result adapter_get_result(tsi_handshaker *self) { + return tsi_handshaker_get_result(tsi_adapter_handshaker_get_wrapped(self)); +} + +static tsi_result adapter_extract_peer(tsi_handshaker *self, tsi_peer *peer) { + return tsi_handshaker_extract_peer(tsi_adapter_handshaker_get_wrapped(self), + peer); +} + +static tsi_result adapter_create_frame_protector( + tsi_handshaker *self, size_t *max_protected_frame_size, + tsi_frame_protector **protector) { + return tsi_handshaker_create_frame_protector( + tsi_adapter_handshaker_get_wrapped(self), max_protected_frame_size, + protector); +} + +static void adapter_destroy(tsi_handshaker *self) { + tsi_adapter_handshaker *impl = (tsi_adapter_handshaker *)self; + tsi_handshaker_destroy(impl->wrapped); + gpr_free(impl->adapter_buffer); + gpr_free(self); +} + +static tsi_result adapter_next( + tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, unsigned char **bytes_to_send, + size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data) { + /* Input sanity check. */ + if ((received_bytes_size > 0 && received_bytes == NULL) || + bytes_to_send == NULL || bytes_to_send_size == NULL || + handshaker_result == NULL) { + return TSI_INVALID_ARGUMENT; + } + + /* If there are received bytes, process them first. */ + tsi_adapter_handshaker *impl = (tsi_adapter_handshaker *)self; + tsi_result status = TSI_OK; + size_t bytes_consumed = received_bytes_size; + if (received_bytes_size > 0) { + status = tsi_handshaker_process_bytes_from_peer( + impl->wrapped, received_bytes, &bytes_consumed); + if (status != TSI_OK) return status; + } + + /* Get bytes to send to the peer, if available. */ + size_t offset = 0; + do { + size_t to_send_size = impl->adapter_buffer_size - offset; + status = tsi_handshaker_get_bytes_to_send_to_peer( + impl->wrapped, impl->adapter_buffer + offset, &to_send_size); + offset += to_send_size; + if (status == TSI_INCOMPLETE_DATA) { + impl->adapter_buffer_size *= 2; + impl->adapter_buffer = + gpr_realloc(impl->adapter_buffer, impl->adapter_buffer_size); + } + } while (status == TSI_INCOMPLETE_DATA); + if (status != TSI_OK) return status; + *bytes_to_send = impl->adapter_buffer; + *bytes_to_send_size = offset; + + /* If handshake completes, create tsi_handshaker_result. */ + if (tsi_handshaker_is_in_progress(impl->wrapped)) { + *handshaker_result = NULL; + } else { + size_t unused_bytes_size = received_bytes_size - bytes_consumed; + const unsigned char *unused_bytes = + unused_bytes_size == 0 ? NULL : received_bytes + bytes_consumed; + status = tsi_adapter_create_handshaker_result( + impl->wrapped, unused_bytes, unused_bytes_size, handshaker_result); + if (status == TSI_OK) { + impl->base.handshaker_result_created = true; + impl->wrapped = NULL; + } + } + return status; +} + +static const tsi_handshaker_vtable handshaker_vtable = { + adapter_get_bytes_to_send_to_peer, + adapter_process_bytes_from_peer, + adapter_get_result, + adapter_extract_peer, + adapter_create_frame_protector, + adapter_destroy, + adapter_next, +}; + +tsi_handshaker *tsi_create_adapter_handshaker(tsi_handshaker *wrapped) { + GPR_ASSERT(wrapped != NULL); + tsi_adapter_handshaker *impl = gpr_zalloc(sizeof(*impl)); + impl->base.vtable = &handshaker_vtable; + impl->wrapped = wrapped; + impl->adapter_buffer_size = TSI_ADAPTER_INITIAL_BUFFER_SIZE; + impl->adapter_buffer = gpr_malloc(impl->adapter_buffer_size); + return &impl->base; +} + +tsi_handshaker *tsi_adapter_handshaker_get_wrapped(tsi_handshaker *adapter) { + if (adapter == NULL) return NULL; + tsi_adapter_handshaker *impl = (tsi_adapter_handshaker *)adapter; + return impl->wrapped; +} diff --git a/src/core/tsi/transport_security_adapter.h b/src/core/tsi/transport_security_adapter.h new file mode 100644 index 0000000000..400df2f11b --- /dev/null +++ b/src/core/tsi/transport_security_adapter.h @@ -0,0 +1,62 @@ +/* + * + * 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. + * + */ + +#ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H +#define GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H + +#include "src/core/tsi/transport_security_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create a tsi handshaker that takes an implementation of old interface and + converts into an implementation of new interface. In the old interface, + there are get_bytes_to_send_to_peer, process_bytes_from_peer, get_result, + extract_peer, and create_frame_protector. In the new interface, only next + method is needed. See transport_security_interface.h for details. Note that + this tsi adapter handshaker is temporary. It will be removed once TSI has + been fully migrated to the new interface. + Ownership of input tsi_handshaker is transferred to this new adapter. */ +tsi_handshaker *tsi_create_adapter_handshaker(tsi_handshaker *wrapped); + +/* Given a tsi adapter handshaker, return the original wrapped handshaker. The + adapter still owns the wrapped handshaker which should not be destroyed by + the caller. */ +tsi_handshaker *tsi_adapter_handshaker_get_wrapped(tsi_handshaker *adapter); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H */ diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h index caed43eac4..f2112b62b6 100644 --- a/src/core/tsi/transport_security_interface.h +++ b/src/core/tsi/transport_security_interface.h @@ -56,7 +56,8 @@ typedef enum { TSI_NOT_FOUND = 9, TSI_PROTOCOL_FAILURE = 10, TSI_HANDSHAKE_IN_PROGRESS = 11, - TSI_OUT_OF_RESOURCES = 12 + TSI_OUT_OF_RESOURCES = 12, + TSI_ASYNC = 13 } tsi_result; typedef enum { @@ -208,76 +209,138 @@ typedef struct { /* Destructs the tsi_peer object. */ void tsi_peer_destruct(tsi_peer *self); +/* --- tsi_handshaker_result object --- + + This object contains all necessary handshake results and data such as peer + info, negotiated keys, unused handshake bytes, when the handshake completes. + Implementations of this object must be thread compatible. */ + +typedef struct tsi_handshaker_result tsi_handshaker_result; + +/* This method extracts tsi peer. It returns TSI_OK assuming there is no fatal + error. + The caller is responsible for destructing the peer. */ +tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result *self, + tsi_peer *peer); + +/* This method creates a tsi_frame_protector object. It returns TSI_OK assuming + there is no fatal error. + The caller is responsible for destroying the protector. */ +tsi_result tsi_handshaker_result_create_frame_protector( + const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector); + +/* This method returns the unused bytes from the handshake. It returns TSI_OK + assuming there is no fatal error. + Ownership of the bytes is retained by the handshaker result. As a + consequence, the caller must not free the bytes. */ +tsi_result tsi_handshaker_result_get_unused_bytes( + const tsi_handshaker_result *self, unsigned char **bytes, + size_t *byte_size); + +/* This method releases the tsi_handshaker_handshaker object. After this method + is called, no other method can be called on the object. */ +void tsi_handshaker_result_destroy(tsi_handshaker_result *self); + /* --- tsi_handshaker objects ---- Implementations of this object must be thread compatible. - A typical usage of this object would be: + ------------------------------------------------------------------------ + + A typical usage supporting both synchronous and asynchronous TSI handshaker + implementations 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; + + typedef struct { + tsi_handshaker *handshaker; + tsi_handshaker_result *handshaker_result; + unsigned char *handshake_buffer; + size_t handshake_buffer_size; + ... + } security_handshaker; + + void do_handshake(security_handshaker *h, ...) { + // Start the handshake by the calling do_handshake_next. + do_handshake_next(h, NULL, 0); + ... } - // 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, ..., ...); - .... + // This method is the callback function when data is received from the + // peer. This method will read bytes into the handshake buffer and call + // do_handshake_next. + void on_handshake_data_received_from_peer(void *user_data) { + security_handshaker *h = (security_handshaker *)user_data; + size_t bytes_received_size = h->handshake_buffer_size; + read_bytes_from_peer(h->handshake_buffer, &bytes_received_size); + do_handshake_next(h, h->handshake_buffer, bytes_received_size); + } + + // This method processes a step of handshake, calling tsi_handshaker_next. + void do_handshake_next(security_handshaker *h, + const unsigned char* bytes_received, + size_t bytes_received_size) { + tsi_result status = TSI_OK; + unsigned char *bytes_to_send = NULL; + size_t bytes_to_send_size = 0; + tsi_handshaker_result *result = NULL; + status = tsi_handshaker_next( + handshaker, bytes_received, bytes_received_size, &bytes_to_send, + &bytes_to_send_size, &result, on_handshake_next_done, h); + // If TSI handshaker is asynchronous, on_handshake_next_done will be + // executed inside tsi_handshaker_next. + if (status == TSI_ASYNC) return; + // If TSI handshaker is synchronous, invoke callback directly in this + // thread. + on_handshake_next_done(status, (void *)h, bytes_to_send, + bytes_to_send_size, result); + } + + // This is the callback function to execute after tsi_handshaker_next. + // It is passed to tsi_handshaker_next as a function parameter. + void on_handshake_next_done( + tsi_result status, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *result) { + security_handshaker *h = (security_handshaker *)user_data; + if (status == TSI_INCOMPLETE_DATA) { + // Schedule an asynchronous read from the peer. If handshake data are + // received, on_handshake_data_received_from_peer will be called. + async_read_from_peer(..., ..., on_handshake_data_received_from_peer); + return; + } + if (status != TSI_OK) return; + + if (bytes_to_send_size > 0) { + send_bytes_to_peer(bytes_to_send, bytes_to_send_size); + } + + if (result != NULL) { + // Handshake completed. + h->result = result; + // Check the Peer. + tsi_peer peer; + status = tsi_handshaker_result_extract_peer(result, &peer); + if (status != TSI_OK) return; + status = check_peer(&peer); + tsi_peer_destruct(&peer); + if (status != TSI_OK) return; + + // Create the protector. + tsi_frame_protector* protector = NULL; + status = tsi_handshaker_result_create_frame_protector(result, NULL, + &protector); + if (status != TSI_OK) return; + + // Do not forget to unprotect outstanding data if any. + .... + } } - ... ------------------------------------------------------------------------ */ typedef struct tsi_handshaker tsi_handshaker; -/* Gets bytes that need to be sent to the peer. +/* TO BE DEPRECATED SOON. Use tsi_handshaker_next instead. + 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 @@ -292,7 +355,8 @@ 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. +/* TO BE DEPRECATED SOON. Use tsi_handshaker_next instead. + 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. @@ -305,24 +369,29 @@ 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. +/* TO BE DEPRECATED SOON. + 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. */ +/* TO BE DEPRECATED SOON. + 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 +/* TO BE DEPRECATED SOON. Use tsi_handshaker_result_extract_peer instead. + 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 +/* TO BE DEPRECATED SOON. Use tsi_handshaker_result_create_frame_protector + instead. + 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 @@ -342,10 +411,53 @@ tsi_result tsi_handshaker_create_frame_protector( tsi_handshaker *self, size_t *max_output_protected_frame_size, tsi_frame_protector **protector); +/* Callback function definition for tsi_handshaker_next. + - status indicates the status of the next operation. + - user_data is the argument to callback function passed from the caller. + - bytes_to_send is the data buffer to be sent to the peer. + - bytes_to_send_size is the size of data buffer to be sent to the peer. + - handshaker_result is the result of handshake when the handshake completes, + is NULL otherwise. */ +typedef void (*tsi_handshaker_on_next_done_cb)( + tsi_result status, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result); + +/* Conduct a next step of the handshake. + - received_bytes is the buffer containing the data received from the peer. + - received_bytes_size is the size of the data received from the peer. + - bytes_to_send is the data buffer to be sent to the peer. + - bytes_to_send_size is the size of data buffer to be sent to the peer. + - handshaker_result is the result of handshake if the handshake completes. + - cb is the callback function defined above. It can be NULL for synchronous + TSI handshaker implementation. + - user_data is the argument to callback function passed from the caller. + This method returns TSI_ASYNC if the TSI handshaker implementation is + asynchronous, and in this case, the callback is guaranteed to run in another + thread owned by TSI. It returns TSI_OK if the handshake completes or if + there are data to send to the peer, otherwise returns TSI_INCOMPLETE_DATA + which indicates that this method needs to be called again with more data + from the peer. In case of a fatal error in the handshake, another specific + error code is returned. + The caller is responsible for destroying the handshaker_result. However, + the caller should not free bytes_to_send, as the buffer is owned by the + tsi_handshaker object. */ +tsi_result tsi_handshaker_next( + tsi_handshaker *self, const unsigned char *received_bytes, + size_t received_bytes_size, unsigned char **bytes_to_send, + size_t *bytes_to_send_size, tsi_handshaker_result **handshaker_result, + tsi_handshaker_on_next_done_cb cb, void *user_data); + /* 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); +/* This method initializes the necessary shared objects used for tsi + implementation. */ +void tsi_init(); + +/* This method destroys the shared objects created by tsi_init. */ +void tsi_destroy(); + #ifdef __cplusplus } #endif |