1 /*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include "test/core/end2end/end2end_tests.h"
20
21 #include <stdio.h>
22 #include <string.h>
23
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26
27 #include "src/core/lib/channel/channel_args.h"
28 #include "src/core/lib/gpr/env.h"
29 #include "src/core/lib/gpr/host_port.h"
30 #include "src/core/lib/gpr/string.h"
31 #include "src/core/lib/gpr/tmpfile.h"
32 #include "src/core/lib/security/credentials/credentials.h"
33 #include "test/core/end2end/cq_verifier.h"
34 #include "test/core/end2end/data/ssl_test_data.h"
35 #include "test/core/util/port.h"
36 #include "test/core/util/test_config.h"
37
38 #include <gtest/gtest.h>
39
40 namespace grpc {
41 namespace testing {
42 namespace {
43
tag(intptr_t t)44 void* tag(intptr_t t) { return (void*)t; }
45
five_seconds_time()46 gpr_timespec five_seconds_time() { return grpc_timeout_seconds_to_deadline(5); }
47
server_create(grpc_completion_queue * cq,char * server_addr)48 grpc_server* server_create(grpc_completion_queue* cq, char* server_addr) {
49 grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
50 test_server1_cert};
51 grpc_server_credentials* server_creds = grpc_ssl_server_credentials_create_ex(
52 test_root_cert, &pem_cert_key_pair, 1,
53 GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, nullptr);
54
55 grpc_server* server = grpc_server_create(nullptr, nullptr);
56 grpc_server_register_completion_queue(server, cq, nullptr);
57 GPR_ASSERT(
58 grpc_server_add_secure_http2_port(server, server_addr, server_creds));
59 grpc_server_credentials_release(server_creds);
60 grpc_server_start(server);
61
62 return server;
63 }
64
client_create(char * server_addr,grpc_ssl_session_cache * cache)65 grpc_channel* client_create(char* server_addr, grpc_ssl_session_cache* cache) {
66 grpc_ssl_pem_key_cert_pair signed_client_key_cert_pair = {
67 test_signed_client_key, test_signed_client_cert};
68 grpc_channel_credentials* client_creds = grpc_ssl_credentials_create(
69 test_root_cert, &signed_client_key_cert_pair, nullptr, nullptr);
70
71 grpc_arg args[] = {
72 grpc_channel_arg_string_create(
73 const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
74 const_cast<char*>("waterzooi.test.google.be")),
75 grpc_ssl_session_cache_create_channel_arg(cache),
76 };
77
78 grpc_channel_args* client_args =
79 grpc_channel_args_copy_and_add(nullptr, args, GPR_ARRAY_SIZE(args));
80
81 grpc_channel* client = grpc_secure_channel_create(client_creds, server_addr,
82 client_args, nullptr);
83 GPR_ASSERT(client != nullptr);
84 grpc_channel_credentials_release(client_creds);
85
86 {
87 grpc_core::ExecCtx exec_ctx;
88 grpc_channel_args_destroy(client_args);
89 }
90
91 return client;
92 }
93
do_round_trip(grpc_completion_queue * cq,grpc_server * server,char * server_addr,grpc_ssl_session_cache * cache,bool expect_session_reuse)94 void do_round_trip(grpc_completion_queue* cq, grpc_server* server,
95 char* server_addr, grpc_ssl_session_cache* cache,
96 bool expect_session_reuse) {
97 grpc_channel* client = client_create(server_addr, cache);
98
99 cq_verifier* cqv = cq_verifier_create(cq);
100 grpc_op ops[6];
101 grpc_op* op;
102 grpc_metadata_array initial_metadata_recv;
103 grpc_metadata_array trailing_metadata_recv;
104 grpc_metadata_array request_metadata_recv;
105 grpc_call_details call_details;
106 grpc_status_code status;
107 grpc_call_error error;
108 grpc_slice details;
109 int was_cancelled = 2;
110
111 gpr_timespec deadline = grpc_timeout_seconds_to_deadline(60);
112 grpc_call* c = grpc_channel_create_call(
113 client, nullptr, GRPC_PROPAGATE_DEFAULTS, cq,
114 grpc_slice_from_static_string("/foo"), nullptr, deadline, nullptr);
115 GPR_ASSERT(c);
116
117 grpc_metadata_array_init(&initial_metadata_recv);
118 grpc_metadata_array_init(&trailing_metadata_recv);
119 grpc_metadata_array_init(&request_metadata_recv);
120 grpc_call_details_init(&call_details);
121
122 memset(ops, 0, sizeof(ops));
123 op = ops;
124 op->op = GRPC_OP_SEND_INITIAL_METADATA;
125 op->data.send_initial_metadata.count = 0;
126 op->flags = 0;
127 op->reserved = nullptr;
128 op++;
129 op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
130 op->flags = 0;
131 op->reserved = nullptr;
132 op++;
133 op->op = GRPC_OP_RECV_INITIAL_METADATA;
134 op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
135 op->flags = 0;
136 op->reserved = nullptr;
137 op++;
138 op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
139 op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
140 op->data.recv_status_on_client.status = &status;
141 op->data.recv_status_on_client.status_details = &details;
142 op->flags = 0;
143 op->reserved = nullptr;
144 op++;
145 error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
146 nullptr);
147 GPR_ASSERT(GRPC_CALL_OK == error);
148
149 grpc_call* s;
150 error = grpc_server_request_call(server, &s, &call_details,
151 &request_metadata_recv, cq, cq, tag(101));
152 GPR_ASSERT(GRPC_CALL_OK == error);
153 CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
154 cq_verify(cqv);
155
156 grpc_auth_context* auth = grpc_call_auth_context(s);
157 grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
158 auth, GRPC_SSL_SESSION_REUSED_PROPERTY);
159 const grpc_auth_property* property = grpc_auth_property_iterator_next(&it);
160 GPR_ASSERT(property != nullptr);
161
162 if (expect_session_reuse) {
163 GPR_ASSERT(strcmp(property->value, "true") == 0);
164 } else {
165 GPR_ASSERT(strcmp(property->value, "false") == 0);
166 }
167 grpc_auth_context_release(auth);
168
169 memset(ops, 0, sizeof(ops));
170 op = ops;
171 op->op = GRPC_OP_SEND_INITIAL_METADATA;
172 op->data.send_initial_metadata.count = 0;
173 op->flags = 0;
174 op->reserved = nullptr;
175 op++;
176 op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
177 op->data.recv_close_on_server.cancelled = &was_cancelled;
178 op->flags = 0;
179 op->reserved = nullptr;
180 op++;
181 op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
182 op->data.send_status_from_server.trailing_metadata_count = 0;
183 op->data.send_status_from_server.status = GRPC_STATUS_OK;
184 op->flags = 0;
185 op->reserved = nullptr;
186 op++;
187 error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(103),
188 nullptr);
189 GPR_ASSERT(GRPC_CALL_OK == error);
190
191 CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
192 CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
193 cq_verify(cqv);
194
195 grpc_metadata_array_destroy(&initial_metadata_recv);
196 grpc_metadata_array_destroy(&trailing_metadata_recv);
197 grpc_metadata_array_destroy(&request_metadata_recv);
198 grpc_call_details_destroy(&call_details);
199
200 grpc_call_unref(c);
201 grpc_call_unref(s);
202
203 cq_verifier_destroy(cqv);
204
205 grpc_channel_destroy(client);
206 }
207
drain_cq(grpc_completion_queue * cq)208 void drain_cq(grpc_completion_queue* cq) {
209 grpc_event ev;
210 do {
211 ev = grpc_completion_queue_next(cq, five_seconds_time(), nullptr);
212 } while (ev.type != GRPC_QUEUE_SHUTDOWN);
213 }
214
TEST(H2SessionReuseTest,SingleReuse)215 TEST(H2SessionReuseTest, SingleReuse) {
216 int port = grpc_pick_unused_port_or_die();
217
218 char* server_addr;
219 gpr_join_host_port(&server_addr, "localhost", port);
220
221 grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
222 grpc_ssl_session_cache* cache = grpc_ssl_session_cache_create_lru(16);
223
224 grpc_server* server = server_create(cq, server_addr);
225
226 do_round_trip(cq, server, server_addr, cache, false);
227 do_round_trip(cq, server, server_addr, cache, true);
228 do_round_trip(cq, server, server_addr, cache, true);
229
230 gpr_free(server_addr);
231 grpc_ssl_session_cache_destroy(cache);
232
233 GPR_ASSERT(grpc_completion_queue_next(
234 cq, grpc_timeout_milliseconds_to_deadline(100), nullptr)
235 .type == GRPC_QUEUE_TIMEOUT);
236
237 grpc_completion_queue* shutdown_cq =
238 grpc_completion_queue_create_for_pluck(nullptr);
239 grpc_server_shutdown_and_notify(server, shutdown_cq, tag(1000));
240 GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, tag(1000),
241 grpc_timeout_seconds_to_deadline(5),
242 nullptr)
243 .type == GRPC_OP_COMPLETE);
244 grpc_server_destroy(server);
245 grpc_completion_queue_destroy(shutdown_cq);
246
247 grpc_completion_queue_shutdown(cq);
248 drain_cq(cq);
249 grpc_completion_queue_destroy(cq);
250 }
251
252 } // namespace
253 } // namespace testing
254 } // namespace grpc
255
main(int argc,char ** argv)256 int main(int argc, char** argv) {
257 FILE* roots_file;
258 size_t roots_size = strlen(test_root_cert);
259 char* roots_filename;
260
261 grpc_test_init(argc, argv);
262 /* Set the SSL roots env var. */
263 roots_file = gpr_tmpfile("chttp2_ssl_session_reuse_test", &roots_filename);
264 GPR_ASSERT(roots_filename != nullptr);
265 GPR_ASSERT(roots_file != nullptr);
266 GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
267 fclose(roots_file);
268 gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
269
270 grpc_init();
271 ::testing::InitGoogleTest(&argc, argv);
272 int ret = RUN_ALL_TESTS();
273 grpc_shutdown();
274
275 /* Cleanup. */
276 remove(roots_filename);
277 gpr_free(roots_filename);
278
279 return ret;
280 }
281