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