1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5
6 #include <jni.h>
7
8 #include <aws/event-stream/event_stream_rpc_server.h>
9
10 #include <aws/common/string.h>
11 #include <aws/io/tls_channel_handler.h>
12
13 #include "crt.h"
14 #include "event_stream_message.h"
15 #include "java_class_ids.h"
16
17 #if defined(_MSC_VER)
18 # pragma warning(disable : 4204) /* non-constant aggregate initializer */
19 #endif
20
21 /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
22 #if UINTPTR_MAX == 0xffffffff
23 # if defined(_MSC_VER)
24 # pragma warning(push)
25 # pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
26 # else
27 # pragma GCC diagnostic push
28 # pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
29 # pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
30 # endif
31 #endif
32
33 struct shutdown_callback_data {
34 JavaVM *jvm;
35 jweak java_server_listener;
36 jobject java_listener_handler;
37 };
38
s_shutdown_callback_data_destroy(JNIEnv * env,struct shutdown_callback_data * callback_data)39 static void s_shutdown_callback_data_destroy(JNIEnv *env, struct shutdown_callback_data *callback_data) {
40
41 if (!callback_data) {
42 return;
43 }
44
45 if (callback_data->java_server_listener) {
46 (*env)->DeleteWeakGlobalRef(env, callback_data->java_server_listener);
47 }
48
49 if (callback_data->java_listener_handler) {
50 (*env)->DeleteGlobalRef(env, callback_data->java_listener_handler);
51 }
52
53 aws_mem_release(aws_jni_get_allocator(), callback_data);
54 }
55
56 struct connection_callback_data {
57 JavaVM *jvm;
58 jobject java_server_connection;
59 jweak java_listener_handler;
60 jobject java_connection_handler;
61 };
62
s_server_connection_data_destroy(JNIEnv * env,struct connection_callback_data * callback_data)63 static void s_server_connection_data_destroy(JNIEnv *env, struct connection_callback_data *callback_data) {
64 if (!callback_data) {
65 return;
66 }
67
68 if (callback_data->java_listener_handler) {
69 (*env)->DeleteGlobalRef(env, callback_data->java_listener_handler);
70 }
71
72 if (callback_data->java_server_connection) {
73 (*env)->DeleteGlobalRef(env, callback_data->java_server_connection);
74 }
75
76 if (callback_data->java_connection_handler) {
77 (*env)->DeleteGlobalRef(env, callback_data->java_connection_handler);
78 }
79
80 aws_mem_release(aws_jni_get_allocator(), callback_data);
81 }
82
s_server_listener_shutdown_complete(struct aws_event_stream_rpc_server_listener * listener,void * user_data)83 static void s_server_listener_shutdown_complete(
84 struct aws_event_stream_rpc_server_listener *listener,
85 void *user_data) {
86 (void)listener;
87
88 struct shutdown_callback_data *callback_data = user_data;
89
90 /********** JNI ENV ACQUIRE **********/
91 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
92 if (env == NULL) {
93 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
94 return;
95 }
96
97 jobject java_server_listener = (*env)->NewLocalRef(env, callback_data->java_server_listener);
98 if (java_server_listener) {
99 (*env)->CallVoidMethod(env, java_server_listener, event_stream_server_listener_properties.onShutdownComplete);
100 aws_jni_check_and_clear_exception(env);
101 (*env)->DeleteLocalRef(env, java_server_listener);
102 }
103
104 JavaVM *jvm = callback_data->jvm;
105 s_shutdown_callback_data_destroy(env, callback_data);
106 aws_jni_release_thread_env(jvm, env);
107 /********** JNI ENV RELEASE **********/
108 }
109
110 struct continuation_callback_data {
111 JavaVM *jvm;
112 jobject java_continuation;
113 jobject java_continuation_handler;
114 };
115
s_server_continuation_data_destroy(JNIEnv * env,struct continuation_callback_data * callback_data)116 static void s_server_continuation_data_destroy(JNIEnv *env, struct continuation_callback_data *callback_data) {
117 if (!callback_data) {
118 return;
119 }
120
121 if (callback_data->java_continuation_handler) {
122 (*env)->DeleteGlobalRef(env, callback_data->java_continuation_handler);
123 }
124
125 if (callback_data->java_continuation) {
126 (*env)->DeleteGlobalRef(env, callback_data->java_continuation);
127 }
128
129 aws_mem_release(aws_jni_get_allocator(), callback_data);
130 }
131
s_stream_continuation_fn(struct aws_event_stream_rpc_server_continuation_token * token,const struct aws_event_stream_rpc_message_args * message_args,void * user_data)132 static void s_stream_continuation_fn(
133 struct aws_event_stream_rpc_server_continuation_token *token,
134 const struct aws_event_stream_rpc_message_args *message_args,
135 void *user_data) {
136 (void)token;
137
138 struct continuation_callback_data *callback_data = user_data;
139
140 /********** JNI ENV ACQUIRE **********/
141 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
142 if (env == NULL) {
143 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
144 return;
145 }
146
147 jbyteArray headers_array = aws_event_stream_rpc_marshall_headers_to_byteArray(
148 aws_jni_get_allocator(), env, message_args->headers, message_args->headers_count);
149
150 struct aws_byte_cursor payload_cur = aws_byte_cursor_from_buf(message_args->payload);
151 jbyteArray payload_byte_array = aws_jni_byte_array_from_cursor(env, &payload_cur);
152 (*env)->CallVoidMethod(
153 env,
154 callback_data->java_continuation_handler,
155 event_stream_server_continuation_handler_properties.onContinuationMessage,
156 headers_array,
157 payload_byte_array,
158 (jint)message_args->message_type,
159 (jint)message_args->message_flags);
160 (*env)->DeleteLocalRef(env, headers_array);
161 (*env)->DeleteLocalRef(env, payload_byte_array);
162 /* don't really care if they threw here, but we want to make the jvm happy that we checked */
163 aws_jni_check_and_clear_exception(env);
164
165 aws_jni_release_thread_env(callback_data->jvm, env);
166 /********** JNI ENV RELEASE **********/
167 }
168
s_stream_continuation_closed_fn(struct aws_event_stream_rpc_server_continuation_token * token,void * user_data)169 static void s_stream_continuation_closed_fn(
170 struct aws_event_stream_rpc_server_continuation_token *token,
171 void *user_data) {
172 (void)token;
173 struct continuation_callback_data *continuation_callback_data = user_data;
174
175 /********** JNI ENV ACQUIRE **********/
176 JNIEnv *env = aws_jni_acquire_thread_env(continuation_callback_data->jvm);
177 if (env == NULL) {
178 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
179 return;
180 }
181
182 (*env)->CallVoidMethod(
183 env,
184 continuation_callback_data->java_continuation_handler,
185 event_stream_server_continuation_handler_properties.onContinuationClosed);
186 /* don't really care if they threw here, but we want to make the jvm happy that we checked */
187 aws_jni_check_and_clear_exception(env);
188
189 JavaVM *jvm = continuation_callback_data->jvm;
190 s_server_continuation_data_destroy(env, continuation_callback_data);
191 aws_jni_release_thread_env(jvm, env);
192 /********** JNI ENV RELEASE **********/
193 }
194
s_on_incoming_stream_fn(struct aws_event_stream_rpc_server_connection * connection,struct aws_event_stream_rpc_server_continuation_token * token,struct aws_byte_cursor operation_name,struct aws_event_stream_rpc_server_stream_continuation_options * continuation_options,void * user_data)195 static int s_on_incoming_stream_fn(
196 struct aws_event_stream_rpc_server_connection *connection,
197 struct aws_event_stream_rpc_server_continuation_token *token,
198 struct aws_byte_cursor operation_name,
199 struct aws_event_stream_rpc_server_stream_continuation_options *continuation_options,
200 void *user_data) {
201 (void)connection;
202
203 struct connection_callback_data *callback_data = user_data;
204
205 jobject java_continuation = NULL;
206 jobject java_continuation_handler = NULL;
207
208 /********** JNI ENV ACQUIRE **********/
209 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
210 if (env == NULL) {
211 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
212 return AWS_OP_ERR;
213 }
214
215 struct continuation_callback_data *continuation_callback_data =
216 aws_mem_calloc(aws_jni_get_allocator(), 1, sizeof(struct continuation_callback_data));
217
218 if (!continuation_callback_data) {
219 goto on_error;
220 }
221
222 continuation_callback_data->jvm = callback_data->jvm;
223
224 java_continuation = (*env)->NewObject(
225 env,
226 event_stream_server_connection_handler_properties.continuationCls,
227 event_stream_server_connection_handler_properties.newContinuationConstructor,
228 (jlong)token);
229
230 aws_jni_check_and_clear_exception(env);
231
232 if (!java_continuation) {
233 aws_raise_error(AWS_ERROR_INVALID_STATE);
234 goto on_error;
235 }
236
237 continuation_callback_data->java_continuation = (*env)->NewGlobalRef(env, java_continuation);
238 if (continuation_callback_data->java_continuation == NULL) {
239 aws_raise_error(AWS_ERROR_INVALID_STATE);
240 goto on_error;
241 }
242
243 java_continuation_handler = NULL;
244 jbyteArray operation_name_array = aws_jni_byte_array_from_cursor(env, &operation_name);
245 if (operation_name_array != NULL) {
246 java_continuation_handler = (*env)->CallObjectMethod(
247 env,
248 callback_data->java_connection_handler,
249 event_stream_server_connection_handler_properties.onIncomingStream,
250 java_continuation,
251 operation_name_array);
252 (*env)->DeleteLocalRef(env, operation_name_array);
253 aws_jni_check_and_clear_exception(env);
254 }
255
256 if (!java_continuation_handler) {
257 aws_raise_error(AWS_ERROR_INVALID_STATE);
258 goto on_error;
259 }
260
261 continuation_callback_data->java_continuation_handler = (*env)->NewGlobalRef(env, java_continuation_handler);
262 if (continuation_callback_data->java_continuation_handler == NULL) {
263 aws_raise_error(AWS_ERROR_INVALID_STATE);
264 goto on_error;
265 }
266
267 continuation_options->user_data = continuation_callback_data;
268 continuation_options->on_continuation = s_stream_continuation_fn;
269 continuation_options->on_continuation_closed = s_stream_continuation_closed_fn;
270
271 (*env)->DeleteLocalRef(env, java_continuation_handler);
272 (*env)->DeleteLocalRef(env, java_continuation);
273
274 aws_jni_release_thread_env(callback_data->jvm, env);
275 /********** JNI ENV RELEASE SUCCESS PATH **********/
276
277 return AWS_OP_SUCCESS;
278
279 on_error:
280
281 if (java_continuation_handler != NULL) {
282 (*env)->DeleteLocalRef(env, java_continuation_handler);
283 }
284
285 if (java_continuation != NULL) {
286 (*env)->DeleteLocalRef(env, java_continuation);
287 }
288
289 aws_event_stream_rpc_server_connection_close(connection, aws_last_error());
290 s_server_continuation_data_destroy(env, continuation_callback_data);
291
292 aws_jni_release_thread_env(callback_data->jvm, env);
293 /********** JNI ENV RELEASE FAILURE PATH **********/
294
295 return AWS_OP_ERR;
296 }
297
s_connection_protocol_message_fn(struct aws_event_stream_rpc_server_connection * connection,const struct aws_event_stream_rpc_message_args * message_args,void * user_data)298 static void s_connection_protocol_message_fn(
299 struct aws_event_stream_rpc_server_connection *connection,
300 const struct aws_event_stream_rpc_message_args *message_args,
301 void *user_data) {
302 (void)connection;
303
304 struct connection_callback_data *callback_data = user_data;
305
306 /********** JNI ENV ACQUIRE **********/
307 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
308 if (env == NULL) {
309 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
310 return;
311 }
312
313 jbyteArray headers_array = aws_event_stream_rpc_marshall_headers_to_byteArray(
314 aws_jni_get_allocator(), env, message_args->headers, message_args->headers_count);
315
316 struct aws_byte_cursor payload_cur = aws_byte_cursor_from_buf(message_args->payload);
317 jbyteArray payload_byte_array = aws_jni_byte_array_from_cursor(env, &payload_cur);
318
319 (*env)->CallVoidMethod(
320 env,
321 callback_data->java_connection_handler,
322 event_stream_server_connection_handler_properties.onProtocolMessage,
323 headers_array,
324 payload_byte_array,
325 (jint)message_args->message_type,
326 (jint)message_args->message_flags);
327 (*env)->DeleteLocalRef(env, headers_array);
328 (*env)->DeleteLocalRef(env, payload_byte_array);
329 /* don't really care if they threw here, but we want to make the jvm happy that we checked */
330 aws_jni_check_and_clear_exception(env);
331
332 aws_jni_release_thread_env(callback_data->jvm, env);
333 /********** JNI ENV RELEASE **********/
334 }
335
s_on_new_connection_fn(struct aws_event_stream_rpc_server_connection * connection,int error_code,struct aws_event_stream_rpc_connection_options * connection_options,void * user_data)336 static int s_on_new_connection_fn(
337 struct aws_event_stream_rpc_server_connection *connection,
338 int error_code,
339 struct aws_event_stream_rpc_connection_options *connection_options,
340 void *user_data) {
341
342 struct shutdown_callback_data *callback_data = user_data;
343
344 /********** JNI ENV ACQUIRE **********/
345 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
346 if (env == NULL) {
347 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
348 return AWS_OP_ERR;
349 }
350
351 jobject java_server_connection = NULL;
352 jobject java_connection_handler = NULL;
353
354 struct connection_callback_data *connection_callback_data =
355 aws_mem_calloc(aws_jni_get_allocator(), 1, sizeof(struct connection_callback_data));
356
357 if (!connection_callback_data) {
358 goto error;
359 }
360
361 connection_callback_data->jvm = callback_data->jvm;
362 connection_callback_data->java_listener_handler = (*env)->NewGlobalRef(env, callback_data->java_listener_handler);
363
364 if (!error_code) {
365 java_server_connection = (*env)->NewObject(
366 env,
367 event_stream_server_listener_handler_properties.connCls,
368 event_stream_server_listener_handler_properties.newConnConstructor,
369 (jlong)connection);
370 if (aws_jni_check_and_clear_exception(env) || java_server_connection == NULL) {
371 aws_raise_error(AWS_ERROR_INVALID_STATE);
372 goto error;
373 }
374
375 connection_callback_data->java_server_connection = (*env)->NewGlobalRef(env, java_server_connection);
376 }
377
378 java_connection_handler = (*env)->CallObjectMethod(
379 env,
380 connection_callback_data->java_listener_handler,
381 event_stream_server_listener_handler_properties.onNewConnection,
382 java_server_connection,
383 error_code);
384
385 /* we check whether the function succeeded when we do the null check on java_connection_handler below */
386 aws_jni_check_and_clear_exception(env);
387
388 if (!java_connection_handler) {
389 aws_raise_error(AWS_ERROR_INVALID_STATE);
390 goto error;
391 }
392
393 connection_callback_data->java_connection_handler = (*env)->NewGlobalRef(env, java_connection_handler);
394 if (connection_callback_data->java_connection_handler == NULL) {
395 aws_raise_error(AWS_ERROR_INVALID_STATE);
396 goto error;
397 }
398
399 /* Nothing can fail after here */
400 connection_options->on_connection_protocol_message = s_connection_protocol_message_fn;
401 connection_options->on_incoming_stream = s_on_incoming_stream_fn;
402 connection_options->user_data = connection_callback_data;
403
404 (*env)->DeleteLocalRef(env, java_connection_handler);
405 (*env)->DeleteLocalRef(env, java_server_connection);
406
407 aws_jni_release_thread_env(callback_data->jvm, env);
408 /********** JNI ENV RELEASE SUCCESS PATH **********/
409
410 return AWS_OP_SUCCESS;
411
412 error:
413
414 if (java_connection_handler != NULL) {
415 (*env)->DeleteLocalRef(env, java_connection_handler);
416 }
417
418 if (java_server_connection != NULL) {
419 (*env)->DeleteLocalRef(env, java_server_connection);
420 }
421
422 s_server_connection_data_destroy(env, connection_callback_data);
423
424 aws_jni_release_thread_env(callback_data->jvm, env);
425 /********** JNI ENV RELEASE ERROR PATH **********/
426
427 return AWS_OP_ERR;
428 }
429
s_on_connection_shutdown_fn(struct aws_event_stream_rpc_server_connection * connection,int error_code,void * user_data)430 static void s_on_connection_shutdown_fn(
431 struct aws_event_stream_rpc_server_connection *connection,
432 int error_code,
433 void *user_data) {
434
435 (void)user_data;
436 struct connection_callback_data *callback_data = aws_event_stream_rpc_server_connection_get_user_data(connection);
437 if (!callback_data) {
438 /* The connection was not setup correctly. Probably failed within s_on_new_connection_fn. Early out. */
439 return;
440 }
441
442 /********** JNI ENV ACQUIRE **********/
443 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
444 if (env == NULL) {
445 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
446 return;
447 }
448
449 jobject java_listener_handler = (*env)->NewLocalRef(env, callback_data->java_listener_handler);
450 jobject java_server_connection = (*env)->NewLocalRef(env, callback_data->java_server_connection);
451
452 AWS_FATAL_ASSERT(java_listener_handler);
453 AWS_FATAL_ASSERT(java_server_connection);
454
455 /* Tell the Java ListenerHandler that the connection shutdown. */
456 (*env)->CallVoidMethod(
457 env,
458 java_listener_handler,
459 event_stream_server_listener_handler_properties.onConnectionShutdown,
460 java_server_connection,
461 error_code);
462 aws_jni_check_and_clear_exception(env);
463
464 (*env)->DeleteLocalRef(env, java_server_connection);
465 (*env)->DeleteLocalRef(env, java_listener_handler);
466
467 /* this is the should be connection specific callback data. */
468 JavaVM *jvm = callback_data->jvm;
469 s_server_connection_data_destroy(env, callback_data);
470 aws_jni_release_thread_env(jvm, env);
471 /********** JNI ENV RELEASE **********/
472 }
473
474 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerListener_serverListenerNew(JNIEnv * env,jclass jni_class,jobject jni_server_listener,jbyteArray jni_host_name,jint port,jlong jni_socket_options,jlong jni_tls_ctx,jlong jni_server_bootstrap,jobject jni_server_listener_handler)475 jlong JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerListener_serverListenerNew(
476 JNIEnv *env,
477 jclass jni_class,
478 jobject jni_server_listener,
479 jbyteArray jni_host_name,
480 jint port,
481 jlong jni_socket_options,
482 jlong jni_tls_ctx,
483 jlong jni_server_bootstrap,
484 jobject jni_server_listener_handler) {
485 (void)jni_class;
486 aws_cache_jni_ids(env);
487
488 struct aws_server_bootstrap *server_bootstrap = (struct aws_server_bootstrap *)jni_server_bootstrap;
489 struct aws_socket_options *socket_options = (struct aws_socket_options *)jni_socket_options;
490 struct aws_tls_ctx *tls_context = (struct aws_tls_ctx *)jni_tls_ctx;
491
492 if (!server_bootstrap) {
493 aws_jni_throw_runtime_exception(env, "ServerListener.server_listener_new: Invalid ServerBootstrap");
494 return (jlong)NULL;
495 }
496
497 if (!socket_options) {
498 aws_jni_throw_runtime_exception(env, "ServerListener.server_listener_new: Invalid SocketOptions");
499 return (jlong)NULL;
500 }
501
502 struct aws_tls_connection_options connection_options;
503 AWS_ZERO_STRUCT(connection_options);
504 struct aws_tls_connection_options *conn_options_ptr = NULL;
505 struct aws_string *host_name_str = NULL;
506
507 if (tls_context) {
508 aws_tls_connection_options_init_from_ctx(&connection_options, tls_context);
509 conn_options_ptr = &connection_options;
510 }
511
512 struct aws_allocator *allocator = aws_jni_get_allocator();
513
514 struct shutdown_callback_data *callback_data = aws_mem_calloc(allocator, 1, sizeof(struct shutdown_callback_data));
515 if (!callback_data) {
516 aws_jni_throw_runtime_exception(env, "ServerListener.server_listener_new: Unable to allocate");
517 goto error;
518 }
519
520 jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
521 if (jvmresult != 0) {
522 aws_jni_throw_runtime_exception(env, "ServerListener.server_listener_new: Unable to get JVM");
523 goto error;
524 }
525
526 callback_data->java_server_listener = (*env)->NewWeakGlobalRef(env, jni_server_listener);
527 if (!callback_data->java_server_listener) {
528 aws_jni_throw_runtime_exception(env, "ServerListener.server_listener_new: Unable to create global weak ref");
529 goto error;
530 }
531
532 callback_data->java_listener_handler = (*env)->NewGlobalRef(env, jni_server_listener_handler);
533 if (!callback_data->java_listener_handler) {
534 aws_jni_throw_runtime_exception(env, "ServerListener.server_listener_new: Unable to create global ref");
535 goto error;
536 }
537
538 const size_t host_name_len = (*env)->GetArrayLength(env, jni_host_name);
539 jbyte *host_name = (*env)->GetPrimitiveArrayCritical(env, jni_host_name, NULL);
540 host_name_str = aws_string_new_from_array(allocator, (uint8_t *)host_name, host_name_len);
541 (*env)->ReleasePrimitiveArrayCritical(env, jni_host_name, host_name, 0);
542
543 if (!host_name_str) {
544 aws_jni_throw_runtime_exception(env, "ServerListener.server_listener_new: Unable to allocate");
545 goto error;
546 }
547
548 const char *c_str_host_name = aws_string_c_str(host_name_str);
549
550 struct aws_event_stream_rpc_server_listener_options listener_options = {
551 .socket_options = socket_options,
552 .on_destroy_callback = s_server_listener_shutdown_complete,
553 .bootstrap = server_bootstrap,
554 .tls_options = conn_options_ptr,
555 .port = (uint32_t)port,
556 .host_name = c_str_host_name,
557 .user_data = callback_data,
558 .on_new_connection = s_on_new_connection_fn,
559 .on_connection_shutdown = s_on_connection_shutdown_fn,
560 };
561
562 struct aws_event_stream_rpc_server_listener *listener =
563 aws_event_stream_rpc_server_new_listener(allocator, &listener_options);
564 aws_string_destroy(host_name_str);
565 host_name_str = NULL;
566
567 if (!listener) {
568 aws_jni_throw_runtime_exception(
569 env, "ServerBootstrap.server_bootstrap_new: Unable to allocate new aws_event_stream_rpc_server_listener");
570 goto error;
571 }
572
573 return (jlong)listener;
574
575 error:
576 if (host_name_str) {
577 aws_string_destroy(host_name_str);
578 }
579
580 if (conn_options_ptr) {
581 aws_tls_connection_options_clean_up(conn_options_ptr);
582 }
583
584 s_shutdown_callback_data_destroy(env, callback_data);
585 return (jlong)NULL;
586 }
587
588 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerListener_getBoundPort(JNIEnv * env,jclass jni_class,jlong jni_server_listener)589 jint JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerListener_getBoundPort(
590 JNIEnv *env,
591 jclass jni_class,
592 jlong jni_server_listener) {
593 (void)env;
594 (void)jni_class;
595 aws_cache_jni_ids(env);
596
597 struct aws_event_stream_rpc_server_listener *listener =
598 (struct aws_event_stream_rpc_server_listener *)jni_server_listener;
599 if (!listener) {
600 aws_jni_throw_runtime_exception(env, "ServerListener.getBoundPort: Invalid serverListener");
601 return -1;
602 }
603
604 return (jint)aws_event_stream_rpc_server_listener_get_bound_port(listener);
605 }
606
607 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerListener_release(JNIEnv * env,jclass jni_class,jlong jni_server_listener)608 void JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerListener_release(
609 JNIEnv *env,
610 jclass jni_class,
611 jlong jni_server_listener) {
612 (void)env;
613 (void)jni_class;
614 aws_cache_jni_ids(env);
615
616 struct aws_event_stream_rpc_server_listener *listener =
617 (struct aws_event_stream_rpc_server_listener *)jni_server_listener;
618 if (!listener) {
619 return;
620 }
621
622 aws_event_stream_rpc_server_listener_release(listener);
623 }
624
625 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnection_acquire(JNIEnv * env,jclass jni_class,jlong jni_server_connection)626 void JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnection_acquire(
627 JNIEnv *env,
628 jclass jni_class,
629 jlong jni_server_connection) {
630 (void)env;
631 (void)jni_class;
632 aws_cache_jni_ids(env);
633
634 struct aws_event_stream_rpc_server_connection *connection =
635 (struct aws_event_stream_rpc_server_connection *)jni_server_connection;
636 if (connection == NULL) {
637 return;
638 }
639
640 aws_event_stream_rpc_server_connection_acquire(connection);
641 }
642
643 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnection_release(JNIEnv * env,jclass jni_class,jlong jni_server_connection)644 void JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnection_release(
645 JNIEnv *env,
646 jclass jni_class,
647 jlong jni_server_connection) {
648 (void)env;
649 (void)jni_class;
650 aws_cache_jni_ids(env);
651
652 struct aws_event_stream_rpc_server_connection *connection =
653 (struct aws_event_stream_rpc_server_connection *)jni_server_connection;
654 if (connection == NULL) {
655 return;
656 }
657
658 aws_event_stream_rpc_server_connection_release(connection);
659 }
660
661 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnection_closeConnection(JNIEnv * env,jclass jni_class,jlong jni_server_connection,jint error_code)662 void JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnection_closeConnection(
663 JNIEnv *env,
664 jclass jni_class,
665 jlong jni_server_connection,
666 jint error_code) {
667 (void)env;
668 (void)jni_class;
669 aws_cache_jni_ids(env);
670
671 struct aws_event_stream_rpc_server_connection *connection =
672 (struct aws_event_stream_rpc_server_connection *)jni_server_connection;
673 if (connection == NULL) {
674 return;
675 }
676
677 aws_event_stream_rpc_server_connection_close(connection, error_code);
678 }
679
680 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnection_isOpen(JNIEnv * env,jclass jni_class,jlong jni_server_connection)681 jboolean JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnection_isOpen(
682 JNIEnv *env,
683 jclass jni_class,
684 jlong jni_server_connection) {
685 (void)env;
686 (void)jni_class;
687 aws_cache_jni_ids(env);
688
689 struct aws_event_stream_rpc_server_connection *connection =
690 (struct aws_event_stream_rpc_server_connection *)jni_server_connection;
691
692 if (connection == NULL) {
693 return false;
694 }
695
696 return aws_event_stream_rpc_server_connection_is_open(connection);
697 }
698
699 struct message_flush_callback_args {
700 JavaVM *jvm;
701 jobject callback;
702 };
703
s_destroy_message_flush_callback_args(JNIEnv * env,struct message_flush_callback_args * callback_args)704 static void s_destroy_message_flush_callback_args(JNIEnv *env, struct message_flush_callback_args *callback_args) {
705 if (callback_args == NULL) {
706 return;
707 }
708
709 if (callback_args->callback != NULL) {
710 (*env)->DeleteGlobalRef(env, callback_args->callback);
711 }
712
713 aws_mem_release(aws_jni_get_allocator(), callback_args);
714 }
715
s_message_flush_fn(int error_code,void * user_data)716 static void s_message_flush_fn(int error_code, void *user_data) {
717 struct message_flush_callback_args *callback_data = user_data;
718
719 /********** JNI ENV ACQUIRE **********/
720 JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
721 if (env == NULL) {
722 /* If we can't get an environment, then the JVM is probably shutting down. Don't crash. */
723 return;
724 }
725
726 (*env)->CallVoidMethod(
727 env, callback_data->callback, event_stream_server_message_flush_properties.callback, error_code);
728 aws_jni_check_and_clear_exception(env);
729
730 JavaVM *jvm = callback_data->jvm;
731 s_destroy_message_flush_callback_args(env, callback_data);
732 aws_jni_release_thread_env(jvm, env);
733 /********** JNI ENV RELEASE **********/
734 }
735
736 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnection_sendProtocolMessage(JNIEnv * env,jclass jni_class,jlong jni_server_connection,jbyteArray headers,jbyteArray payload,jint message_type,jint message_flags,jobject callback)737 jint JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnection_sendProtocolMessage(
738 JNIEnv *env,
739 jclass jni_class,
740 jlong jni_server_connection,
741 jbyteArray headers,
742 jbyteArray payload,
743 jint message_type,
744 jint message_flags,
745 jobject callback) {
746 (void)jni_class;
747 aws_cache_jni_ids(env);
748
749 struct aws_event_stream_rpc_server_connection *connection =
750 (struct aws_event_stream_rpc_server_connection *)jni_server_connection;
751
752 int ret_val = AWS_OP_ERR;
753 struct message_flush_callback_args *callback_data = NULL;
754
755 struct aws_event_stream_rpc_marshalled_message marshalled_message;
756 if (aws_event_stream_rpc_marshall_message_args_init(
757 &marshalled_message, aws_jni_get_allocator(), env, headers, payload, NULL, message_flags, message_type)) {
758 goto clean_up;
759 }
760
761 if (connection == NULL) {
762 aws_jni_throw_runtime_exception(env, "ServerConnection.sendProtocolMessage: native connection is NULL.");
763 goto clean_up;
764 }
765
766 callback_data = aws_mem_calloc(aws_jni_get_allocator(), 1, sizeof(struct message_flush_callback_args));
767
768 if (!callback_data) {
769 aws_jni_throw_runtime_exception(env, "ServerConnection.sendProtocolMessage: allocation failed.");
770 goto clean_up;
771 }
772
773 jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
774 if (jvmresult != 0) {
775 aws_jni_throw_runtime_exception(env, "ServerConnection.sendProtocolMessage: Unable to get JVM");
776 goto clean_up;
777 }
778
779 callback_data->callback = (*env)->NewGlobalRef(env, callback);
780 if (callback_data->callback == NULL) {
781 aws_jni_throw_runtime_exception(
782 env, "ServerConnection.sendProtocolMessage: Unable to create global ref to callback");
783 goto clean_up;
784 }
785
786 if (aws_event_stream_rpc_server_connection_send_protocol_message(
787 connection, &marshalled_message.message_args, s_message_flush_fn, callback_data)) {
788 aws_jni_throw_runtime_exception(env, "ServerConnection.sendProtocolMessage: send message failed");
789 goto clean_up;
790 }
791
792 ret_val = AWS_OP_SUCCESS;
793
794 clean_up:
795
796 aws_event_stream_rpc_marshall_message_args_clean_up(&marshalled_message);
797 if (ret_val != AWS_OP_SUCCESS) {
798 s_destroy_message_flush_callback_args(env, callback_data);
799 }
800
801 return ret_val;
802 }
803
804 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_acquire(JNIEnv * env,jclass jni_class,jlong jni_server_continuation)805 void JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_acquire(
806 JNIEnv *env,
807 jclass jni_class,
808 jlong jni_server_continuation) {
809 (void)env;
810 (void)jni_class;
811 aws_cache_jni_ids(env);
812
813 struct aws_event_stream_rpc_server_continuation_token *continuation =
814 (struct aws_event_stream_rpc_server_continuation_token *)jni_server_continuation;
815 aws_event_stream_rpc_server_continuation_acquire(continuation);
816 }
817
818 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_release(JNIEnv * env,jclass jni_class,jlong jni_server_continuation)819 void JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_release(
820 JNIEnv *env,
821 jclass jni_class,
822 jlong jni_server_continuation) {
823 (void)env;
824 (void)jni_class;
825 aws_cache_jni_ids(env);
826
827 struct aws_event_stream_rpc_server_continuation_token *continuation =
828 (struct aws_event_stream_rpc_server_continuation_token *)jni_server_continuation;
829 aws_event_stream_rpc_server_continuation_release(continuation);
830 }
831
832 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_isClosed(JNIEnv * env,jclass jni_class,jlong jni_server_continuation)833 jboolean JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_isClosed(
834 JNIEnv *env,
835 jclass jni_class,
836 jlong jni_server_continuation) {
837 (void)env;
838 (void)jni_class;
839 aws_cache_jni_ids(env);
840
841 struct aws_event_stream_rpc_server_continuation_token *continuation =
842 (struct aws_event_stream_rpc_server_continuation_token *)jni_server_continuation;
843
844 if (continuation == NULL) {
845 return true;
846 }
847
848 return aws_event_stream_rpc_server_continuation_is_closed(continuation);
849 }
850
851 JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_sendContinuationMessage(JNIEnv * env,jclass jni_class,jlong jni_server_continuation,jbyteArray headers,jbyteArray payload,jint message_type,jint message_flags,jobject callback)852 jint JNICALL Java_software_amazon_awssdk_crt_eventstream_ServerConnectionContinuation_sendContinuationMessage(
853 JNIEnv *env,
854 jclass jni_class,
855 jlong jni_server_continuation,
856 jbyteArray headers,
857 jbyteArray payload,
858 jint message_type,
859 jint message_flags,
860 jobject callback) {
861 (void)jni_class;
862 aws_cache_jni_ids(env);
863
864 struct aws_event_stream_rpc_server_continuation_token *continuation =
865 (struct aws_event_stream_rpc_server_continuation_token *)jni_server_continuation;
866
867 struct message_flush_callback_args *callback_data = NULL;
868
869 int ret_val = AWS_OP_ERR;
870
871 struct aws_event_stream_rpc_marshalled_message marshalled_message;
872 if (aws_event_stream_rpc_marshall_message_args_init(
873 &marshalled_message, aws_jni_get_allocator(), env, headers, payload, NULL, message_flags, message_type)) {
874 goto clean_up;
875 }
876
877 if (continuation == NULL) {
878 aws_jni_throw_runtime_exception(env, "ServerConnection.sendContinuationMessage: native continuation is NULL.");
879 goto clean_up;
880 }
881
882 callback_data = aws_mem_calloc(aws_jni_get_allocator(), 1, sizeof(struct message_flush_callback_args));
883 if (!callback_data) {
884 aws_jni_throw_runtime_exception(
885 env, "ServerConnectionContinuation.sendContinuationMessage: allocation failed.");
886 goto clean_up;
887 }
888
889 jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
890 if (jvmresult != 0) {
891 aws_jni_throw_runtime_exception(env, "ServerConnectionContinuation.sendContinuationMessage: Unable to get JVM");
892 goto clean_up;
893 }
894
895 callback_data->callback = (*env)->NewGlobalRef(env, callback);
896 if (callback_data->callback == NULL) {
897 aws_jni_throw_runtime_exception(
898 env, "ServerConnection.sendContinuationMessage: Unable to create global ref to callback");
899 goto clean_up;
900 }
901
902 if (aws_event_stream_rpc_server_continuation_send_message(
903 continuation, &marshalled_message.message_args, s_message_flush_fn, callback_data)) {
904 aws_jni_throw_runtime_exception(
905 env, "ServerConnectionContinuation.sendContinuationMessage: send message failed");
906 goto clean_up;
907 }
908
909 ret_val = AWS_OP_SUCCESS;
910
911 clean_up:
912 aws_event_stream_rpc_marshall_message_args_clean_up(&marshalled_message);
913 if (ret_val != AWS_OP_SUCCESS) {
914 s_destroy_message_flush_callback_args(env, callback_data);
915 }
916
917 return ret_val;
918 }
919
920 #if UINTPTR_MAX == 0xffffffff
921 # if defined(_MSC_VER)
922 # pragma warning(pop)
923 # else
924 # pragma GCC diagnostic pop
925 # endif
926 #endif
927