xref: /aosp_15_r20/external/aws-crt-java/src/native/event_stream_message.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 <jni.h>
7*3c7ae9deSAndroid Build Coastguard Worker 
8*3c7ae9deSAndroid Build Coastguard Worker #include <aws/event-stream/event_stream.h>
9*3c7ae9deSAndroid Build Coastguard Worker 
10*3c7ae9deSAndroid Build Coastguard Worker #include "crt.h"
11*3c7ae9deSAndroid Build Coastguard Worker #include "event_stream_message.h"
12*3c7ae9deSAndroid Build Coastguard Worker #include "java_class_ids.h"
13*3c7ae9deSAndroid Build Coastguard Worker 
14*3c7ae9deSAndroid Build Coastguard Worker /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
15*3c7ae9deSAndroid Build Coastguard Worker #if UINTPTR_MAX == 0xffffffff
16*3c7ae9deSAndroid Build Coastguard Worker #    if defined(_MSC_VER)
17*3c7ae9deSAndroid Build Coastguard Worker #        pragma warning(push)
18*3c7ae9deSAndroid Build Coastguard Worker #        pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
19*3c7ae9deSAndroid Build Coastguard Worker #    else
20*3c7ae9deSAndroid Build Coastguard Worker #        pragma GCC diagnostic push
21*3c7ae9deSAndroid Build Coastguard Worker #        pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
22*3c7ae9deSAndroid Build Coastguard Worker #        pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
23*3c7ae9deSAndroid Build Coastguard Worker #    endif
24*3c7ae9deSAndroid Build Coastguard Worker #endif
25*3c7ae9deSAndroid Build Coastguard Worker 
26*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_Message_messageNew(JNIEnv * env,jclass jni_class,jbyteArray headers,jbyteArray payload)27*3c7ae9deSAndroid Build Coastguard Worker jlong JNICALL Java_software_amazon_awssdk_crt_eventstream_Message_messageNew(
28*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
29*3c7ae9deSAndroid Build Coastguard Worker     jclass jni_class,
30*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray headers,
31*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray payload) {
32*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_class;
33*3c7ae9deSAndroid Build Coastguard Worker     aws_cache_jni_ids(env);
34*3c7ae9deSAndroid Build Coastguard Worker 
35*3c7ae9deSAndroid Build Coastguard Worker     struct aws_event_stream_message *message =
36*3c7ae9deSAndroid Build Coastguard Worker         aws_mem_calloc(aws_jni_get_allocator(), 1, sizeof(struct aws_event_stream_message));
37*3c7ae9deSAndroid Build Coastguard Worker 
38*3c7ae9deSAndroid Build Coastguard Worker     if (!message) {
39*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_throw_runtime_exception(env, "Message.MessageNew: Allocation failed!");
40*3c7ae9deSAndroid Build Coastguard Worker         return (jlong)NULL;
41*3c7ae9deSAndroid Build Coastguard Worker     }
42*3c7ae9deSAndroid Build Coastguard Worker 
43*3c7ae9deSAndroid Build Coastguard Worker     struct aws_event_stream_message *return_message = NULL;
44*3c7ae9deSAndroid Build Coastguard Worker 
45*3c7ae9deSAndroid Build Coastguard Worker     struct aws_event_stream_rpc_marshalled_message marshalled_message;
46*3c7ae9deSAndroid Build Coastguard Worker     if (aws_event_stream_rpc_marshall_message_args_init(
47*3c7ae9deSAndroid Build Coastguard Worker             &marshalled_message, aws_jni_get_allocator(), env, headers, payload, NULL, 0, 0)) {
48*3c7ae9deSAndroid Build Coastguard Worker         goto clean_up;
49*3c7ae9deSAndroid Build Coastguard Worker     }
50*3c7ae9deSAndroid Build Coastguard Worker 
51*3c7ae9deSAndroid Build Coastguard Worker     if (aws_event_stream_message_init(
52*3c7ae9deSAndroid Build Coastguard Worker             message, aws_jni_get_allocator(), &marshalled_message.headers_list, &marshalled_message.payload_buf)) {
53*3c7ae9deSAndroid Build Coastguard Worker         goto clean_up;
54*3c7ae9deSAndroid Build Coastguard Worker     }
55*3c7ae9deSAndroid Build Coastguard Worker 
56*3c7ae9deSAndroid Build Coastguard Worker     return_message = message;
57*3c7ae9deSAndroid Build Coastguard Worker 
58*3c7ae9deSAndroid Build Coastguard Worker clean_up:
59*3c7ae9deSAndroid Build Coastguard Worker     aws_event_stream_rpc_marshall_message_args_clean_up(&marshalled_message);
60*3c7ae9deSAndroid Build Coastguard Worker 
61*3c7ae9deSAndroid Build Coastguard Worker     if (!return_message) {
62*3c7ae9deSAndroid Build Coastguard Worker         aws_mem_release(aws_jni_get_allocator(), message);
63*3c7ae9deSAndroid Build Coastguard Worker     }
64*3c7ae9deSAndroid Build Coastguard Worker 
65*3c7ae9deSAndroid Build Coastguard Worker     return (jlong)return_message;
66*3c7ae9deSAndroid Build Coastguard Worker }
67*3c7ae9deSAndroid Build Coastguard Worker 
68*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_Message_messageDelete(JNIEnv * env,jclass jni_class,jlong message_ptr)69*3c7ae9deSAndroid Build Coastguard Worker void JNICALL Java_software_amazon_awssdk_crt_eventstream_Message_messageDelete(
70*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
71*3c7ae9deSAndroid Build Coastguard Worker     jclass jni_class,
72*3c7ae9deSAndroid Build Coastguard Worker     jlong message_ptr) {
73*3c7ae9deSAndroid Build Coastguard Worker     (void)env;
74*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_class;
75*3c7ae9deSAndroid Build Coastguard Worker     aws_cache_jni_ids(env);
76*3c7ae9deSAndroid Build Coastguard Worker 
77*3c7ae9deSAndroid Build Coastguard Worker     struct aws_event_stream_message *message = (struct aws_event_stream_message *)message_ptr;
78*3c7ae9deSAndroid Build Coastguard Worker     aws_event_stream_message_clean_up(message);
79*3c7ae9deSAndroid Build Coastguard Worker     aws_mem_release(aws_jni_get_allocator(), message);
80*3c7ae9deSAndroid Build Coastguard Worker }
81*3c7ae9deSAndroid Build Coastguard Worker 
82*3c7ae9deSAndroid Build Coastguard Worker JNIEXPORT
Java_software_amazon_awssdk_crt_eventstream_Message_messageBuffer(JNIEnv * env,jclass jni_class,jlong message_ptr)83*3c7ae9deSAndroid Build Coastguard Worker jobject JNICALL Java_software_amazon_awssdk_crt_eventstream_Message_messageBuffer(
84*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
85*3c7ae9deSAndroid Build Coastguard Worker     jclass jni_class,
86*3c7ae9deSAndroid Build Coastguard Worker     jlong message_ptr) {
87*3c7ae9deSAndroid Build Coastguard Worker     (void)jni_class;
88*3c7ae9deSAndroid Build Coastguard Worker     aws_cache_jni_ids(env);
89*3c7ae9deSAndroid Build Coastguard Worker 
90*3c7ae9deSAndroid Build Coastguard Worker     struct aws_event_stream_message *message = (struct aws_event_stream_message *)message_ptr;
91*3c7ae9deSAndroid Build Coastguard Worker     const uint8_t *buffer = aws_event_stream_message_buffer(message);
92*3c7ae9deSAndroid Build Coastguard Worker     size_t buffer_len = aws_event_stream_message_total_length(message);
93*3c7ae9deSAndroid Build Coastguard Worker 
94*3c7ae9deSAndroid Build Coastguard Worker     return aws_jni_direct_byte_buffer_from_raw_ptr(env, buffer, (jlong)buffer_len);
95*3c7ae9deSAndroid Build Coastguard Worker }
96*3c7ae9deSAndroid Build Coastguard Worker 
aws_event_stream_rpc_marshall_message_args_init(struct aws_event_stream_rpc_marshalled_message * message_args,struct aws_allocator * allocator,JNIEnv * env,jbyteArray headers,jbyteArray payload,jbyteArray operation_name,jint message_flags,jint message_type)97*3c7ae9deSAndroid Build Coastguard Worker int aws_event_stream_rpc_marshall_message_args_init(
98*3c7ae9deSAndroid Build Coastguard Worker     struct aws_event_stream_rpc_marshalled_message *message_args,
99*3c7ae9deSAndroid Build Coastguard Worker     struct aws_allocator *allocator,
100*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
101*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray headers,
102*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray payload,
103*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray operation_name,
104*3c7ae9deSAndroid Build Coastguard Worker     jint message_flags,
105*3c7ae9deSAndroid Build Coastguard Worker     jint message_type) {
106*3c7ae9deSAndroid Build Coastguard Worker     AWS_ZERO_STRUCT(*message_args);
107*3c7ae9deSAndroid Build Coastguard Worker     message_args->allocator = allocator;
108*3c7ae9deSAndroid Build Coastguard Worker 
109*3c7ae9deSAndroid Build Coastguard Worker     if (headers) {
110*3c7ae9deSAndroid Build Coastguard Worker         if (aws_event_stream_headers_list_init(&message_args->headers_list, allocator)) {
111*3c7ae9deSAndroid Build Coastguard Worker             aws_jni_throw_runtime_exception(env, "EventStreamRPCMessage: headers allocation failed.");
112*3c7ae9deSAndroid Build Coastguard Worker             return AWS_OP_ERR;
113*3c7ae9deSAndroid Build Coastguard Worker         }
114*3c7ae9deSAndroid Build Coastguard Worker 
115*3c7ae9deSAndroid Build Coastguard Worker         message_args->headers_init = true;
116*3c7ae9deSAndroid Build Coastguard Worker 
117*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor headers_cur = aws_jni_byte_cursor_from_jbyteArray_acquire(env, headers);
118*3c7ae9deSAndroid Build Coastguard Worker         /* copy because JNI is stupid and the buffer that the headers parser runs from needs the memory to stick around
119*3c7ae9deSAndroid Build Coastguard Worker          * until the final message creation happens. */
120*3c7ae9deSAndroid Build Coastguard Worker         aws_byte_buf_init_copy_from_cursor(&message_args->headers_buf, allocator, headers_cur);
121*3c7ae9deSAndroid Build Coastguard Worker         int headers_parse_error = aws_event_stream_read_headers_from_buffer(
122*3c7ae9deSAndroid Build Coastguard Worker             &message_args->headers_list, message_args->headers_buf.buffer, message_args->headers_buf.len);
123*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_byte_cursor_from_jbyteArray_release(env, headers, headers_cur);
124*3c7ae9deSAndroid Build Coastguard Worker 
125*3c7ae9deSAndroid Build Coastguard Worker         if (headers_parse_error) {
126*3c7ae9deSAndroid Build Coastguard Worker             aws_jni_throw_runtime_exception(env, "EventStreamRPCMessage: headers allocation failed.");
127*3c7ae9deSAndroid Build Coastguard Worker             goto clean_up;
128*3c7ae9deSAndroid Build Coastguard Worker         }
129*3c7ae9deSAndroid Build Coastguard Worker     }
130*3c7ae9deSAndroid Build Coastguard Worker 
131*3c7ae9deSAndroid Build Coastguard Worker     if (payload) {
132*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor payload_cur = aws_jni_byte_cursor_from_jbyteArray_acquire(env, payload);
133*3c7ae9deSAndroid Build Coastguard Worker         aws_byte_buf_init_copy_from_cursor(&message_args->payload_buf, allocator, payload_cur);
134*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_byte_cursor_from_jbyteArray_release(env, payload, payload_cur);
135*3c7ae9deSAndroid Build Coastguard Worker 
136*3c7ae9deSAndroid Build Coastguard Worker         if (!message_args->payload_buf.buffer) {
137*3c7ae9deSAndroid Build Coastguard Worker             aws_jni_throw_runtime_exception(env, "EventStreamRPCMessage: allocation failed.");
138*3c7ae9deSAndroid Build Coastguard Worker             goto clean_up;
139*3c7ae9deSAndroid Build Coastguard Worker         }
140*3c7ae9deSAndroid Build Coastguard Worker     }
141*3c7ae9deSAndroid Build Coastguard Worker 
142*3c7ae9deSAndroid Build Coastguard Worker     message_args->message_args.message_type = message_type;
143*3c7ae9deSAndroid Build Coastguard Worker     message_args->message_args.message_flags = message_flags;
144*3c7ae9deSAndroid Build Coastguard Worker     message_args->message_args.headers = message_args->headers_list.data;
145*3c7ae9deSAndroid Build Coastguard Worker     message_args->message_args.headers_count = message_args->headers_list.length;
146*3c7ae9deSAndroid Build Coastguard Worker     message_args->message_args.payload = &message_args->payload_buf;
147*3c7ae9deSAndroid Build Coastguard Worker 
148*3c7ae9deSAndroid Build Coastguard Worker     if (operation_name) {
149*3c7ae9deSAndroid Build Coastguard Worker         struct aws_byte_cursor operation_cur = aws_jni_byte_cursor_from_jbyteArray_acquire(env, operation_name);
150*3c7ae9deSAndroid Build Coastguard Worker         aws_byte_buf_init_copy_from_cursor(&message_args->operation_buf, allocator, operation_cur);
151*3c7ae9deSAndroid Build Coastguard Worker         aws_jni_byte_cursor_from_jbyteArray_release(env, operation_name, operation_cur);
152*3c7ae9deSAndroid Build Coastguard Worker 
153*3c7ae9deSAndroid Build Coastguard Worker         if (!message_args->operation_buf.buffer) {
154*3c7ae9deSAndroid Build Coastguard Worker             aws_jni_throw_runtime_exception(env, "CEventStreamRPCMessage: allocation failed.");
155*3c7ae9deSAndroid Build Coastguard Worker             goto clean_up;
156*3c7ae9deSAndroid Build Coastguard Worker         }
157*3c7ae9deSAndroid Build Coastguard Worker     }
158*3c7ae9deSAndroid Build Coastguard Worker 
159*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_SUCCESS;
160*3c7ae9deSAndroid Build Coastguard Worker 
161*3c7ae9deSAndroid Build Coastguard Worker clean_up:
162*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&message_args->headers_buf);
163*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&message_args->payload_buf);
164*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&message_args->operation_buf);
165*3c7ae9deSAndroid Build Coastguard Worker 
166*3c7ae9deSAndroid Build Coastguard Worker     if (message_args->headers_init) {
167*3c7ae9deSAndroid Build Coastguard Worker         aws_event_stream_headers_list_cleanup(&message_args->headers_list);
168*3c7ae9deSAndroid Build Coastguard Worker     }
169*3c7ae9deSAndroid Build Coastguard Worker 
170*3c7ae9deSAndroid Build Coastguard Worker     return AWS_OP_ERR;
171*3c7ae9deSAndroid Build Coastguard Worker }
172*3c7ae9deSAndroid Build Coastguard Worker 
aws_event_stream_rpc_marshall_message_args_clean_up(struct aws_event_stream_rpc_marshalled_message * message_args)173*3c7ae9deSAndroid Build Coastguard Worker void aws_event_stream_rpc_marshall_message_args_clean_up(struct aws_event_stream_rpc_marshalled_message *message_args) {
174*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&message_args->headers_buf);
175*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&message_args->payload_buf);
176*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&message_args->operation_buf);
177*3c7ae9deSAndroid Build Coastguard Worker 
178*3c7ae9deSAndroid Build Coastguard Worker     if (message_args->headers_init) {
179*3c7ae9deSAndroid Build Coastguard Worker         aws_event_stream_headers_list_cleanup(&message_args->headers_list);
180*3c7ae9deSAndroid Build Coastguard Worker         message_args->headers_init = false;
181*3c7ae9deSAndroid Build Coastguard Worker     }
182*3c7ae9deSAndroid Build Coastguard Worker }
183*3c7ae9deSAndroid Build Coastguard Worker 
aws_event_stream_rpc_marshall_headers_to_byteArray(struct aws_allocator * allocator,JNIEnv * env,struct aws_event_stream_header_value_pair * headers_array,size_t length)184*3c7ae9deSAndroid Build Coastguard Worker jbyteArray aws_event_stream_rpc_marshall_headers_to_byteArray(
185*3c7ae9deSAndroid Build Coastguard Worker     struct aws_allocator *allocator,
186*3c7ae9deSAndroid Build Coastguard Worker     JNIEnv *env,
187*3c7ae9deSAndroid Build Coastguard Worker     struct aws_event_stream_header_value_pair *headers_array,
188*3c7ae9deSAndroid Build Coastguard Worker     size_t length) {
189*3c7ae9deSAndroid Build Coastguard Worker     /* this is not how we recommend you use the array_list api, but it is correct, and it prevents the need for extra
190*3c7ae9deSAndroid Build Coastguard Worker      * allocations and copies. */
191*3c7ae9deSAndroid Build Coastguard Worker     struct aws_array_list headers_list;
192*3c7ae9deSAndroid Build Coastguard Worker     aws_array_list_init_static(&headers_list, headers_array, length, sizeof(struct aws_event_stream_header_value_pair));
193*3c7ae9deSAndroid Build Coastguard Worker     headers_list.length = length;
194*3c7ae9deSAndroid Build Coastguard Worker 
195*3c7ae9deSAndroid Build Coastguard Worker     uint32_t headers_buf_len = aws_event_stream_compute_headers_required_buffer_len(&headers_list);
196*3c7ae9deSAndroid Build Coastguard Worker 
197*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_buf headers_buf;
198*3c7ae9deSAndroid Build Coastguard Worker     if (aws_byte_buf_init(&headers_buf, allocator, headers_buf_len)) {
199*3c7ae9deSAndroid Build Coastguard Worker         return NULL;
200*3c7ae9deSAndroid Build Coastguard Worker     }
201*3c7ae9deSAndroid Build Coastguard Worker 
202*3c7ae9deSAndroid Build Coastguard Worker     jbyteArray headers_byte_array = NULL;
203*3c7ae9deSAndroid Build Coastguard Worker     if (aws_event_stream_write_headers_to_buffer_safe(&headers_list, &headers_buf)) {
204*3c7ae9deSAndroid Build Coastguard Worker         goto done;
205*3c7ae9deSAndroid Build Coastguard Worker     }
206*3c7ae9deSAndroid Build Coastguard Worker 
207*3c7ae9deSAndroid Build Coastguard Worker     struct aws_byte_cursor headers_cur = aws_byte_cursor_from_buf(&headers_buf);
208*3c7ae9deSAndroid Build Coastguard Worker     headers_byte_array = aws_jni_byte_array_from_cursor(env, &headers_cur);
209*3c7ae9deSAndroid Build Coastguard Worker 
210*3c7ae9deSAndroid Build Coastguard Worker done:
211*3c7ae9deSAndroid Build Coastguard Worker 
212*3c7ae9deSAndroid Build Coastguard Worker     aws_byte_buf_clean_up(&headers_buf);
213*3c7ae9deSAndroid Build Coastguard Worker     aws_array_list_clean_up(&headers_list);
214*3c7ae9deSAndroid Build Coastguard Worker 
215*3c7ae9deSAndroid Build Coastguard Worker     return headers_byte_array;
216*3c7ae9deSAndroid Build Coastguard Worker }
217