xref: /aosp_15_r20/external/aws-crt-java/src/native/http2_stream_manager.c (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
1*3c7ae9deSAndroid Build Coastguard Worker /**
2*3c7ae9deSAndroid Build Coastguard Worker  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3*3c7ae9deSAndroid Build Coastguard Worker  * SPDX-License-Identifier: Apache-2.0.
4*3c7ae9deSAndroid Build Coastguard Worker  */
5*3c7ae9deSAndroid Build Coastguard Worker 
6*3c7ae9deSAndroid Build Coastguard Worker #include "crt.h"
7*3c7ae9deSAndroid Build Coastguard Worker #include "http_connection_manager.h"
8*3c7ae9deSAndroid Build Coastguard Worker #include "http_request_response.h"
9*3c7ae9deSAndroid Build Coastguard Worker #include "http_request_utils.h"
10*3c7ae9deSAndroid Build Coastguard Worker #include "java_class_ids.h"
11*3c7ae9deSAndroid Build Coastguard Worker 
12*3c7ae9deSAndroid Build Coastguard Worker #include <http_proxy_options.h>
13*3c7ae9deSAndroid Build Coastguard Worker #include <jni.h>
14*3c7ae9deSAndroid Build Coastguard Worker #include <string.h>
15*3c7ae9deSAndroid Build Coastguard Worker 
16*3c7ae9deSAndroid Build Coastguard Worker #include <aws/common/condition_variable.h>
17*3c7ae9deSAndroid Build Coastguard Worker #include <aws/common/string.h>
18*3c7ae9deSAndroid Build Coastguard Worker 
19*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/channel_bootstrap.h>
20*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/event_loop.h>
21*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/logging.h>
22*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/socket.h>
23*3c7ae9deSAndroid Build Coastguard Worker #include <aws/io/tls_channel_handler.h>
24*3c7ae9deSAndroid Build Coastguard Worker 
25*3c7ae9deSAndroid Build Coastguard Worker #include <aws/http/connection.h>
26*3c7ae9deSAndroid Build Coastguard Worker #include <aws/http/connection_manager.h>
27*3c7ae9deSAndroid Build Coastguard Worker #include <aws/http/http.h>
28*3c7ae9deSAndroid Build Coastguard Worker #include <aws/http/http2_stream_manager.h>
29*3c7ae9deSAndroid Build Coastguard Worker #include <aws/http/proxy.h>
30*3c7ae9deSAndroid Build Coastguard Worker 
31*3c7ae9deSAndroid Build Coastguard Worker /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
32*3c7ae9deSAndroid Build Coastguard Worker #if UINTPTR_MAX == 0xffffffff
33*3c7ae9deSAndroid Build Coastguard Worker #    if defined(_MSC_VER)
34*3c7ae9deSAndroid Build Coastguard Worker #        pragma warning(push)
35*3c7ae9deSAndroid Build Coastguard Worker #        pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
36*3c7ae9deSAndroid Build Coastguard Worker #    else
37*3c7ae9deSAndroid Build Coastguard Worker #        pragma GCC diagnostic push
38*3c7ae9deSAndroid Build Coastguard Worker #        pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
39*3c7ae9deSAndroid Build Coastguard Worker #        pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
40*3c7ae9deSAndroid Build Coastguard Worker #    endif
41*3c7ae9deSAndroid Build Coastguard Worker #endif
42*3c7ae9deSAndroid Build Coastguard Worker 
43*3c7ae9deSAndroid Build Coastguard Worker /*
44*3c7ae9deSAndroid Build Coastguard Worker  * Stream manager binding, persists across the lifetime of the native object.
45*3c7ae9deSAndroid Build Coastguard Worker  */
46*3c7ae9deSAndroid Build Coastguard Worker struct aws_http2_stream_manager_binding {
47*3c7ae9deSAndroid Build Coastguard Worker     JavaVM *jvm;
48*3c7ae9deSAndroid Build Coastguard Worker     jweak java_http2_stream_manager;
49*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager *stream_manager;
50*3c7ae9deSAndroid Build Coastguard Worker };
51*3c7ae9deSAndroid Build Coastguard Worker 
s_destroy_manager_binding(struct aws_http2_stream_manager_binding * binding,JNIEnv * env)52*3c7ae9deSAndroid Build Coastguard Worker static void s_destroy_manager_binding(struct aws_http2_stream_manager_binding *binding, JNIEnv *env) {
53*3c7ae9deSAndroid Build Coastguard Worker     if (binding == NULL) {
54*3c7ae9deSAndroid Build Coastguard Worker         return;
55*3c7ae9deSAndroid Build Coastguard Worker     }
56*3c7ae9deSAndroid Build Coastguard Worker     if (binding->java_http2_stream_manager != NULL) {
57*3c7ae9deSAndroid Build Coastguard Worker         (*env)->DeleteWeakGlobalRef(env, binding->java_http2_stream_manager);
58*3c7ae9deSAndroid Build Coastguard Worker     }
59*3c7ae9deSAndroid Build Coastguard Worker 
60*3c7ae9deSAndroid Build Coastguard Worker     aws_mem_release(aws_jni_get_allocator(), binding);
61*3c7ae9deSAndroid Build Coastguard Worker }
62*3c7ae9deSAndroid Build Coastguard Worker 
s_on_stream_manager_shutdown_complete_callback(void * user_data)63*3c7ae9deSAndroid Build Coastguard Worker static void s_on_stream_manager_shutdown_complete_callback(void *user_data) {
64*3c7ae9deSAndroid Build Coastguard Worker 
65*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager_binding *binding = (struct aws_http2_stream_manager_binding *)user_data;
66*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV ACQUIRE **********/
67*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env = aws_jni_acquire_thread_env(binding->jvm);
68*3c7ae9deSAndroid Build Coastguard Worker     if (env == NULL) {
69*3c7ae9deSAndroid Build Coastguard Worker         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
70*3c7ae9deSAndroid Build Coastguard Worker         return;
71*3c7ae9deSAndroid Build Coastguard Worker     }
72*3c7ae9deSAndroid Build Coastguard Worker 
73*3c7ae9deSAndroid Build Coastguard Worker     AWS_LOGF_DEBUG(AWS_LS_HTTP_STREAM_MANAGER, "Java Stream Manager Shutdown Complete");
74*3c7ae9deSAndroid Build Coastguard Worker     jobject java_http2_stream_manager = (*env)->NewLocalRef(env, binding->java_http2_stream_manager);
75*3c7ae9deSAndroid Build Coastguard Worker     if (java_http2_stream_manager != NULL) {
76*3c7ae9deSAndroid Build Coastguard Worker         (*env)->CallVoidMethod(env, java_http2_stream_manager, http2_stream_manager_properties.onShutdownComplete);
77*3c7ae9deSAndroid Build Coastguard Worker 
78*3c7ae9deSAndroid Build Coastguard Worker         /* If exception raised from Java callback, but we already closed the stream manager, just move on */
79*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_check_and_clear_exception(env);
80*3c7ae9deSAndroid Build Coastguard Worker 
81*3c7ae9deSAndroid Build Coastguard Worker         (*env)->DeleteLocalRef(env, java_http2_stream_manager);
82*3c7ae9deSAndroid Build Coastguard Worker     }
83*3c7ae9deSAndroid Build Coastguard Worker 
84*3c7ae9deSAndroid Build Coastguard Worker     /* We're done with this wrapper, free it. */
85*3c7ae9deSAndroid Build Coastguard Worker     s_destroy_manager_binding(binding, env);
86*3c7ae9deSAndroid Build Coastguard Worker     aws_jni_release_thread_env(binding->jvm, env);
87*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV RELEASE **********/
88*3c7ae9deSAndroid Build Coastguard Worker }
89*3c7ae9deSAndroid Build Coastguard Worker 
Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerNew(JNIEnv * env,jclass jni_class,jobject stream_manager_jobject,jlong jni_client_bootstrap,jlong jni_socket_options,jlong jni_tls_ctx,jlong jni_tls_connection_options,jlongArray java_marshalled_settings,jbyteArray jni_endpoint,jint jni_port,jint jni_proxy_connection_type,jbyteArray jni_proxy_host,jint jni_proxy_port,jlong jni_proxy_tls_context,jint jni_proxy_authorization_type,jbyteArray jni_proxy_authorization_username,jbyteArray jni_proxy_authorization_password,jboolean jni_manual_window_management,jlong jni_monitoring_throughput_threshold_in_bytes_per_second,jint jni_monitoring_failure_interval_in_seconds,jint jni_max_conns,jint jni_ideal_concurrent_streams_per_connection,jint jni_max_concurrent_streams_per_connection,jboolean jni_prior_knowledge,jboolean jni_close_connection_on_server_error,jint jni_connection_ping_period_ms,jint jni_connection_ping_timeout_ms)90*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT jlong JNICALL Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerNew(
91*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
92*3c7ae9deSAndroid Build Coastguard Worker     jclass jni_class,
93*3c7ae9deSAndroid Build Coastguard Worker     jobject stream_manager_jobject,
94*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_client_bootstrap,
95*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_socket_options,
96*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_tls_ctx,
97*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_tls_connection_options,
98*3c7ae9deSAndroid Build Coastguard Worker     jlongArray java_marshalled_settings,
99*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray jni_endpoint,
100*3c7ae9deSAndroid Build Coastguard Worker     jint jni_port,
101*3c7ae9deSAndroid Build Coastguard Worker     jint jni_proxy_connection_type,
102*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray jni_proxy_host,
103*3c7ae9deSAndroid Build Coastguard Worker     jint jni_proxy_port,
104*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_proxy_tls_context,
105*3c7ae9deSAndroid Build Coastguard Worker     jint jni_proxy_authorization_type,
106*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray jni_proxy_authorization_username,
107*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray jni_proxy_authorization_password,
108*3c7ae9deSAndroid Build Coastguard Worker     jboolean jni_manual_window_management,
109*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_monitoring_throughput_threshold_in_bytes_per_second,
110*3c7ae9deSAndroid Build Coastguard Worker     jint jni_monitoring_failure_interval_in_seconds,
111*3c7ae9deSAndroid Build Coastguard Worker     jint jni_max_conns,
112*3c7ae9deSAndroid Build Coastguard Worker     jint jni_ideal_concurrent_streams_per_connection,
113*3c7ae9deSAndroid Build Coastguard Worker     jint jni_max_concurrent_streams_per_connection,
114*3c7ae9deSAndroid Build Coastguard Worker     jboolean jni_prior_knowledge,
115*3c7ae9deSAndroid Build Coastguard Worker     jboolean jni_close_connection_on_server_error,
116*3c7ae9deSAndroid Build Coastguard Worker     jint jni_connection_ping_period_ms,
117*3c7ae9deSAndroid Build Coastguard Worker     jint jni_connection_ping_timeout_ms) {
118*3c7ae9deSAndroid Build Coastguard Worker 
119*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_class;
120*3c7ae9deSAndroid Build Coastguard Worker     aws_cache_jni_ids(env);
121*3c7ae9deSAndroid Build Coastguard Worker 
122*3c7ae9deSAndroid Build Coastguard Worker     struct aws_client_bootstrap *client_bootstrap = (struct aws_client_bootstrap *)jni_client_bootstrap;
123*3c7ae9deSAndroid Build Coastguard Worker     struct aws_socket_options *socket_options = (struct aws_socket_options *)jni_socket_options;
124*3c7ae9deSAndroid Build Coastguard Worker     struct aws_tls_ctx *tls_ctx = (struct aws_tls_ctx *)jni_tls_ctx;
125*3c7ae9deSAndroid Build Coastguard Worker     struct aws_tls_connection_options *tls_connection_options =
126*3c7ae9deSAndroid Build Coastguard Worker         (struct aws_tls_connection_options *)jni_tls_connection_options;
127*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager_binding *binding = NULL;
128*3c7ae9deSAndroid Build Coastguard Worker     struct aws_allocator *allocator = aws_jni_get_allocator();
129*3c7ae9deSAndroid Build Coastguard Worker 
130*3c7ae9deSAndroid Build Coastguard Worker     if (!client_bootstrap) {
131*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_illegal_argument_exception(env, "ClientBootstrap can't be null");
132*3c7ae9deSAndroid Build Coastguard Worker         return (jlong)NULL;
133*3c7ae9deSAndroid Build Coastguard Worker     }
134*3c7ae9deSAndroid Build Coastguard Worker 
135*3c7ae9deSAndroid Build Coastguard Worker     if (!socket_options) {
136*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_illegal_argument_exception(env, "SocketOptions can't be null");
137*3c7ae9deSAndroid Build Coastguard Worker         return (jlong)NULL;
138*3c7ae9deSAndroid Build Coastguard Worker     }
139*3c7ae9deSAndroid Build Coastguard Worker 
140*3c7ae9deSAndroid Build Coastguard Worker     const size_t marshalled_len = (*env)->GetArrayLength(env, java_marshalled_settings);
141*3c7ae9deSAndroid Build Coastguard Worker     AWS_ASSERT(marshalled_len % 2 == 0);
142*3c7ae9deSAndroid Build Coastguard Worker 
143*3c7ae9deSAndroid Build Coastguard Worker     size_t num_initial_settings = marshalled_len / 2;
144*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_setting *initial_settings =
145*3c7ae9deSAndroid Build Coastguard Worker         num_initial_settings ? aws_mem_calloc(allocator, num_initial_settings, sizeof(struct aws_http2_setting)) : NULL;
146*3c7ae9deSAndroid Build Coastguard Worker 
147*3c7ae9deSAndroid Build Coastguard Worker     jlong *marshalled_settings = (*env)->GetLongArrayElements(env, java_marshalled_settings, NULL);
148*3c7ae9deSAndroid Build Coastguard Worker     for (size_t i = 0; i < num_initial_settings; i++) {
149*3c7ae9deSAndroid Build Coastguard Worker         jlong id = marshalled_settings[i * 2];
150*3c7ae9deSAndroid Build Coastguard Worker         initial_settings[i].id = (uint32_t)id;
151*3c7ae9deSAndroid Build Coastguard Worker         jlong value = marshalled_settings[i * 2 + 1];
152*3c7ae9deSAndroid Build Coastguard Worker         /* We checked the value can fit into uint32_t in Java already */
153*3c7ae9deSAndroid Build Coastguard Worker         initial_settings[i].value = (uint32_t)value;
154*3c7ae9deSAndroid Build Coastguard Worker     }
155*3c7ae9deSAndroid Build Coastguard Worker 
156*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor endpoint = aws_jni_byte_cursor_from_jbyteArray_acquire(env, jni_endpoint);
157*3c7ae9deSAndroid Build Coastguard Worker 
158*3c7ae9deSAndroid Build Coastguard Worker     if (jni_port == 0) {
159*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_illegal_argument_exception(env, "Port must not be 0");
160*3c7ae9deSAndroid Build Coastguard Worker         goto cleanup;
161*3c7ae9deSAndroid Build Coastguard Worker     }
162*3c7ae9deSAndroid Build Coastguard Worker 
163*3c7ae9deSAndroid Build Coastguard Worker     if (jni_max_conns <= 0) {
164*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_illegal_argument_exception(env, "Max Connections must be > 0");
165*3c7ae9deSAndroid Build Coastguard Worker         goto cleanup;
166*3c7ae9deSAndroid Build Coastguard Worker     }
167*3c7ae9deSAndroid Build Coastguard Worker 
168*3c7ae9deSAndroid Build Coastguard Worker     uint32_t port = (uint32_t)jni_port;
169*3c7ae9deSAndroid Build Coastguard Worker 
170*3c7ae9deSAndroid Build Coastguard Worker     bool new_tls_conn_opts = (jni_tls_ctx != 0 && !tls_connection_options);
171*3c7ae9deSAndroid Build Coastguard Worker 
172*3c7ae9deSAndroid Build Coastguard Worker     struct aws_tls_connection_options tls_conn_options;
173*3c7ae9deSAndroid Build Coastguard Worker     AWS_ZERO_STRUCT(tls_conn_options);
174*3c7ae9deSAndroid Build Coastguard Worker     if (new_tls_conn_opts) {
175*3c7ae9deSAndroid Build Coastguard Worker         aws_tls_connection_options_init_from_ctx(&tls_conn_options, tls_ctx);
176*3c7ae9deSAndroid Build Coastguard Worker         aws_tls_connection_options_set_server_name(&tls_conn_options, allocator, &endpoint);
177*3c7ae9deSAndroid Build Coastguard Worker         tls_connection_options = &tls_conn_options;
178*3c7ae9deSAndroid Build Coastguard Worker     }
179*3c7ae9deSAndroid Build Coastguard Worker 
180*3c7ae9deSAndroid Build Coastguard Worker     binding = aws_mem_calloc(allocator, 1, sizeof(struct aws_http2_stream_manager_binding));
181*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(binding);
182*3c7ae9deSAndroid Build Coastguard Worker     binding->java_http2_stream_manager = (*env)->NewWeakGlobalRef(env, stream_manager_jobject);
183*3c7ae9deSAndroid Build Coastguard Worker 
184*3c7ae9deSAndroid Build Coastguard Worker     jint jvmresult = (*env)->GetJavaVM(env, &binding->jvm);
185*3c7ae9deSAndroid Build Coastguard Worker     (void)jvmresult;
186*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(jvmresult == 0);
187*3c7ae9deSAndroid Build Coastguard Worker 
188*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager_options manager_options = {
189*3c7ae9deSAndroid Build Coastguard Worker         .bootstrap = client_bootstrap,
190*3c7ae9deSAndroid Build Coastguard Worker         .initial_settings_array = initial_settings,
191*3c7ae9deSAndroid Build Coastguard Worker         .num_initial_settings = num_initial_settings,
192*3c7ae9deSAndroid Build Coastguard Worker         .socket_options = socket_options,
193*3c7ae9deSAndroid Build Coastguard Worker         .http2_prior_knowledge = jni_prior_knowledge,
194*3c7ae9deSAndroid Build Coastguard Worker         .tls_connection_options = tls_connection_options,
195*3c7ae9deSAndroid Build Coastguard Worker         .monitoring_options = NULL,
196*3c7ae9deSAndroid Build Coastguard Worker         .host = endpoint,
197*3c7ae9deSAndroid Build Coastguard Worker         .port = port,
198*3c7ae9deSAndroid Build Coastguard Worker         .shutdown_complete_callback = &s_on_stream_manager_shutdown_complete_callback,
199*3c7ae9deSAndroid Build Coastguard Worker         .shutdown_complete_user_data = binding,
200*3c7ae9deSAndroid Build Coastguard Worker         .enable_read_back_pressure = jni_manual_window_management,
201*3c7ae9deSAndroid Build Coastguard Worker         .close_connection_on_server_error = jni_close_connection_on_server_error,
202*3c7ae9deSAndroid Build Coastguard Worker         .connection_ping_period_ms = jni_connection_ping_period_ms,
203*3c7ae9deSAndroid Build Coastguard Worker         .connection_ping_timeout_ms = jni_connection_ping_timeout_ms,
204*3c7ae9deSAndroid Build Coastguard Worker         .ideal_concurrent_streams_per_connection = (size_t)jni_ideal_concurrent_streams_per_connection,
205*3c7ae9deSAndroid Build Coastguard Worker         .max_concurrent_streams_per_connection = (size_t)jni_max_concurrent_streams_per_connection,
206*3c7ae9deSAndroid Build Coastguard Worker         .max_connections = (size_t)jni_max_conns,
207*3c7ae9deSAndroid Build Coastguard Worker     };
208*3c7ae9deSAndroid Build Coastguard Worker 
209*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_connection_monitoring_options monitoring_options;
210*3c7ae9deSAndroid Build Coastguard Worker     AWS_ZERO_STRUCT(monitoring_options);
211*3c7ae9deSAndroid Build Coastguard Worker     if (jni_monitoring_throughput_threshold_in_bytes_per_second >= 0 &&
212*3c7ae9deSAndroid Build Coastguard Worker         jni_monitoring_failure_interval_in_seconds >= 2) {
213*3c7ae9deSAndroid Build Coastguard Worker         monitoring_options.minimum_throughput_bytes_per_second =
214*3c7ae9deSAndroid Build Coastguard Worker             jni_monitoring_throughput_threshold_in_bytes_per_second;
215*3c7ae9deSAndroid Build Coastguard Worker         monitoring_options.allowable_throughput_failure_interval_seconds = jni_monitoring_failure_interval_in_seconds;
216*3c7ae9deSAndroid Build Coastguard Worker 
217*3c7ae9deSAndroid Build Coastguard Worker         manager_options.monitoring_options = &monitoring_options;
218*3c7ae9deSAndroid Build Coastguard Worker     }
219*3c7ae9deSAndroid Build Coastguard Worker 
220*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_proxy_options proxy_options;
221*3c7ae9deSAndroid Build Coastguard Worker     AWS_ZERO_STRUCT(proxy_options);
222*3c7ae9deSAndroid Build Coastguard Worker 
223*3c7ae9deSAndroid Build Coastguard Worker     struct aws_tls_connection_options proxy_tls_conn_options;
224*3c7ae9deSAndroid Build Coastguard Worker     AWS_ZERO_STRUCT(proxy_tls_conn_options);
225*3c7ae9deSAndroid Build Coastguard Worker 
226*3c7ae9deSAndroid Build Coastguard Worker     aws_http_proxy_options_jni_init(
227*3c7ae9deSAndroid Build Coastguard Worker         env,
228*3c7ae9deSAndroid Build Coastguard Worker         &proxy_options,
229*3c7ae9deSAndroid Build Coastguard Worker         jni_proxy_connection_type,
230*3c7ae9deSAndroid Build Coastguard Worker         &proxy_tls_conn_options,
231*3c7ae9deSAndroid Build Coastguard Worker         jni_proxy_host,
232*3c7ae9deSAndroid Build Coastguard Worker         jni_proxy_port,
233*3c7ae9deSAndroid Build Coastguard Worker         jni_proxy_authorization_username,
234*3c7ae9deSAndroid Build Coastguard Worker         jni_proxy_authorization_password,
235*3c7ae9deSAndroid Build Coastguard Worker         jni_proxy_authorization_type,
236*3c7ae9deSAndroid Build Coastguard Worker         (struct aws_tls_ctx *)jni_proxy_tls_context);
237*3c7ae9deSAndroid Build Coastguard Worker 
238*3c7ae9deSAndroid Build Coastguard Worker     if (jni_proxy_host != NULL) {
239*3c7ae9deSAndroid Build Coastguard Worker         manager_options.proxy_options = &proxy_options;
240*3c7ae9deSAndroid Build Coastguard Worker     }
241*3c7ae9deSAndroid Build Coastguard Worker 
242*3c7ae9deSAndroid Build Coastguard Worker     binding->stream_manager = aws_http2_stream_manager_new(allocator, &manager_options);
243*3c7ae9deSAndroid Build Coastguard Worker     if (binding->stream_manager == NULL) {
244*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(env, "Failed to create stream manager: %s", aws_error_str(aws_last_error()));
245*3c7ae9deSAndroid Build Coastguard Worker     }
246*3c7ae9deSAndroid Build Coastguard Worker 
247*3c7ae9deSAndroid Build Coastguard Worker     aws_http_proxy_options_jni_clean_up(
248*3c7ae9deSAndroid Build Coastguard Worker         env, &proxy_options, jni_proxy_host, jni_proxy_authorization_username, jni_proxy_authorization_password);
249*3c7ae9deSAndroid Build Coastguard Worker 
250*3c7ae9deSAndroid Build Coastguard Worker     if (new_tls_conn_opts) {
251*3c7ae9deSAndroid Build Coastguard Worker         aws_tls_connection_options_clean_up(&tls_conn_options);
252*3c7ae9deSAndroid Build Coastguard Worker     }
253*3c7ae9deSAndroid Build Coastguard Worker 
254*3c7ae9deSAndroid Build Coastguard Worker cleanup:
255*3c7ae9deSAndroid Build Coastguard Worker     aws_jni_byte_cursor_from_jbyteArray_release(env, jni_endpoint, endpoint);
256*3c7ae9deSAndroid Build Coastguard Worker 
257*3c7ae9deSAndroid Build Coastguard Worker     if (binding->stream_manager == NULL) {
258*3c7ae9deSAndroid Build Coastguard Worker         s_destroy_manager_binding(binding, env);
259*3c7ae9deSAndroid Build Coastguard Worker         binding = NULL;
260*3c7ae9deSAndroid Build Coastguard Worker     }
261*3c7ae9deSAndroid Build Coastguard Worker 
262*3c7ae9deSAndroid Build Coastguard Worker     return (jlong)binding;
263*3c7ae9deSAndroid Build Coastguard Worker }
264*3c7ae9deSAndroid Build Coastguard Worker 
265*3c7ae9deSAndroid Build Coastguard Worker /*
266*3c7ae9deSAndroid Build Coastguard Worker  * Stream manager binding, persists across the lifetime of the native object.
267*3c7ae9deSAndroid Build Coastguard Worker  */
268*3c7ae9deSAndroid Build Coastguard Worker struct aws_sm_acquire_stream_callback_data {
269*3c7ae9deSAndroid Build Coastguard Worker     JavaVM *jvm;
270*3c7ae9deSAndroid Build Coastguard Worker     struct http_stream_binding *stream_binding;
271*3c7ae9deSAndroid Build Coastguard Worker     jobject java_async_callback;
272*3c7ae9deSAndroid Build Coastguard Worker };
273*3c7ae9deSAndroid Build Coastguard Worker 
s_cleanup_sm_acquire_stream_callback_data(struct aws_sm_acquire_stream_callback_data * callback_data,JNIEnv * env)274*3c7ae9deSAndroid Build Coastguard Worker static void s_cleanup_sm_acquire_stream_callback_data(
275*3c7ae9deSAndroid Build Coastguard Worker     struct aws_sm_acquire_stream_callback_data *callback_data,
276*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env) {
277*3c7ae9deSAndroid Build Coastguard Worker 
278*3c7ae9deSAndroid Build Coastguard Worker     if (callback_data->java_async_callback) {
279*3c7ae9deSAndroid Build Coastguard Worker         (*env)->DeleteGlobalRef(env, callback_data->java_async_callback);
280*3c7ae9deSAndroid Build Coastguard Worker     }
281*3c7ae9deSAndroid Build Coastguard Worker     aws_mem_release(aws_jni_get_allocator(), callback_data);
282*3c7ae9deSAndroid Build Coastguard Worker }
283*3c7ae9deSAndroid Build Coastguard Worker 
s_new_sm_acquire_stream_callback_data(JNIEnv * env,struct aws_allocator * allocator,struct http_stream_binding * stream_binding,jobject async_callback)284*3c7ae9deSAndroid Build Coastguard Worker static struct aws_sm_acquire_stream_callback_data *s_new_sm_acquire_stream_callback_data(
285*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
286*3c7ae9deSAndroid Build Coastguard Worker     struct aws_allocator *allocator,
287*3c7ae9deSAndroid Build Coastguard Worker     struct http_stream_binding *stream_binding,
288*3c7ae9deSAndroid Build Coastguard Worker     jobject async_callback) {
289*3c7ae9deSAndroid Build Coastguard Worker     struct aws_sm_acquire_stream_callback_data *callback_data =
290*3c7ae9deSAndroid Build Coastguard Worker         aws_mem_calloc(allocator, 1, sizeof(struct aws_sm_acquire_stream_callback_data));
291*3c7ae9deSAndroid Build Coastguard Worker 
292*3c7ae9deSAndroid Build Coastguard Worker     jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
293*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(jvmresult == 0);
294*3c7ae9deSAndroid Build Coastguard Worker     callback_data->java_async_callback = async_callback ? (*env)->NewGlobalRef(env, async_callback) : NULL;
295*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(callback_data->java_async_callback != NULL);
296*3c7ae9deSAndroid Build Coastguard Worker     callback_data->stream_binding = stream_binding;
297*3c7ae9deSAndroid Build Coastguard Worker 
298*3c7ae9deSAndroid Build Coastguard Worker     return callback_data;
299*3c7ae9deSAndroid Build Coastguard Worker }
300*3c7ae9deSAndroid Build Coastguard Worker 
s_on_stream_acquired(struct aws_http_stream * stream,int error_code,void * user_data)301*3c7ae9deSAndroid Build Coastguard Worker static void s_on_stream_acquired(struct aws_http_stream *stream, int error_code, void *user_data) {
302*3c7ae9deSAndroid Build Coastguard Worker     struct aws_sm_acquire_stream_callback_data *callback_data = user_data;
303*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV ACQUIRE **********/
304*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
305*3c7ae9deSAndroid Build Coastguard Worker     if (env == NULL) {
306*3c7ae9deSAndroid Build Coastguard Worker         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
307*3c7ae9deSAndroid Build Coastguard Worker         return;
308*3c7ae9deSAndroid Build Coastguard Worker     }
309*3c7ae9deSAndroid Build Coastguard Worker     if (error_code) {
310*3c7ae9deSAndroid Build Coastguard Worker         AWS_ASSERT(stream == NULL);
311*3c7ae9deSAndroid Build Coastguard Worker         jobject crt_exception = aws_jni_new_crt_exception_from_error_code(env, error_code);
312*3c7ae9deSAndroid Build Coastguard Worker         (*env)->CallVoidMethod(
313*3c7ae9deSAndroid Build Coastguard Worker             env, callback_data->java_async_callback, async_callback_properties.on_failure, crt_exception);
314*3c7ae9deSAndroid Build Coastguard Worker         (*env)->DeleteLocalRef(env, crt_exception);
315*3c7ae9deSAndroid Build Coastguard Worker         aws_http_stream_binding_release(env, callback_data->stream_binding);
316*3c7ae9deSAndroid Build Coastguard Worker     } else {
317*3c7ae9deSAndroid Build Coastguard Worker         /* Acquire for the native stream. The destroy callback for native stream will release the ref. */
318*3c7ae9deSAndroid Build Coastguard Worker         aws_http_stream_binding_acquire(callback_data->stream_binding);
319*3c7ae9deSAndroid Build Coastguard Worker 
320*3c7ae9deSAndroid Build Coastguard Worker         callback_data->stream_binding->native_stream = stream;
321*3c7ae9deSAndroid Build Coastguard Worker         jobject j_http_stream =
322*3c7ae9deSAndroid Build Coastguard Worker             aws_java_http_stream_from_native_new(env, callback_data->stream_binding, AWS_HTTP_VERSION_2);
323*3c7ae9deSAndroid Build Coastguard Worker         if (!j_http_stream) {
324*3c7ae9deSAndroid Build Coastguard Worker             jthrowable crt_exception = (*env)->ExceptionOccurred(env);
325*3c7ae9deSAndroid Build Coastguard Worker             AWS_ASSERT(crt_exception);
326*3c7ae9deSAndroid Build Coastguard Worker             (*env)->CallVoidMethod(
327*3c7ae9deSAndroid Build Coastguard Worker                 env, callback_data->java_async_callback, async_callback_properties.on_failure, crt_exception);
328*3c7ae9deSAndroid Build Coastguard Worker             (*env)->DeleteLocalRef(env, crt_exception);
329*3c7ae9deSAndroid Build Coastguard Worker             (*env)->ExceptionClear(env);
330*3c7ae9deSAndroid Build Coastguard Worker             /* Release the refcount on binding for the java object that failed to be created. */
331*3c7ae9deSAndroid Build Coastguard Worker             aws_http_stream_binding_release(env, callback_data->stream_binding);
332*3c7ae9deSAndroid Build Coastguard Worker         } else {
333*3c7ae9deSAndroid Build Coastguard Worker             callback_data->stream_binding->java_http_stream_base = (*env)->NewGlobalRef(env, j_http_stream);
334*3c7ae9deSAndroid Build Coastguard Worker             (*env)->CallVoidMethod(
335*3c7ae9deSAndroid Build Coastguard Worker                 env,
336*3c7ae9deSAndroid Build Coastguard Worker                 callback_data->java_async_callback,
337*3c7ae9deSAndroid Build Coastguard Worker                 async_callback_properties.on_success_with_object,
338*3c7ae9deSAndroid Build Coastguard Worker                 callback_data->stream_binding->java_http_stream_base);
339*3c7ae9deSAndroid Build Coastguard Worker             (*env)->DeleteLocalRef(env, j_http_stream);
340*3c7ae9deSAndroid Build Coastguard Worker         }
341*3c7ae9deSAndroid Build Coastguard Worker     }
342*3c7ae9deSAndroid Build Coastguard Worker     AWS_FATAL_ASSERT(!aws_jni_check_and_clear_exception(env));
343*3c7ae9deSAndroid Build Coastguard Worker     s_cleanup_sm_acquire_stream_callback_data(callback_data, env);
344*3c7ae9deSAndroid Build Coastguard Worker     aws_jni_release_thread_env(callback_data->jvm, env);
345*3c7ae9deSAndroid Build Coastguard Worker     /********** JNI ENV RELEASE **********/
346*3c7ae9deSAndroid Build Coastguard Worker }
347*3c7ae9deSAndroid Build Coastguard Worker 
Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerAcquireStream(JNIEnv * env,jclass jni_class,jlong jni_stream_manager,jbyteArray marshalled_request,jobject jni_http_request_body_stream,jobject jni_http_response_callback_handler,jobject java_async_callback)348*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerAcquireStream(
349*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
350*3c7ae9deSAndroid Build Coastguard Worker     jclass jni_class,
351*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_stream_manager,
352*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray marshalled_request,
353*3c7ae9deSAndroid Build Coastguard Worker     jobject jni_http_request_body_stream,
354*3c7ae9deSAndroid Build Coastguard Worker     jobject jni_http_response_callback_handler,
355*3c7ae9deSAndroid Build Coastguard Worker     jobject java_async_callback) {
356*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_class;
357*3c7ae9deSAndroid Build Coastguard Worker     aws_cache_jni_ids(env);
358*3c7ae9deSAndroid Build Coastguard Worker 
359*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager_binding *sm_binding = (struct aws_http2_stream_manager_binding *)jni_stream_manager;
360*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager *stream_manager = sm_binding->stream_manager;
361*3c7ae9deSAndroid Build Coastguard Worker 
362*3c7ae9deSAndroid Build Coastguard Worker     if (!stream_manager) {
363*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_illegal_argument_exception(env, "Stream Manager can't be null");
364*3c7ae9deSAndroid Build Coastguard Worker         return;
365*3c7ae9deSAndroid Build Coastguard Worker     }
366*3c7ae9deSAndroid Build Coastguard Worker 
367*3c7ae9deSAndroid Build Coastguard Worker     if (!jni_http_response_callback_handler) {
368*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_illegal_argument_exception(
369*3c7ae9deSAndroid Build Coastguard Worker             env, "Http2StreamManager.acquireStream: Invalid jni_http_response_callback_handler");
370*3c7ae9deSAndroid Build Coastguard Worker         return;
371*3c7ae9deSAndroid Build Coastguard Worker     }
372*3c7ae9deSAndroid Build Coastguard Worker     if (!java_async_callback) {
373*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_illegal_argument_exception(env, "Http2StreamManager.acquireStream: Invalid async callback");
374*3c7ae9deSAndroid Build Coastguard Worker         return;
375*3c7ae9deSAndroid Build Coastguard Worker     }
376*3c7ae9deSAndroid Build Coastguard Worker 
377*3c7ae9deSAndroid Build Coastguard Worker     struct http_stream_binding *stream_binding = aws_http_stream_binding_new(env, jni_http_response_callback_handler);
378*3c7ae9deSAndroid Build Coastguard Worker     if (!stream_binding) {
379*3c7ae9deSAndroid Build Coastguard Worker         /* Exception already thrown */
380*3c7ae9deSAndroid Build Coastguard Worker         return;
381*3c7ae9deSAndroid Build Coastguard Worker     }
382*3c7ae9deSAndroid Build Coastguard Worker 
383*3c7ae9deSAndroid Build Coastguard Worker     stream_binding->native_request =
384*3c7ae9deSAndroid Build Coastguard Worker         aws_http_request_new_from_java_http_request(env, marshalled_request, jni_http_request_body_stream);
385*3c7ae9deSAndroid Build Coastguard Worker     if (stream_binding->native_request == NULL) {
386*3c7ae9deSAndroid Build Coastguard Worker         /* Exception already thrown */
387*3c7ae9deSAndroid Build Coastguard Worker         aws_http_stream_binding_release(env, stream_binding);
388*3c7ae9deSAndroid Build Coastguard Worker         return;
389*3c7ae9deSAndroid Build Coastguard Worker     }
390*3c7ae9deSAndroid Build Coastguard Worker 
391*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_make_request_options request_options = {
392*3c7ae9deSAndroid Build Coastguard Worker         .self_size = sizeof(request_options),
393*3c7ae9deSAndroid Build Coastguard Worker         .request = stream_binding->native_request,
394*3c7ae9deSAndroid Build Coastguard Worker         /* Set Callbacks */
395*3c7ae9deSAndroid Build Coastguard Worker         .on_response_headers = aws_java_http_stream_on_incoming_headers_fn,
396*3c7ae9deSAndroid Build Coastguard Worker         .on_response_header_block_done = aws_java_http_stream_on_incoming_header_block_done_fn,
397*3c7ae9deSAndroid Build Coastguard Worker         .on_response_body = aws_java_http_stream_on_incoming_body_fn,
398*3c7ae9deSAndroid Build Coastguard Worker         .on_complete = aws_java_http_stream_on_stream_complete_fn,
399*3c7ae9deSAndroid Build Coastguard Worker         .on_destroy = aws_java_http_stream_on_stream_destroy_fn,
400*3c7ae9deSAndroid Build Coastguard Worker         .user_data = stream_binding,
401*3c7ae9deSAndroid Build Coastguard Worker     };
402*3c7ae9deSAndroid Build Coastguard Worker 
403*3c7ae9deSAndroid Build Coastguard Worker     struct aws_allocator *allocator = aws_jni_get_allocator();
404*3c7ae9deSAndroid Build Coastguard Worker     struct aws_sm_acquire_stream_callback_data *callback_data =
405*3c7ae9deSAndroid Build Coastguard Worker         s_new_sm_acquire_stream_callback_data(env, allocator, stream_binding, java_async_callback);
406*3c7ae9deSAndroid Build Coastguard Worker 
407*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager_acquire_stream_options acquire_options = {
408*3c7ae9deSAndroid Build Coastguard Worker         .options = &request_options,
409*3c7ae9deSAndroid Build Coastguard Worker         .callback = s_on_stream_acquired,
410*3c7ae9deSAndroid Build Coastguard Worker         .user_data = callback_data,
411*3c7ae9deSAndroid Build Coastguard Worker     };
412*3c7ae9deSAndroid Build Coastguard Worker 
413*3c7ae9deSAndroid Build Coastguard Worker     aws_http2_stream_manager_acquire_stream(sm_binding->stream_manager, &acquire_options);
414*3c7ae9deSAndroid Build Coastguard Worker }
415*3c7ae9deSAndroid Build Coastguard Worker 
Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerRelease(JNIEnv * env,jclass jni_class,jlong jni_stream_manager)416*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT void JNICALL Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerRelease(
417*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
418*3c7ae9deSAndroid Build Coastguard Worker     jclass jni_class,
419*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_stream_manager) {
420*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_class;
421*3c7ae9deSAndroid Build Coastguard Worker     aws_cache_jni_ids(env);
422*3c7ae9deSAndroid Build Coastguard Worker 
423*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager_binding *sm_binding = (struct aws_http2_stream_manager_binding *)jni_stream_manager;
424*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager *stream_manager = sm_binding->stream_manager;
425*3c7ae9deSAndroid Build Coastguard Worker 
426*3c7ae9deSAndroid Build Coastguard Worker     if (!stream_manager) {
427*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(env, "Stream Manager can't be null");
428*3c7ae9deSAndroid Build Coastguard Worker         return;
429*3c7ae9deSAndroid Build Coastguard Worker     }
430*3c7ae9deSAndroid Build Coastguard Worker 
431*3c7ae9deSAndroid Build Coastguard Worker     AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "Releasing StreamManager: id: %p", (void *)stream_manager);
432*3c7ae9deSAndroid Build Coastguard Worker     aws_http2_stream_manager_release(stream_manager);
433*3c7ae9deSAndroid Build Coastguard Worker }
434*3c7ae9deSAndroid Build Coastguard Worker 
Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerFetchMetrics(JNIEnv * env,jclass jni_class,jlong jni_stream_manager)435*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT jobject JNICALL Java_software_amazon_awssdk_crt_http_Http2StreamManager_http2StreamManagerFetchMetrics(
436*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
437*3c7ae9deSAndroid Build Coastguard Worker     jclass jni_class,
438*3c7ae9deSAndroid Build Coastguard Worker     jlong jni_stream_manager) {
439*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_class;
440*3c7ae9deSAndroid Build Coastguard Worker     aws_cache_jni_ids(env);
441*3c7ae9deSAndroid Build Coastguard Worker 
442*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager_binding *sm_binding = (struct aws_http2_stream_manager_binding *)jni_stream_manager;
443*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http2_stream_manager *stream_manager = sm_binding->stream_manager;
444*3c7ae9deSAndroid Build Coastguard Worker 
445*3c7ae9deSAndroid Build Coastguard Worker     if (!stream_manager) {
446*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(env, "Stream Manager can't be null");
447*3c7ae9deSAndroid Build Coastguard Worker         return NULL;
448*3c7ae9deSAndroid Build Coastguard Worker     }
449*3c7ae9deSAndroid Build Coastguard Worker 
450*3c7ae9deSAndroid Build Coastguard Worker     struct aws_http_manager_metrics metrics;
451*3c7ae9deSAndroid Build Coastguard Worker     aws_http2_stream_manager_fetch_metrics(stream_manager, &metrics);
452*3c7ae9deSAndroid Build Coastguard Worker 
453*3c7ae9deSAndroid Build Coastguard Worker     return (*env)->NewObject(
454*3c7ae9deSAndroid Build Coastguard Worker         env,
455*3c7ae9deSAndroid Build Coastguard Worker         http_manager_metrics_properties.http_manager_metrics_class,
456*3c7ae9deSAndroid Build Coastguard Worker         http_manager_metrics_properties.constructor_method_id,
457*3c7ae9deSAndroid Build Coastguard Worker         (jlong)metrics.available_concurrency,
458*3c7ae9deSAndroid Build Coastguard Worker         (jlong)metrics.pending_concurrency_acquires,
459*3c7ae9deSAndroid Build Coastguard Worker         (jlong)metrics.leased_concurrency);
460*3c7ae9deSAndroid Build Coastguard Worker }
461