/* * * Copyright 2018 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "test/core/end2end/end2end_tests.h" #include #include #include #include #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/security/credentials/credentials.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include namespace grpc { namespace testing { namespace { void* tag(intptr_t t) { return (void*)t; } gpr_timespec five_seconds_time() { return grpc_timeout_seconds_to_deadline(5); } grpc_server* server_create(grpc_completion_queue* cq, char* server_addr) { grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials* server_creds = grpc_ssl_server_credentials_create_ex( test_root_cert, &pem_cert_key_pair, 1, GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, nullptr); grpc_server* server = grpc_server_create(nullptr, nullptr); grpc_server_register_completion_queue(server, cq, nullptr); GPR_ASSERT( grpc_server_add_secure_http2_port(server, server_addr, server_creds)); grpc_server_credentials_release(server_creds); grpc_server_start(server); return server; } grpc_channel* client_create(char* server_addr, grpc_ssl_session_cache* cache) { grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = { test_signed_client_key, test_signed_client_cert}; grpc_channel_credentials* client_creds = grpc_ssl_credentials_create( test_root_cert, &signed_client_key_cert_pair, nullptr, nullptr); grpc_arg args[] = { grpc_channel_arg_string_create( const_cast(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), const_cast("waterzooi.test.google.be")), grpc_ssl_session_cache_create_channel_arg(cache), }; grpc_channel_args* client_args = grpc_channel_args_copy_and_add(nullptr, args, GPR_ARRAY_SIZE(args)); grpc_channel* client = grpc_secure_channel_create(client_creds, server_addr, client_args, nullptr); GPR_ASSERT(client != nullptr); grpc_channel_credentials_release(client_creds); { grpc_core::ExecCtx exec_ctx; grpc_channel_args_destroy(client_args); } return client; } void do_round_trip(grpc_completion_queue* cq, grpc_server* server, char* server_addr, grpc_ssl_session_cache* cache, bool expect_session_reuse) { grpc_channel* client = client_create(server_addr, cache); cq_verifier* cqv = cq_verifier_create(cq); grpc_op ops[6]; grpc_op* op; grpc_metadata_array initial_metadata_recv; grpc_metadata_array trailing_metadata_recv; grpc_metadata_array request_metadata_recv; grpc_call_details call_details; grpc_status_code status; grpc_call_error error; grpc_slice details; int was_cancelled = 2; gpr_timespec deadline = grpc_timeout_seconds_to_deadline(60); grpc_call* c = grpc_channel_create_call( client, nullptr, GRPC_PROPAGATE_DEFAULTS, cq, grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr); GPR_ASSERT(c); grpc_metadata_array_init(&initial_metadata_recv); grpc_metadata_array_init(&trailing_metadata_recv); grpc_metadata_array_init(&request_metadata_recv); grpc_call_details_init(&call_details); memset(ops, 0, sizeof(ops)); op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; op->flags = 0; op->reserved = nullptr; op++; op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; op->flags = 0; op->reserved = nullptr; op++; op->op = GRPC_OP_RECV_INITIAL_METADATA; op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv; op->flags = 0; op->reserved = nullptr; op++; op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv; op->data.recv_status_on_client.status = &status; op->data.recv_status_on_client.status_details = &details; op->flags = 0; op->reserved = nullptr; op++; error = grpc_call_start_batch(c, ops, static_cast(op - ops), tag(1), nullptr); GPR_ASSERT(GRPC_CALL_OK == error); grpc_call* s; error = grpc_server_request_call(server, &s, &call_details, &request_metadata_recv, cq, cq, tag(101)); GPR_ASSERT(GRPC_CALL_OK == error); CQ_EXPECT_COMPLETION(cqv, tag(101), 1); cq_verify(cqv); grpc_auth_context* auth = grpc_call_auth_context(s); grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name( auth, GRPC_SSL_SESSION_REUSED_PROPERTY); const grpc_auth_property* property = grpc_auth_property_iterator_next(&it); GPR_ASSERT(property != nullptr); if (expect_session_reuse) { GPR_ASSERT(strcmp(property->value, "true") == 0); } else { GPR_ASSERT(strcmp(property->value, "false") == 0); } grpc_auth_context_release(auth); memset(ops, 0, sizeof(ops)); op = ops; op->op = GRPC_OP_SEND_INITIAL_METADATA; op->data.send_initial_metadata.count = 0; op->flags = 0; op->reserved = nullptr; op++; op->op = GRPC_OP_RECV_CLOSE_ON_SERVER; op->data.recv_close_on_server.cancelled = &was_cancelled; op->flags = 0; op->reserved = nullptr; op++; op->op = GRPC_OP_SEND_STATUS_FROM_SERVER; op->data.send_status_from_server.trailing_metadata_count = 0; op->data.send_status_from_server.status = GRPC_STATUS_OK; op->flags = 0; op->reserved = nullptr; op++; error = grpc_call_start_batch(s, ops, static_cast(op - ops), tag(103), nullptr); GPR_ASSERT(GRPC_CALL_OK == error); CQ_EXPECT_COMPLETION(cqv, tag(103), 1); CQ_EXPECT_COMPLETION(cqv, tag(1), 1); cq_verify(cqv); grpc_metadata_array_destroy(&initial_metadata_recv); grpc_metadata_array_destroy(&trailing_metadata_recv); grpc_metadata_array_destroy(&request_metadata_recv); grpc_call_details_destroy(&call_details); grpc_call_unref(c); grpc_call_unref(s); cq_verifier_destroy(cqv); grpc_channel_destroy(client); } void drain_cq(grpc_completion_queue* cq) { grpc_event ev; do { ev = grpc_completion_queue_next(cq, five_seconds_time(), nullptr); } while (ev.type != GRPC_QUEUE_SHUTDOWN); } TEST(H2SessionReuseTest, SingleReuse) { int port = grpc_pick_unused_port_or_die(); char* server_addr; gpr_join_host_port(&server_addr, "localhost", port); grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr); grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16); grpc_server* server = server_create(cq, server_addr); do_round_trip(cq, server, server_addr, cache, false); do_round_trip(cq, server, server_addr, cache, true); do_round_trip(cq, server, server_addr, cache, true); gpr_free(server_addr); grpc_ssl_session_cache_destroy(cache); GPR_ASSERT(grpc_completion_queue_next( cq, grpc_timeout_milliseconds_to_deadline(100), nullptr) .type == GRPC_QUEUE_TIMEOUT); grpc_completion_queue* shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr); grpc_server_shutdown_and_notify(server, shutdown_cq, tag(1000)); GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000), grpc_timeout_seconds_to_deadline(5), nullptr) .type == GRPC_OP_COMPLETE); grpc_server_destroy(server); grpc_completion_queue_destroy(shutdown_cq); grpc_completion_queue_shutdown(cq); drain_cq(cq); grpc_completion_queue_destroy(cq); } } // namespace } // namespace testing } // namespace grpc int main(int argc, char** argv) { FILE* roots_file; size_t roots_size = strlen(test_root_cert); char* roots_filename; grpc::testing::TestEnvironment env(argc, argv); /* Set the SSL roots env var. */ roots_file = gpr_tmpfile("chttp2_ssl_session_reuse_test", &roots_filename); GPR_ASSERT(roots_filename != nullptr); GPR_ASSERT(roots_file != nullptr); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); grpc_init(); ::testing::InitGoogleTest(&argc, argv); int ret = RUN_ALL_TESTS(); grpc_shutdown(); /* Cleanup. */ remove(roots_filename); gpr_free(roots_filename); return ret; }