• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 *
3 * Copyright 2016 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#import <XCTest/XCTest.h>
20#import <netinet/in.h>
21#import <sys/socket.h>
22
23#import "../ConfigureCronet.h"
24
25#import <Cronet/Cronet.h>
26#import <grpc/grpc.h>
27#import <grpc/grpc_cronet.h>
28#import "test/core/end2end/cq_verifier.h"
29#import "test/core/test_util/port.h"
30
31#import <grpc/support/alloc.h>
32
33#import "src/core/lib/channel/channel_args.h"
34#import "src/core/util/env.h"
35#import "src/core/util/host_port.h"
36#import "src/core/util/string.h"
37#import "src/core/util/tmpfile.h"
38#import "test/core/end2end/data/ssl_test_data.h"
39#import "test/core/test_util/test_config.h"
40
41#if COCOAPODS
42#import <openssl_grpc/ssl.h>
43#else
44#import <openssl/ssl.h>
45#endif
46
47static void drain_cq(grpc_completion_queue *cq) {
48  grpc_event ev;
49  do {
50    ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5), NULL);
51  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
52}
53
54@interface CronetUnitTests : XCTestCase
55
56@end
57
58@implementation CronetUnitTests
59
60+ (void)setUp {
61  [super setUp];
62
63  char *argv[] = {(char *)"CoreCronetEnd2EndTests"};
64  int argc = 1;
65  grpc_test_init(&argc, argv);
66
67  grpc_init();
68  configureCronet(/*enable_netlog=*/false);
69  init_ssl();
70}
71
72+ (void)tearDown {
73  grpc_shutdown();
74  cleanup_ssl();
75
76  [super tearDown];
77}
78
79void init_ssl(void) {
80  SSL_load_error_strings();
81  OpenSSL_add_ssl_algorithms();
82}
83
84void cleanup_ssl(void) { EVP_cleanup(); }
85
86int alpn_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in,
87            unsigned int inlen, void *arg) {
88  // Always select "h2" as the ALPN protocol to be used
89  *out = (const unsigned char *)"h2";
90  *outlen = 2;
91  return SSL_TLSEXT_ERR_OK;
92}
93
94void init_ctx(SSL_CTX *ctx) {
95  // Install server certificate
96  BIO *pem = BIO_new_mem_buf((void *)test_server1_cert, (int)strlen(test_server1_cert));
97  X509 *cert = PEM_read_bio_X509_AUX(pem, NULL, NULL, (char *)"");
98  SSL_CTX_use_certificate(ctx, cert);
99  X509_free(cert);
100  BIO_free(pem);
101
102  // Install server private key
103  pem = BIO_new_mem_buf((void *)test_server1_key, (int)strlen(test_server1_key));
104  EVP_PKEY *key = PEM_read_bio_PrivateKey(pem, NULL, NULL, (char *)"");
105  SSL_CTX_use_PrivateKey(ctx, key);
106  EVP_PKEY_free(key);
107  BIO_free(pem);
108
109  // Select cipher suite
110  SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES128-GCM-SHA256");
111
112  // Select ALPN protocol
113  SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, NULL);
114}
115
116unsigned int parse_h2_length(const char *field) {
117  return ((unsigned int)(unsigned char)(field[0])) * 65536 +
118         ((unsigned int)(unsigned char)(field[1])) * 256 +
119         ((unsigned int)(unsigned char)(field[2]));
120}
121
122- (void)testInternalError {
123  grpc_call *c;
124  grpc_slice request_payload_slice = grpc_slice_from_copied_string("hello world");
125  grpc_byte_buffer *request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
126  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
127  grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"),
128                              grpc_slice_from_static_string("val1"),
129                              0,
130                              {{NULL, NULL, NULL, NULL}}},
131                             {grpc_slice_from_static_string("key2"),
132                              grpc_slice_from_static_string("val2"),
133                              0,
134                              {{NULL, NULL, NULL, NULL}}}};
135
136  int port = grpc_pick_unused_port_or_die();
137  std::string addr = grpc_core::JoinHostPort("127.0.0.1", port);
138  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
139  stream_engine *cronetEngine = [Cronet getGlobalEngine];
140  grpc_channel *client = grpc_cronet_secure_channel_create(cronetEngine, addr.c_str(), NULL, NULL);
141
142  grpc_core::CqVerifier cqv(cq);
143  grpc_op ops[6];
144  grpc_op *op;
145  grpc_metadata_array initial_metadata_recv;
146  grpc_metadata_array trailing_metadata_recv;
147  grpc_metadata_array request_metadata_recv;
148  grpc_byte_buffer *response_payload_recv = NULL;
149  grpc_call_details call_details;
150  grpc_status_code status;
151  grpc_call_error error;
152  grpc_slice details;
153
154  c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
155                               grpc_slice_from_static_string("/foo"), NULL, deadline, NULL);
156  CHECK(c);
157
158  grpc_metadata_array_init(&initial_metadata_recv);
159  grpc_metadata_array_init(&trailing_metadata_recv);
160  grpc_metadata_array_init(&request_metadata_recv);
161  grpc_call_details_init(&call_details);
162
163  int sl = socket(AF_INET, SOCK_STREAM, 0);
164  CHECK(sl >= 0);
165
166  // Make an TCP endpoint to accept the connection
167  struct sockaddr_in s_addr;
168  memset(&s_addr, 0, sizeof(s_addr));
169  s_addr.sin_family = AF_INET;
170  s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
171  s_addr.sin_port = htons(port);
172  CHECK(0 == bind(sl, (struct sockaddr *)&s_addr, sizeof(s_addr)));
173  CHECK(0 == listen(sl, 5));
174
175  memset(ops, 0, sizeof(ops));
176  op = ops;
177  op->op = GRPC_OP_SEND_INITIAL_METADATA;
178  op->data.send_initial_metadata.count = 2;
179  op->data.send_initial_metadata.metadata = meta_c;
180  op->flags = 0;
181  op->reserved = NULL;
182  op++;
183  op->op = GRPC_OP_SEND_MESSAGE;
184  op->data.send_message.send_message = request_payload;
185  op->flags = 0;
186  op->reserved = NULL;
187  op++;
188  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
189  op->flags = 0;
190  op->reserved = NULL;
191  op++;
192  op->op = GRPC_OP_RECV_INITIAL_METADATA;
193  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
194  op->flags = 0;
195  op->reserved = NULL;
196  op++;
197  op->op = GRPC_OP_RECV_MESSAGE;
198  op->data.recv_message.recv_message = &response_payload_recv;
199  op->flags = 0;
200  op->reserved = NULL;
201  op++;
202  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
203  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
204  op->data.recv_status_on_client.status = &status;
205  op->data.recv_status_on_client.status_details = &details;
206  op->flags = 0;
207  op->reserved = NULL;
208  op++;
209  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), (void *)1, NULL);
210  CHECK(GRPC_CALL_OK == error);
211
212  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
213    int s = accept(sl, NULL, NULL);
214    CHECK(s >= 0);
215
216    // Close the connection after 1 second to trigger Cronet's on_failed()
217    sleep(1);
218    close(s);
219    close(sl);
220  });
221
222  cqv.Expect((void *)1, true);
223  cqv.Verify();
224
225  CHECK(status == GRPC_STATUS_UNAVAILABLE);
226
227  grpc_slice_unref(details);
228  grpc_metadata_array_destroy(&initial_metadata_recv);
229  grpc_metadata_array_destroy(&trailing_metadata_recv);
230  grpc_metadata_array_destroy(&request_metadata_recv);
231  grpc_call_details_destroy(&call_details);
232
233  grpc_call_unref(c);
234
235  grpc_byte_buffer_destroy(request_payload);
236  grpc_byte_buffer_destroy(response_payload_recv);
237
238  grpc_channel_destroy(client);
239  grpc_completion_queue_shutdown(cq);
240  drain_cq(cq);
241  grpc_completion_queue_destroy(cq);
242}
243
244- (void)packetCoalescing:(BOOL)useCoalescing {
245  grpc_arg arg;
246  arg.key = (char *)GRPC_ARG_USE_CRONET_PACKET_COALESCING;
247  arg.type = GRPC_ARG_INTEGER;
248  arg.value.integer = useCoalescing ? 1 : 0;
249  grpc_channel_args *args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
250
251  grpc_call *c;
252  grpc_slice request_payload_slice = grpc_slice_from_copied_string("hello world");
253  grpc_byte_buffer *request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
254  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
255  grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"),
256                              grpc_slice_from_static_string("val1"),
257                              0,
258                              {{NULL, NULL, NULL, NULL}}},
259                             {grpc_slice_from_static_string("key2"),
260                              grpc_slice_from_static_string("val2"),
261                              0,
262                              {{NULL, NULL, NULL, NULL}}}};
263
264  int port = grpc_pick_unused_port_or_die();
265  std::string addr = grpc_core::JoinHostPort("127.0.0.1", port);
266  grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL);
267  stream_engine *cronetEngine = [Cronet getGlobalEngine];
268  grpc_channel *client = grpc_cronet_secure_channel_create(cronetEngine, addr.c_str(), args, NULL);
269
270  grpc_core::CqVerifier cqv(cq);
271  grpc_op ops[6];
272  grpc_op *op;
273  grpc_metadata_array initial_metadata_recv;
274  grpc_metadata_array trailing_metadata_recv;
275  grpc_metadata_array request_metadata_recv;
276  grpc_byte_buffer *response_payload_recv = NULL;
277  grpc_call_details call_details;
278  grpc_status_code status;
279  grpc_call_error error;
280  grpc_slice details;
281
282  c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
283                               grpc_slice_from_static_string("/foo"), NULL, deadline, NULL);
284  CHECK(c);
285
286  grpc_metadata_array_init(&initial_metadata_recv);
287  grpc_metadata_array_init(&trailing_metadata_recv);
288  grpc_metadata_array_init(&request_metadata_recv);
289  grpc_call_details_init(&call_details);
290
291  __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Coalescing"];
292
293  int sl = socket(AF_INET, SOCK_STREAM, 0);
294  CHECK(sl >= 0);
295  struct sockaddr_in s_addr;
296  memset(&s_addr, 0, sizeof(s_addr));
297  s_addr.sin_family = AF_INET;
298  s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
299  s_addr.sin_port = htons(port);
300  CHECK(0 == bind(sl, (struct sockaddr *)&s_addr, sizeof(s_addr)));
301  CHECK(0 == listen(sl, 5));
302
303  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
304    int s = accept(sl, NULL, NULL);
305    CHECK(s >= 0);
306    struct timeval tv;
307    tv.tv_sec = 2;
308    tv.tv_usec = 0;
309    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
310
311    // Make an TLS endpoint to receive Cronet's transmission
312    SSL_CTX *ctx = SSL_CTX_new(TLSv1_2_server_method());
313    init_ctx(ctx);
314    SSL *ssl = SSL_new(ctx);
315    SSL_set_fd(ssl, s);
316    SSL_accept(ssl);
317
318    const char magic[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
319
320    char buf[4096];
321    long len;
322    BOOL coalesced = NO;
323    while ((len = SSL_read(ssl, buf, sizeof(buf))) > 0) {
324      VLOG(2) << "Read len: " << len;
325
326      // Analyze the HTTP/2 frames in the same TLS PDU to identify if
327      // coalescing is successful
328      unsigned int p = 0;
329      while (p < len) {
330        if (len - p >= 24 && 0 == memcmp(&buf[p], magic, 24)) {
331          p += 24;
332          continue;
333        }
334
335        if (buf[p + 3] == 0 &&                   // Type is DATA
336            parse_h2_length(&buf[p]) == 0x10 &&  // Length is correct
337            (buf[p + 4] & 1) != 0 &&             // EOS bit is set
338            0 == memcmp("hello world", &buf[p + 14],
339                        11)) {  // Message is correct
340          coalesced = YES;
341          break;
342        }
343        p += (parse_h2_length(&buf[p]) + 9);
344      }
345      if (coalesced) {
346        break;
347      }
348    }
349
350    XCTAssert(coalesced == useCoalescing);
351    SSL_free(ssl);
352    SSL_CTX_free(ctx);
353    close(s);
354    close(sl);
355    [expectation fulfill];
356  });
357
358  memset(ops, 0, sizeof(ops));
359  op = ops;
360  op->op = GRPC_OP_SEND_INITIAL_METADATA;
361  op->data.send_initial_metadata.count = 2;
362  op->data.send_initial_metadata.metadata = meta_c;
363  op->flags = 0;
364  op->reserved = NULL;
365  op++;
366  op->op = GRPC_OP_SEND_MESSAGE;
367  op->data.send_message.send_message = request_payload;
368  op->flags = 0;
369  op->reserved = NULL;
370  op++;
371  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
372  op->flags = 0;
373  op->reserved = NULL;
374  op++;
375  op->op = GRPC_OP_RECV_INITIAL_METADATA;
376  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
377  op->flags = 0;
378  op->reserved = NULL;
379  op++;
380  op->op = GRPC_OP_RECV_MESSAGE;
381  op->data.recv_message.recv_message = &response_payload_recv;
382  op->flags = 0;
383  op->reserved = NULL;
384  op++;
385  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
386  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
387  op->data.recv_status_on_client.status = &status;
388  op->data.recv_status_on_client.status_details = &details;
389  op->flags = 0;
390  op->reserved = NULL;
391  op++;
392  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), (void *)1, NULL);
393  CHECK(GRPC_CALL_OK == error);
394
395  cqv.Expect((void *)1, true);
396  cqv.Verify();
397
398  grpc_slice_unref(details);
399  grpc_metadata_array_destroy(&initial_metadata_recv);
400  grpc_metadata_array_destroy(&trailing_metadata_recv);
401  grpc_metadata_array_destroy(&request_metadata_recv);
402  grpc_call_details_destroy(&call_details);
403
404  grpc_call_unref(c);
405
406  grpc_byte_buffer_destroy(request_payload);
407  grpc_byte_buffer_destroy(response_payload_recv);
408
409  grpc_channel_destroy(client);
410  grpc_completion_queue_shutdown(cq);
411  drain_cq(cq);
412  grpc_completion_queue_destroy(cq);
413
414  [self waitForExpectationsWithTimeout:4 handler:nil];
415}
416
417- (void)testPacketCoalescing {
418  [self packetCoalescing:YES];
419  [self packetCoalescing:NO];
420}
421
422@end
423