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