xref: /aosp_15_r20/external/aws-crt-java/src/native/mqtt5_packets.c (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 #include <jni.h>
6 
7 #include <mqtt5_packets.h>
8 
9 #include <aws/mqtt/v5/mqtt5_client.h>
10 #include <crt.h>
11 
12 #include <java_class_ids.h>
13 
14 /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
15 #if UINTPTR_MAX == 0xffffffff
16 #    if defined(_MSC_VER)
17 #        pragma warning(push)
18 #        pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
19 #    else
20 #        pragma GCC diagnostic push
21 #        pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
22 #        pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
23 #    endif
24 #endif
25 
26 /*******************************************************************************
27  * STRUCT DEFINITIONS
28  ******************************************************************************/
29 
30 struct aws_mqtt5_packet_connect_view_java_jni {
31     struct aws_mqtt5_packet_connect_view packet;
32 
33     struct aws_byte_buf client_id_buf;
34     struct aws_byte_cursor client_id_cursor;
35     struct aws_byte_buf username_buf;
36     struct aws_byte_cursor username_cursor;
37     struct aws_byte_buf password_buf;
38     struct aws_byte_cursor password_cursor;
39     uint32_t session_expiry_interval_seconds;
40     uint8_t request_response_information;
41     uint8_t request_problem_information;
42     uint16_t receive_maximum;
43     uint16_t topic_alias_maximum;
44     uint32_t maximum_packet_size_bytes;
45     uint32_t will_delay_interval_seconds;
46     uint16_t keep_alive_interval_seconds;
47     /* Contains buffer_and_cursor_array_holder_struct pointers */
48     struct aws_array_list jni_user_properties_holder;
49     /* Contains aws_mqtt5_user_property pointers */
50     struct aws_array_list jni_user_properties_struct_holder;
51     struct aws_mqtt5_packet_publish_view_java_jni *will_publish_packet;
52 };
53 
54 struct aws_mqtt5_packet_disconnect_view_java_jni {
55     struct aws_mqtt5_packet_disconnect_view packet;
56 
57     struct aws_byte_buf reason_string_buf;
58     struct aws_byte_cursor reason_string_cursor;
59     struct aws_byte_buf server_reference_buf;
60     struct aws_byte_cursor server_reference_cursor;
61     uint32_t session_expiry_interval_seconds;
62     /* Contains buffer_and_cursor_array_holder_struct pointers */
63     struct aws_array_list jni_user_properties_holder;
64     /* Contains aws_mqtt5_user_property pointers */
65     struct aws_array_list jni_user_properties_struct_holder;
66 };
67 
68 struct aws_mqtt5_packet_publish_view_java_jni {
69     struct aws_mqtt5_packet_publish_view packet;
70 
71     struct aws_byte_buf payload_buf;
72     struct aws_byte_cursor payload_cursor;
73     struct aws_byte_buf topic_buf;
74     struct aws_byte_cursor topic_cursor;
75     enum aws_mqtt5_payload_format_indicator payload_format;
76     uint32_t message_expiry_interval_seconds;
77     uint16_t topic_alias;
78     struct aws_byte_buf response_topic_buf;
79     struct aws_byte_cursor response_topic_cursor;
80     struct aws_byte_buf correlation_data_buf;
81     struct aws_byte_cursor correlation_data_cursor;
82     struct aws_byte_buf content_type_buf;
83     struct aws_byte_cursor content_type_cursor;
84     /* Contains buffer_and_cursor_array_holder_struct pointers */
85     struct aws_array_list jni_user_properties_holder;
86     /* Contains aws_mqtt5_user_property pointers */
87     struct aws_array_list jni_user_properties_struct_holder;
88 };
89 
90 struct aws_mqtt5_packet_subscribe_view_java_jni {
91     struct aws_mqtt5_packet_subscribe_view packet;
92 
93     /* Contains aws_mqtt5_subscription_view pointers */
94     struct aws_array_list topic_filters;
95     /* Contains buffer_and_cursor_array_holder_struct pointers */
96     struct aws_array_list jni_subscription_topic_filters;
97     uint32_t subscription_identifier;
98     /* Contains buffer_and_cursor_array_holder_struct pointers */
99     struct aws_array_list jni_user_properties_holder;
100     /* Contains aws_mqtt5_user_property pointers */
101     struct aws_array_list jni_user_properties_struct_holder;
102 };
103 
104 struct aws_mqtt5_packet_unsubscribe_view_java_jni {
105     struct aws_mqtt5_packet_unsubscribe_view packet;
106 
107     /* Contains aws_byte_cursor pointers */
108     struct aws_array_list topic_filters;
109     /* Contains buffer_and_cursor_array_holder_struct pointers */
110     struct aws_array_list jni_topic_filters;
111     /* Contains buffer_and_cursor_array_holder_struct pointers */
112     struct aws_array_list jni_user_properties_holder;
113     /* Contains aws_mqtt5_user_property pointers */
114     struct aws_array_list jni_user_properties_struct_holder;
115 };
116 
117 struct buffer_and_cursor_array_holder_struct {
118     struct aws_byte_cursor cursor;
119     struct aws_byte_buf buffer;
120 };
121 
122 /*******************************************************************************
123  * HELPER FUNCTIONS
124  ******************************************************************************/
125 
s_populate_user_properties(JNIEnv * env,jobject jni_user_properties_list,size_t java_packet_native_user_property_count,const struct aws_mqtt5_user_property ** java_packet_native_user_properties,struct aws_array_list * java_packet_user_properties_holder,struct aws_array_list * java_packet_user_properties_struct_holder)126 static int s_populate_user_properties(
127     JNIEnv *env,
128     jobject jni_user_properties_list,
129     size_t java_packet_native_user_property_count,
130     const struct aws_mqtt5_user_property **java_packet_native_user_properties,
131     /* Contains buffer_and_cursor_array_holder_struct pointers */
132     struct aws_array_list *java_packet_user_properties_holder,
133     /* Contains aws_mqtt5_user_property pointers */
134     struct aws_array_list *java_packet_user_properties_struct_holder) {
135 
136     if (jni_user_properties_list) {
137         for (size_t i = 0; i < java_packet_native_user_property_count; i++) {
138             jobject jni_property =
139                 (*env)->CallObjectMethod(env, jni_user_properties_list, boxed_list_properties.list_get_id, (jint)i);
140             if (!jni_property || aws_jni_check_and_clear_exception(env)) {
141                 AWS_LOGF_ERROR(
142                     AWS_LS_MQTT5_CLIENT,
143                     "Could not populate user properties due to being unable to get property in list from Java");
144                 return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
145             }
146 
147             jstring jni_property_key =
148                 (jstring)(*env)->GetObjectField(env, jni_property, mqtt5_user_property_properties.property_key_id);
149             if (aws_jni_check_and_clear_exception(env) || !jni_property_key) {
150                 AWS_LOGF_ERROR(
151                     AWS_LS_MQTT5_CLIENT,
152                     "Could not populate user properties due to exception when getting property key");
153                 return aws_raise_error(AWS_ERROR_INVALID_STATE);
154             }
155             jstring jni_property_value =
156                 (jstring)(*env)->GetObjectField(env, jni_property, mqtt5_user_property_properties.property_value_id);
157             if (aws_jni_check_and_clear_exception(env) || !jni_property_value) {
158                 AWS_LOGF_ERROR(
159                     AWS_LS_MQTT5_CLIENT,
160                     "Could not populate user properties due to exception when getting property value");
161                 return aws_raise_error(AWS_ERROR_INVALID_STATE);
162             }
163 
164             if (!jni_property_key) {
165                 AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error reading a user property: Key in user property was NULL!");
166                 return aws_raise_error(AWS_ERROR_INVALID_STATE);
167             }
168             if (!jni_property_value) {
169                 AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error reading a user property: Key in user property was NULL!");
170                 return aws_raise_error(AWS_ERROR_INVALID_STATE);
171             }
172 
173             // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy.
174             // This gets around JNI stuff going out of scope.
175             struct buffer_and_cursor_array_holder_struct holder_property_key;
176             struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_property_key);
177             aws_byte_buf_init_copy_from_cursor(&holder_property_key.buffer, aws_jni_get_allocator(), tmp_cursor);
178             holder_property_key.cursor = aws_byte_cursor_from_buf(&holder_property_key.buffer);
179             aws_jni_byte_cursor_from_jstring_release(env, jni_property_key, tmp_cursor);
180             jni_property_key = NULL;
181 
182             // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy.
183             // This gets around JNI stuff going out of scope.
184             struct buffer_and_cursor_array_holder_struct holder_property_value;
185             tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_property_value);
186             aws_byte_buf_init_copy_from_cursor(&holder_property_value.buffer, aws_jni_get_allocator(), tmp_cursor);
187             holder_property_value.cursor = aws_byte_cursor_from_buf(&holder_property_value.buffer);
188             aws_jni_byte_cursor_from_jstring_release(env, jni_property_value, tmp_cursor);
189             jni_property_value = NULL;
190 
191             aws_array_list_push_back(java_packet_user_properties_holder, (void *)&holder_property_key);
192             aws_array_list_push_back(java_packet_user_properties_holder, (void *)&holder_property_value);
193 
194             struct aws_mqtt5_user_property jni_property_struct = {
195                 .name = holder_property_key.cursor,
196                 .value = holder_property_value.cursor,
197             };
198             aws_array_list_push_back(java_packet_user_properties_struct_holder, (void *)&jni_property_struct);
199         }
200         *java_packet_native_user_properties =
201             (struct aws_mqtt5_user_property *)java_packet_user_properties_struct_holder->data;
202     }
203     return AWS_OP_SUCCESS;
204 }
205 
s_allocate_user_properties_array_holders(struct aws_allocator * allocator,struct aws_array_list * holder_array,struct aws_array_list * user_property_array,size_t init_entries)206 static int s_allocate_user_properties_array_holders(
207     struct aws_allocator *allocator,
208     /* Contains buffer_and_cursor_array_holder_struct pointers */
209     struct aws_array_list *holder_array,
210     /* Contains aws_mqtt5_user_property pointers */
211     struct aws_array_list *user_property_array,
212     size_t init_entries) {
213 
214     if (init_entries > 0) {
215         if (aws_array_list_init_dynamic(
216                 holder_array, allocator, 2 * init_entries, sizeof(struct buffer_and_cursor_array_holder_struct)) !=
217                 AWS_OP_SUCCESS ||
218             aws_array_list_init_dynamic(
219                 user_property_array, allocator, 2 * init_entries, sizeof(struct aws_mqtt5_user_property)) !=
220                 AWS_OP_SUCCESS) {
221             return aws_raise_error(AWS_ERROR_INVALID_STATE);
222         }
223     }
224     return AWS_OP_SUCCESS;
225 }
226 
s_cleanup_two_aws_array(JNIEnv * env,struct aws_array_list * user_properties_holder,struct aws_array_list * user_properties_struct_holder)227 static void s_cleanup_two_aws_array(
228     JNIEnv *env,
229     struct aws_array_list *user_properties_holder,
230     struct aws_array_list *user_properties_struct_holder) {
231 
232     (void)env;
233     if (aws_array_list_is_valid(user_properties_holder)) {
234         /**
235          * Note that this ONLY frees the array holders for the non-struct array.
236          * We want to keep the struct one in memory since it belongs to a packet or similar.
237          * If both need to be freed, then we assume whomever is calling this will handle it.
238          */
239         for (size_t i = 0; i < aws_array_list_length(user_properties_holder); i++) {
240             struct buffer_and_cursor_array_holder_struct holder;
241             aws_array_list_get_at(user_properties_holder, &holder, i);
242             if (aws_byte_buf_is_valid(&holder.buffer)) {
243                 aws_byte_buf_clean_up(&holder.buffer);
244             }
245         }
246         aws_array_list_clean_up(user_properties_holder);
247     }
248     if (aws_array_list_is_valid(user_properties_struct_holder)) {
249         aws_array_list_clean_up(user_properties_struct_holder);
250     }
251 }
252 
aws_get_uint16_from_jobject(JNIEnv * env,jobject object,jfieldID object_field,char * object_name,char * field_name,uint16_t * result,bool optional,bool * was_value_set)253 int aws_get_uint16_from_jobject(
254     JNIEnv *env,
255     jobject object,
256     jfieldID object_field,
257     char *object_name,
258     char *field_name,
259     uint16_t *result,
260     bool optional,
261     bool *was_value_set) {
262 
263     if (was_value_set != NULL) {
264         *was_value_set = false;
265     }
266 
267     jobject jlong_obj = (*env)->GetObjectField(env, object, object_field);
268     if (aws_jni_check_and_clear_exception(env)) {
269         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
270         return aws_raise_error(AWS_ERROR_INVALID_STATE);
271     }
272     if (jlong_obj) {
273         jlong jlong_value = (*env)->CallLongMethod(env, jlong_obj, boxed_long_properties.long_value_method_id);
274         if (aws_jni_check_and_clear_exception(env)) {
275             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
276             return aws_raise_error(AWS_ERROR_INVALID_STATE);
277         }
278         int64_t jlong_value_check = (int64_t)jlong_value;
279         if (jlong_value_check < 0) {
280             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is less than 0", object_name, field_name);
281             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
282         } else if (jlong_value_check > UINT16_MAX) {
283             AWS_LOGF_ERROR(
284                 AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is more than UINT16_MAX", object_name, field_name);
285             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
286         }
287         *result = (uint16_t)jlong_value;
288 
289         if (was_value_set != NULL) {
290             *was_value_set = true;
291         }
292 
293         if (!optional) {
294             return AWS_OP_SUCCESS;
295         }
296     }
297 
298     if (optional) {
299         return AWS_OP_SUCCESS;
300     } else {
301         return AWS_OP_ERR;
302     }
303 }
304 
aws_get_uint32_from_jobject(JNIEnv * env,jobject object,jfieldID object_field,char * object_name,char * field_name,uint32_t * result,bool optional,bool * was_value_set)305 int aws_get_uint32_from_jobject(
306     JNIEnv *env,
307     jobject object,
308     jfieldID object_field,
309     char *object_name,
310     char *field_name,
311     uint32_t *result,
312     bool optional,
313     bool *was_value_set) {
314 
315     if (was_value_set != NULL) {
316         *was_value_set = false;
317     }
318 
319     jobject jlong_obj = (*env)->GetObjectField(env, object, object_field);
320     if (aws_jni_check_and_clear_exception(env)) {
321         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
322         return aws_raise_error(AWS_ERROR_INVALID_STATE);
323     }
324     if (jlong_obj) {
325         jlong jlong_value = (*env)->CallLongMethod(env, jlong_obj, boxed_long_properties.long_value_method_id);
326         if (aws_jni_check_and_clear_exception(env)) {
327             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
328             return aws_raise_error(AWS_ERROR_INVALID_STATE);
329         }
330         int64_t jlong_value_check = (int64_t)jlong_value;
331         if (jlong_value_check < 0) {
332             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is less than 0", object_name, field_name);
333             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
334         } else if (jlong_value_check > UINT32_MAX) {
335             AWS_LOGF_ERROR(
336                 AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is more than UINT32_MAX", object_name, field_name);
337             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
338         }
339         *result = (uint32_t)jlong_value_check;
340 
341         if (was_value_set != NULL) {
342             *was_value_set = true;
343         }
344 
345         if (!optional) {
346             return AWS_OP_SUCCESS;
347         }
348     }
349 
350     if (optional) {
351         return AWS_OP_SUCCESS;
352     } else {
353         return AWS_OP_ERR;
354     }
355 }
356 
aws_get_uint64_from_jobject(JNIEnv * env,jobject object,jfieldID object_field,char * object_name,char * field_name,uint64_t * result,bool optional,bool * was_value_set)357 int aws_get_uint64_from_jobject(
358     JNIEnv *env,
359     jobject object,
360     jfieldID object_field,
361     char *object_name,
362     char *field_name,
363     uint64_t *result,
364     bool optional,
365     bool *was_value_set) {
366 
367     if (was_value_set != NULL) {
368         *was_value_set = false;
369     }
370 
371     jobject jlong_obj = (*env)->GetObjectField(env, object, object_field);
372     if (aws_jni_check_and_clear_exception(env)) {
373         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
374         return aws_raise_error(AWS_ERROR_INVALID_STATE);
375     }
376     if (jlong_obj) {
377         jlong jlong_value = (*env)->CallLongMethod(env, jlong_obj, boxed_long_properties.long_value_method_id);
378         if (aws_jni_check_and_clear_exception(env)) {
379             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
380             return aws_raise_error(AWS_ERROR_INVALID_STATE);
381         }
382         int64_t jlong_value_check = (int64_t)jlong_value;
383         if (jlong_value_check < 0) {
384             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is less than 0", object_name, field_name);
385             return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
386         }
387         *result = (uint64_t)jlong_value_check;
388 
389         if (was_value_set != NULL) {
390             *was_value_set = true;
391         }
392 
393         if (!optional) {
394             return AWS_OP_SUCCESS;
395         }
396     }
397 
398     if (optional) {
399         return AWS_OP_SUCCESS;
400     } else {
401         return AWS_OP_ERR;
402     }
403 }
404 
aws_get_string_from_jobject(JNIEnv * env,jobject object,jfieldID object_field,char * object_name,char * field_name,struct aws_byte_buf * result_buf,struct aws_byte_cursor * result_cursor,bool is_optional,bool * was_value_set)405 int aws_get_string_from_jobject(
406     JNIEnv *env,
407     jobject object,
408     jfieldID object_field,
409     char *object_name,
410     char *field_name,
411     struct aws_byte_buf *result_buf,
412     struct aws_byte_cursor *result_cursor,
413     bool is_optional,
414     bool *was_value_set) {
415 
416     if (was_value_set != NULL) {
417         *was_value_set = false;
418     }
419 
420     jstring jstring_value = (jstring)(*env)->GetObjectField(env, object, object_field);
421     if (aws_jni_check_and_clear_exception(env)) {
422         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
423         return aws_raise_error(AWS_ERROR_INVALID_STATE);
424     }
425     if (jstring_value) {
426         // Get the data, copy it, and then release the JNI stuff
427         struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jstring_value);
428         aws_byte_buf_init_copy_from_cursor(result_buf, aws_jni_get_allocator(), tmp_cursor);
429         *result_cursor = aws_byte_cursor_from_buf(result_buf);
430         aws_jni_byte_cursor_from_jstring_release(env, jstring_value, tmp_cursor);
431 
432         if (was_value_set != NULL) {
433             *was_value_set = true;
434         }
435 
436         if (!is_optional) {
437             return AWS_OP_SUCCESS;
438         }
439     }
440     if (is_optional) {
441         return AWS_OP_SUCCESS;
442     } else {
443         return AWS_OP_ERR;
444     }
445 }
446 
aws_get_byte_array_from_jobject(JNIEnv * env,jobject object,jfieldID object_field,char * object_name,char * field_name,struct aws_byte_buf * result_buf,struct aws_byte_cursor * result_cursor,bool optional,bool * was_value_set)447 int aws_get_byte_array_from_jobject(
448     JNIEnv *env,
449     jobject object,
450     jfieldID object_field,
451     char *object_name,
452     char *field_name,
453     struct aws_byte_buf *result_buf,
454     struct aws_byte_cursor *result_cursor,
455     bool optional,
456     bool *was_value_set) {
457 
458     if (was_value_set != NULL) {
459         *was_value_set = false;
460     }
461 
462     jbyteArray jbyte_array_value = (jbyteArray)(*env)->GetObjectField(env, object, object_field);
463     if (aws_jni_check_and_clear_exception(env)) {
464         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
465         return aws_raise_error(AWS_ERROR_INVALID_STATE);
466     }
467     if (jbyte_array_value) {
468         // Get the data, copy it, and then release the JNI stuff
469         struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jbyteArray_acquire(env, jbyte_array_value);
470         aws_byte_buf_init_copy_from_cursor(result_buf, aws_jni_get_allocator(), tmp_cursor);
471         *result_cursor = aws_byte_cursor_from_buf(result_buf);
472         aws_jni_byte_cursor_from_jbyteArray_release(env, jbyte_array_value, tmp_cursor);
473 
474         if (was_value_set != NULL) {
475             *was_value_set = true;
476         }
477 
478         if (!optional) {
479             return AWS_OP_SUCCESS;
480         }
481     }
482     if (optional) {
483         return AWS_OP_SUCCESS;
484     } else {
485         return AWS_OP_ERR;
486     }
487 }
488 
aws_get_boolean_from_jobject(JNIEnv * env,jobject object,jfieldID object_field,char * object_name,char * field_name,uint8_t * result_boolean_int,bool optional,bool * was_value_set)489 int aws_get_boolean_from_jobject(
490     JNIEnv *env,
491     jobject object,
492     jfieldID object_field,
493     char *object_name,
494     char *field_name,
495     uint8_t *result_boolean_int,
496     bool optional,
497     bool *was_value_set) {
498 
499     if (was_value_set != NULL) {
500         *was_value_set = false;
501     }
502 
503     jobject jboolean_obj = (*env)->GetObjectField(env, object, object_field);
504     if (aws_jni_check_and_clear_exception(env)) {
505         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name);
506         return aws_raise_error(AWS_ERROR_INVALID_STATE);
507     }
508     if (jboolean_obj) {
509         jboolean jboolean_value =
510             (*env)->CallBooleanMethod(env, jboolean_obj, boxed_boolean_properties.boolean_get_value_id);
511         if (aws_jni_check_and_clear_exception(env)) {
512             AWS_LOGF_ERROR(
513                 AWS_LS_MQTT5_CLIENT,
514                 "%s create_from_java: Error getting native value from %s",
515                 object_name,
516                 field_name);
517             return aws_raise_error(AWS_ERROR_INVALID_STATE);
518         }
519         *result_boolean_int = (uint8_t)jboolean_value;
520         if (was_value_set != NULL) {
521             *was_value_set = true;
522         }
523         if (!optional) {
524             return AWS_OP_SUCCESS;
525         }
526     }
527 
528     if (optional) {
529         return AWS_OP_SUCCESS;
530     } else {
531         return AWS_OP_ERR;
532     }
533 }
534 
aws_get_enum_from_jobject(JNIEnv * env,jobject object,jmethodID object_enum_field,char * object_name,char * enum_name,jmethodID enum_value_field,uint32_t * enum_value_destination,bool optional,bool * was_value_set)535 int aws_get_enum_from_jobject(
536     JNIEnv *env,
537     jobject object,
538     jmethodID object_enum_field,
539     char *object_name,
540     char *enum_name,
541     jmethodID enum_value_field,
542     uint32_t *enum_value_destination,
543     bool optional,
544     bool *was_value_set) {
545 
546     if (was_value_set != NULL) {
547         *was_value_set = false;
548     }
549 
550     if (enum_value_destination == NULL) {
551         AWS_LOGF_ERROR(
552             AWS_LS_MQTT5_CLIENT,
553             "%s create_from_java: Error getting %s due to null destination",
554             object_name,
555             enum_name);
556         return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
557     }
558 
559     jobject jni_retain_handling_type = (*env)->CallObjectMethod(env, object, object_enum_field);
560     if (aws_jni_check_and_clear_exception(env)) {
561         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, enum_name);
562         return aws_raise_error(AWS_ERROR_INVALID_STATE);
563     }
564     if (jni_retain_handling_type) {
565         jint enum_value = (*env)->CallIntMethod(env, jni_retain_handling_type, enum_value_field);
566         if (aws_jni_check_and_clear_exception(env)) {
567             AWS_LOGF_ERROR(
568                 AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting native value from %s", object_name, enum_name);
569             return aws_raise_error(AWS_ERROR_INVALID_STATE);
570         }
571         if (enum_value < 0) {
572             AWS_LOGF_ERROR(
573                 AWS_LS_MQTT5_CLIENT,
574                 "%s create_from_java: Native value from %s is less than 0",
575                 object_name,
576                 enum_name);
577             return aws_raise_error(AWS_ERROR_INVALID_STATE);
578         } else if ((int32_t)enum_value > UINT16_MAX) {
579             AWS_LOGF_ERROR(
580                 AWS_LS_MQTT5_CLIENT,
581                 "%s create_from_java: Native value from %s is more than UINT16_MAX",
582                 object_name,
583                 enum_name);
584             return aws_raise_error(AWS_ERROR_INVALID_STATE);
585         }
586         *enum_value_destination = (int32_t)enum_value;
587         if (was_value_set != NULL) {
588             *was_value_set = true;
589         }
590         if (!optional) {
591             return AWS_OP_SUCCESS;
592         }
593     }
594     if (optional) {
595         return AWS_OP_SUCCESS;
596     } else {
597         return AWS_OP_ERR;
598     }
599 }
600 
s_get_user_properties_from_packet_optional(JNIEnv * env,jobject packet,jfieldID packet_field,char * packet_name,size_t * packet_user_property_count,struct aws_array_list * jni_user_properties_holder,struct aws_array_list * jni_user_properties_struct_holder,const struct aws_mqtt5_user_property ** packet_properties)601 static int s_get_user_properties_from_packet_optional(
602     JNIEnv *env,
603     jobject packet,
604     jfieldID packet_field,
605     char *packet_name,
606     size_t *packet_user_property_count,
607     /* Contains buffer_and_cursor_array_holder_struct pointers */
608     struct aws_array_list *jni_user_properties_holder,
609     /* Contains aws_mqtt5_user_property pointers */
610     struct aws_array_list *jni_user_properties_struct_holder,
611     const struct aws_mqtt5_user_property **packet_properties) {
612 
613     struct aws_allocator *allocator = aws_jni_get_allocator();
614 
615     jobject jni_list = (*env)->GetObjectField(env, packet, packet_field);
616     if (aws_jni_check_and_clear_exception(env)) {
617         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting user properties list", packet_name);
618         return aws_raise_error(AWS_ERROR_INVALID_STATE);
619     }
620     if (jni_list) {
621         jint jni_user_properties_size = (*env)->CallIntMethod(env, jni_list, boxed_list_properties.list_size_id);
622         if (aws_jni_check_and_clear_exception(env)) {
623             AWS_LOGF_ERROR(
624                 AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting user properties list size", packet_name);
625             return aws_raise_error(AWS_ERROR_INVALID_STATE);
626         }
627         *packet_user_property_count = (size_t)jni_user_properties_size;
628         if (AWS_OP_SUCCESS != s_allocate_user_properties_array_holders(
629                                   allocator,
630                                   jni_user_properties_holder,
631                                   jni_user_properties_struct_holder,
632                                   *packet_user_property_count)) {
633             AWS_LOGF_ERROR(
634                 AWS_LS_MQTT5_CLIENT, "%s create_from_java: Could not create user properties array", packet_name);
635             return aws_raise_error(AWS_ERROR_INVALID_STATE);
636         }
637         int populate_result = s_populate_user_properties(
638             env,
639             jni_list,
640             *packet_user_property_count,
641             packet_properties,
642             jni_user_properties_holder,
643             jni_user_properties_struct_holder);
644         if (populate_result != AWS_OP_SUCCESS) {
645             return aws_raise_error(AWS_ERROR_INVALID_STATE);
646         }
647     }
648     return AWS_OP_SUCCESS;
649 }
650 
s_get_qos_from_packet(JNIEnv * env,jobject packet,jmethodID packet_field,char * packet_name,enum aws_mqtt5_qos * packet_qos,bool optional,bool * was_value_set)651 static int s_get_qos_from_packet(
652     JNIEnv *env,
653     jobject packet,
654     jmethodID packet_field,
655     char *packet_name,
656     enum aws_mqtt5_qos *packet_qos,
657     bool optional,
658     bool *was_value_set) {
659 
660     if (was_value_set != NULL) {
661         *was_value_set = false;
662     }
663 
664     jobject jni_qos = (*env)->CallObjectMethod(env, packet, packet_field);
665     if (aws_jni_check_and_clear_exception(env)) {
666         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting QoS", packet_name);
667         return AWS_OP_ERR;
668     }
669     if (jni_qos) {
670         jint jni_qos_value = (*env)->CallIntMethod(env, jni_qos, mqtt5_packet_qos_properties.qos_get_value_id);
671         if (aws_jni_check_and_clear_exception(env)) {
672             AWS_LOGF_ERROR(
673                 AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting native value from QoS", packet_name);
674             return aws_raise_error(AWS_ERROR_INVALID_STATE);
675         }
676         *packet_qos = (enum aws_mqtt5_qos)jni_qos_value;
677         if (was_value_set != NULL) {
678             *was_value_set = true;
679         }
680         if (!optional) {
681             return AWS_OP_SUCCESS;
682         }
683     } else {
684         if (!optional) {
685             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: QoS not found", packet_name);
686             return aws_raise_error(AWS_ERROR_INVALID_STATE);
687         }
688     }
689     if (optional) {
690         return AWS_OP_SUCCESS;
691     } else {
692         return AWS_OP_ERR;
693     }
694 }
695 
696 static char s_connect_packet_string[] = "ConnectPacket";
697 static char s_disconnect_packet_string[] = "DisconnectPacket";
698 static char s_publish_packet_string[] = "PublishPacket";
699 static char s_subscribe_packet_string[] = "SubscribePacket";
700 static char s_unsubscribe_packet_string[] = "UnsubscribePacket";
701 
702 /*******************************************************************************
703  * CONNECT PACKET FUNCTIONS
704  ******************************************************************************/
705 
aws_mqtt5_packet_connect_view_java_destroy(JNIEnv * env,struct aws_allocator * allocator,struct aws_mqtt5_packet_connect_view_java_jni * java_packet)706 void aws_mqtt5_packet_connect_view_java_destroy(
707     JNIEnv *env,
708     struct aws_allocator *allocator,
709     struct aws_mqtt5_packet_connect_view_java_jni *java_packet) {
710     if (!java_packet) {
711         return;
712     }
713     AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying ConnectPacket", (void *)java_packet);
714 
715     if (aws_byte_buf_is_valid(&java_packet->client_id_buf)) {
716         aws_byte_buf_clean_up(&java_packet->client_id_buf);
717     }
718     if (aws_byte_buf_is_valid(&java_packet->username_buf)) {
719         aws_byte_buf_clean_up(&java_packet->username_buf);
720     }
721     if (aws_byte_buf_is_valid(&java_packet->password_buf)) {
722         aws_byte_buf_clean_up(&java_packet->password_buf);
723     }
724     if (java_packet->will_publish_packet) {
725         aws_mqtt5_packet_publish_view_java_destroy(env, allocator, java_packet->will_publish_packet);
726     }
727 
728     s_cleanup_two_aws_array(
729         env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder);
730     aws_mem_release(allocator, java_packet);
731 }
732 
733 /**
734  * Creates a JNI connack packet from the given Java connack packet and returns it. It creates a new packet but it does
735  * NOT free it. You will need to call aws_mqtt5_packet_connect_view_java_destroy when you are done with it.
736  */
aws_mqtt5_packet_connect_view_create_from_java(JNIEnv * env,struct aws_allocator * allocator,jobject java_connect_packet)737 struct aws_mqtt5_packet_connect_view_java_jni *aws_mqtt5_packet_connect_view_create_from_java(
738     JNIEnv *env,
739     struct aws_allocator *allocator,
740     jobject java_connect_packet) {
741     struct aws_mqtt5_packet_connect_view_java_jni *java_packet =
742         aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_connect_view_java_jni));
743     if (java_packet == NULL) {
744         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "ConnectPacket create_from_java: Creating new ConnectPacket failed");
745         return NULL;
746     }
747 
748     /* Needed to track if optionals are set or not */
749     bool was_value_set = false;
750 
751     if (aws_get_uint16_from_jobject(
752             env,
753             java_connect_packet,
754             mqtt5_connect_packet_properties.connect_keep_alive_interval_seconds_field_id,
755             s_connect_packet_string,
756             "keep alive interval seconds",
757             &java_packet->keep_alive_interval_seconds,
758             true,
759             &was_value_set) == AWS_OP_ERR) {
760         goto on_error;
761     }
762     if (was_value_set) {
763         java_packet->packet.keep_alive_interval_seconds = java_packet->keep_alive_interval_seconds;
764     }
765 
766     if (aws_get_string_from_jobject(
767             env,
768             java_connect_packet,
769             mqtt5_connect_packet_properties.connect_client_id_field_id,
770             s_connect_packet_string,
771             "client ID",
772             &java_packet->client_id_buf,
773             &java_packet->client_id_cursor,
774             true,
775             &was_value_set) == AWS_OP_ERR) {
776         goto on_error;
777     }
778     if (was_value_set) {
779         java_packet->packet.client_id = java_packet->client_id_cursor;
780     }
781 
782     if (aws_get_string_from_jobject(
783             env,
784             java_connect_packet,
785             mqtt5_connect_packet_properties.connect_username_field_id,
786             s_connect_packet_string,
787             "username",
788             &java_packet->username_buf,
789             &java_packet->username_cursor,
790             true,
791             &was_value_set) == AWS_OP_ERR) {
792         goto on_error;
793     }
794     if (was_value_set) {
795         java_packet->packet.username = &java_packet->username_cursor;
796     }
797 
798     if (aws_get_byte_array_from_jobject(
799             env,
800             java_connect_packet,
801             mqtt5_connect_packet_properties.connect_password_field_id,
802             s_connect_packet_string,
803             "password",
804             &java_packet->password_buf,
805             &java_packet->password_cursor,
806             true,
807             &was_value_set) == AWS_OP_ERR) {
808         goto on_error;
809     }
810     if (was_value_set) {
811         java_packet->packet.password = &java_packet->password_cursor;
812     }
813 
814     if (aws_get_uint32_from_jobject(
815             env,
816             java_connect_packet,
817             mqtt5_connect_packet_properties.connect_session_expiry_interval_seconds_field_id,
818             s_connect_packet_string,
819             "session expiry interval seconds",
820             &java_packet->session_expiry_interval_seconds,
821             true,
822             &was_value_set) == AWS_OP_ERR) {
823         goto on_error;
824     }
825     if (was_value_set) {
826         java_packet->packet.session_expiry_interval_seconds = &java_packet->session_expiry_interval_seconds;
827     }
828 
829     if (aws_get_boolean_from_jobject(
830             env,
831             java_connect_packet,
832             mqtt5_connect_packet_properties.connect_request_response_information_field_id,
833             s_connect_packet_string,
834             "request response information",
835             &java_packet->request_response_information,
836             true,
837             &was_value_set) == AWS_OP_ERR) {
838         goto on_error;
839     }
840     if (was_value_set) {
841         java_packet->packet.request_response_information = &java_packet->request_response_information;
842     }
843 
844     if (aws_get_boolean_from_jobject(
845             env,
846             java_connect_packet,
847             mqtt5_connect_packet_properties.connect_request_problem_information_field_id,
848             s_connect_packet_string,
849             "request problem information",
850             &java_packet->request_problem_information,
851             true,
852             &was_value_set) == AWS_OP_ERR) {
853         goto on_error;
854     }
855     if (was_value_set) {
856         java_packet->packet.request_problem_information = &java_packet->request_problem_information;
857     }
858 
859     if (aws_get_uint16_from_jobject(
860             env,
861             java_connect_packet,
862             mqtt5_connect_packet_properties.connect_receive_maximum_field_id,
863             s_connect_packet_string,
864             "receive maximum",
865             &java_packet->receive_maximum,
866             true,
867             &was_value_set) == AWS_OP_ERR) {
868         goto on_error;
869     }
870     if (was_value_set) {
871         java_packet->packet.receive_maximum = &java_packet->receive_maximum;
872     }
873 
874     if (aws_get_uint32_from_jobject(
875             env,
876             java_connect_packet,
877             mqtt5_connect_packet_properties.connect_maximum_packet_size_bytes_field_id,
878             s_connect_packet_string,
879             "maximum packet size",
880             &java_packet->maximum_packet_size_bytes,
881             true,
882             &was_value_set) == AWS_OP_ERR) {
883         goto on_error;
884     }
885     if (was_value_set) {
886         java_packet->packet.maximum_packet_size_bytes = &java_packet->maximum_packet_size_bytes;
887     }
888 
889     if (aws_get_uint32_from_jobject(
890             env,
891             java_connect_packet,
892             mqtt5_connect_packet_properties.connect_will_delay_interval_seconds_field_id,
893             s_connect_packet_string,
894             "will delay interval",
895             &java_packet->will_delay_interval_seconds,
896             true,
897             &was_value_set) == AWS_OP_ERR) {
898         goto on_error;
899     }
900     if (was_value_set) {
901         java_packet->packet.will_delay_interval_seconds = &java_packet->will_delay_interval_seconds;
902     }
903 
904     jobject jni_will_packet =
905         (*env)->GetObjectField(env, java_connect_packet, mqtt5_connect_packet_properties.connect_will_field_id);
906     if (aws_jni_check_and_clear_exception(env)) {
907         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "ConnectPacket create_from_java: Error getting will packet");
908         goto on_error;
909     }
910     if (jni_will_packet) {
911         java_packet->will_publish_packet =
912             aws_mqtt5_packet_publish_view_create_from_java(env, allocator, jni_will_packet);
913         if (java_packet->will_publish_packet == NULL) {
914             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "ConnectPacket create_from_java: Error getting will packet");
915             goto on_error;
916         }
917         java_packet->packet.will = &java_packet->will_publish_packet->packet;
918     }
919 
920     if (s_get_user_properties_from_packet_optional(
921             env,
922             java_connect_packet,
923             mqtt5_connect_packet_properties.connect_user_properties_field_id,
924             s_connect_packet_string,
925             &java_packet->packet.user_property_count,
926             &java_packet->jni_user_properties_holder,
927             &java_packet->jni_user_properties_struct_holder,
928             &java_packet->packet.user_properties) == AWS_OP_ERR) {
929         goto on_error;
930     }
931 
932     return java_packet;
933 
934 on_error:
935 
936     /* Clean up */
937     aws_mqtt5_packet_connect_view_java_destroy(env, allocator, java_packet);
938     return NULL;
939 }
940 
aws_mqtt5_packet_connect_view_get_packet(struct aws_mqtt5_packet_connect_view_java_jni * java_packet)941 struct aws_mqtt5_packet_connect_view *aws_mqtt5_packet_connect_view_get_packet(
942     struct aws_mqtt5_packet_connect_view_java_jni *java_packet) {
943     if (java_packet) {
944         return &java_packet->packet;
945     } else {
946         return NULL;
947     }
948 }
949 
950 /*******************************************************************************
951  * PACKET DISCONNECT FUNCTIONS
952  ******************************************************************************/
953 
aws_mqtt5_packet_disconnect_view_java_destroy(JNIEnv * env,struct aws_allocator * allocator,struct aws_mqtt5_packet_disconnect_view_java_jni * java_packet)954 void aws_mqtt5_packet_disconnect_view_java_destroy(
955     JNIEnv *env,
956     struct aws_allocator *allocator,
957     struct aws_mqtt5_packet_disconnect_view_java_jni *java_packet) {
958     if (!java_packet) {
959         return;
960     }
961     AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying DisconnectPacket", (void *)java_packet);
962 
963     if (aws_byte_buf_is_valid(&java_packet->reason_string_buf)) {
964         aws_byte_buf_clean_up(&java_packet->reason_string_buf);
965     }
966     if (aws_byte_buf_is_valid(&java_packet->server_reference_buf)) {
967         aws_byte_buf_clean_up(&java_packet->server_reference_buf);
968     }
969 
970     s_cleanup_two_aws_array(
971         env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder);
972     aws_mem_release(allocator, java_packet);
973 }
974 
aws_mqtt5_packet_disconnect_view_create_from_java(JNIEnv * env,struct aws_allocator * allocator,jobject java_disconnect_packet)975 struct aws_mqtt5_packet_disconnect_view_java_jni *aws_mqtt5_packet_disconnect_view_create_from_java(
976     JNIEnv *env,
977     struct aws_allocator *allocator,
978     jobject java_disconnect_packet) {
979 
980     struct aws_mqtt5_packet_disconnect_view_java_jni *java_packet =
981         aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_disconnect_view_java_jni));
982     if (java_packet == NULL) {
983         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "DisconnectPacket create_from_java: Creating new DisconnectPacket failed");
984         return NULL;
985     }
986 
987     /* Needed to track if optionals are set or not */
988     bool was_value_set = false;
989 
990     uint32_t reason_code_enum;
991     if (aws_get_enum_from_jobject(
992             env,
993             java_disconnect_packet,
994             mqtt5_disconnect_packet_properties.disconnect_get_reason_code_id,
995             s_disconnect_packet_string,
996             "reason code",
997             mqtt5_disconnect_reason_code_properties.code_get_value_id,
998             &reason_code_enum,
999             true,
1000             &was_value_set) == AWS_OP_ERR) {
1001         goto on_error;
1002     }
1003     if (was_value_set) {
1004         java_packet->packet.reason_code = (enum aws_mqtt5_disconnect_reason_code)reason_code_enum;
1005     }
1006 
1007     if (aws_get_uint32_from_jobject(
1008             env,
1009             java_disconnect_packet,
1010             mqtt5_disconnect_packet_properties.disconnect_session_expiry_interval_seconds_field_id,
1011             s_disconnect_packet_string,
1012             "session expiry interval seconds",
1013             &java_packet->session_expiry_interval_seconds,
1014             true,
1015             &was_value_set) == AWS_OP_ERR) {
1016         goto on_error;
1017     }
1018     if (was_value_set) {
1019         java_packet->packet.session_expiry_interval_seconds = &java_packet->session_expiry_interval_seconds;
1020     }
1021 
1022     if (aws_get_string_from_jobject(
1023             env,
1024             java_disconnect_packet,
1025             mqtt5_disconnect_packet_properties.disconnect_reason_string_field_id,
1026             s_disconnect_packet_string,
1027             "reason string",
1028             &java_packet->reason_string_buf,
1029             &java_packet->reason_string_cursor,
1030             true,
1031             &was_value_set) == AWS_OP_ERR) {
1032         goto on_error;
1033     }
1034     if (was_value_set) {
1035         java_packet->packet.reason_string = &java_packet->reason_string_cursor;
1036     }
1037 
1038     if (aws_get_string_from_jobject(
1039             env,
1040             java_disconnect_packet,
1041             mqtt5_disconnect_packet_properties.disconnect_session_server_reference_field_id,
1042             s_disconnect_packet_string,
1043             "server reference",
1044             &java_packet->server_reference_buf,
1045             &java_packet->server_reference_cursor,
1046             true,
1047             &was_value_set) == AWS_OP_ERR) {
1048         goto on_error;
1049     }
1050     if (was_value_set) {
1051         java_packet->packet.server_reference = &java_packet->server_reference_cursor;
1052     }
1053 
1054     if (s_get_user_properties_from_packet_optional(
1055             env,
1056             java_disconnect_packet,
1057             mqtt5_disconnect_packet_properties.disconnect_user_properties_field_id,
1058             s_disconnect_packet_string,
1059             &java_packet->packet.user_property_count,
1060             &java_packet->jni_user_properties_holder,
1061             &java_packet->jni_user_properties_struct_holder,
1062             &java_packet->packet.user_properties) == AWS_OP_ERR) {
1063         goto on_error;
1064     }
1065 
1066     return java_packet;
1067 
1068 on_error:
1069 
1070     /* Clean up */
1071     aws_mqtt5_packet_disconnect_view_java_destroy(env, allocator, java_packet);
1072     return NULL;
1073 }
1074 
aws_mqtt5_packet_disconnect_view_get_packet(struct aws_mqtt5_packet_disconnect_view_java_jni * java_packet)1075 struct aws_mqtt5_packet_disconnect_view *aws_mqtt5_packet_disconnect_view_get_packet(
1076     struct aws_mqtt5_packet_disconnect_view_java_jni *java_packet) {
1077     if (java_packet) {
1078         return &java_packet->packet;
1079     } else {
1080         return NULL;
1081     }
1082 }
1083 
1084 /*******************************************************************************
1085  * PUBLISH PACKET FUNCTIONS
1086  ******************************************************************************/
1087 
aws_mqtt5_packet_publish_view_java_destroy(JNIEnv * env,struct aws_allocator * allocator,struct aws_mqtt5_packet_publish_view_java_jni * java_packet)1088 void aws_mqtt5_packet_publish_view_java_destroy(
1089     JNIEnv *env,
1090     struct aws_allocator *allocator,
1091     struct aws_mqtt5_packet_publish_view_java_jni *java_packet) {
1092     if (!java_packet) {
1093         return;
1094     }
1095     AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying PublishPacket", (void *)java_packet);
1096 
1097     if (aws_byte_buf_is_valid(&java_packet->payload_buf)) {
1098         aws_byte_buf_clean_up(&java_packet->payload_buf);
1099     }
1100     if (aws_byte_buf_is_valid(&java_packet->topic_buf)) {
1101         aws_byte_buf_clean_up(&java_packet->topic_buf);
1102     }
1103     if (aws_byte_buf_is_valid(&java_packet->response_topic_buf)) {
1104         aws_byte_buf_clean_up(&java_packet->response_topic_buf);
1105     }
1106     if (aws_byte_buf_is_valid(&java_packet->correlation_data_buf)) {
1107         aws_byte_buf_clean_up(&java_packet->correlation_data_buf);
1108     }
1109     if (aws_byte_buf_is_valid(&java_packet->content_type_buf)) {
1110         aws_byte_buf_clean_up(&java_packet->content_type_buf);
1111     }
1112 
1113     s_cleanup_two_aws_array(
1114         env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder);
1115     aws_mem_release(allocator, java_packet);
1116 }
1117 
aws_mqtt5_packet_publish_view_create_from_java(JNIEnv * env,struct aws_allocator * allocator,jobject java_publish_packet)1118 struct aws_mqtt5_packet_publish_view_java_jni *aws_mqtt5_packet_publish_view_create_from_java(
1119     JNIEnv *env,
1120     struct aws_allocator *allocator,
1121     jobject java_publish_packet) {
1122 
1123     struct aws_mqtt5_packet_publish_view_java_jni *java_packet =
1124         aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_publish_view_java_jni));
1125     if (java_packet == NULL) {
1126         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "PublishPacket create_from_java: Creating new PublishPacket failed");
1127         return NULL;
1128     }
1129 
1130     /* Needed to track if optionals are set or not */
1131     bool was_value_set = false;
1132 
1133     if (aws_get_byte_array_from_jobject(
1134             env,
1135             java_publish_packet,
1136             mqtt5_publish_packet_properties.publish_payload_field_id,
1137             s_publish_packet_string,
1138             "payload",
1139             &java_packet->correlation_data_buf,
1140             &java_packet->payload_cursor,
1141             true,
1142             &was_value_set) == AWS_OP_ERR) {
1143         goto on_error;
1144     }
1145     if (was_value_set) {
1146         java_packet->packet.payload = java_packet->payload_cursor;
1147     }
1148 
1149     if (s_get_qos_from_packet(
1150             env,
1151             java_publish_packet,
1152             mqtt5_publish_packet_properties.publish_get_qos_id,
1153             s_publish_packet_string,
1154             &java_packet->packet.qos,
1155             false,
1156             NULL) == AWS_OP_ERR) {
1157         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "PublishPacket create_from_java: QOS not found");
1158         goto on_error;
1159     }
1160 
1161     uint8_t packet_retain;
1162     if (aws_get_boolean_from_jobject(
1163             env,
1164             java_publish_packet,
1165             mqtt5_publish_packet_properties.publish_retain_field_id,
1166             s_publish_packet_string,
1167             "retain",
1168             &packet_retain,
1169             true,
1170             &was_value_set) == AWS_OP_ERR) {
1171         goto on_error;
1172     }
1173     if (was_value_set) {
1174         java_packet->packet.retain = (bool)packet_retain;
1175     }
1176 
1177     if (aws_get_string_from_jobject(
1178             env,
1179             java_publish_packet,
1180             mqtt5_publish_packet_properties.publish_topic_field_id,
1181             s_publish_packet_string,
1182             "topic",
1183             &java_packet->topic_buf,
1184             &java_packet->topic_cursor,
1185             false,
1186             NULL) == AWS_OP_ERR) {
1187         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "PublishPacket create_from_java: No topic found");
1188         goto on_error;
1189     }
1190     java_packet->packet.topic = java_packet->topic_cursor;
1191 
1192     uint32_t format_enum;
1193     if (aws_get_enum_from_jobject(
1194             env,
1195             java_publish_packet,
1196             mqtt5_publish_packet_properties.publish_get_payload_format_id,
1197             s_publish_packet_string,
1198             "payload format",
1199             mqtt5_payload_format_indicator_properties.format_get_value_id,
1200             &format_enum,
1201             true,
1202             &was_value_set) == AWS_OP_ERR) {
1203         goto on_error;
1204     }
1205     if (was_value_set) {
1206         java_packet->payload_format = (enum aws_mqtt5_payload_format_indicator)format_enum;
1207         java_packet->packet.payload_format = &java_packet->payload_format;
1208     }
1209 
1210     if (aws_get_uint32_from_jobject(
1211             env,
1212             java_publish_packet,
1213             mqtt5_publish_packet_properties.publish_message_expiry_interval_seconds_field_id,
1214             s_publish_packet_string,
1215             "message expiry interval seconds",
1216             &java_packet->message_expiry_interval_seconds,
1217             true,
1218             &was_value_set) == AWS_OP_ERR) {
1219         goto on_error;
1220     }
1221     if (was_value_set) {
1222         java_packet->packet.message_expiry_interval_seconds = &java_packet->message_expiry_interval_seconds;
1223     }
1224 
1225     if (aws_get_uint16_from_jobject(
1226             env,
1227             java_publish_packet,
1228             mqtt5_publish_packet_properties.publish_topic_alias_field_id,
1229             s_publish_packet_string,
1230             "topic alias",
1231             &java_packet->topic_alias,
1232             true,
1233             &was_value_set) == AWS_OP_ERR) {
1234         goto on_error;
1235     }
1236     if (was_value_set) {
1237         java_packet->packet.topic_alias = &java_packet->topic_alias;
1238     }
1239 
1240     if (aws_get_string_from_jobject(
1241             env,
1242             java_publish_packet,
1243             mqtt5_publish_packet_properties.publish_response_topic_field_id,
1244             s_publish_packet_string,
1245             "response topic",
1246             &java_packet->response_topic_buf,
1247             &java_packet->response_topic_cursor,
1248             true,
1249             &was_value_set) == AWS_OP_ERR) {
1250         goto on_error;
1251     }
1252     if (was_value_set) {
1253         java_packet->packet.response_topic = &java_packet->response_topic_cursor;
1254     }
1255 
1256     if (aws_get_byte_array_from_jobject(
1257             env,
1258             java_publish_packet,
1259             mqtt5_publish_packet_properties.publish_correlation_data_field_id,
1260             s_publish_packet_string,
1261             "correlation data",
1262             &java_packet->correlation_data_buf,
1263             &java_packet->correlation_data_cursor,
1264             true,
1265             &was_value_set) == AWS_OP_ERR) {
1266         goto on_error;
1267     }
1268     if (was_value_set) {
1269         java_packet->packet.correlation_data = &java_packet->correlation_data_cursor;
1270     }
1271 
1272     if (aws_get_string_from_jobject(
1273             env,
1274             java_publish_packet,
1275             mqtt5_publish_packet_properties.publish_content_type_field_id,
1276             s_publish_packet_string,
1277             "content type",
1278             &java_packet->content_type_buf,
1279             &java_packet->content_type_cursor,
1280             true,
1281             &was_value_set) == AWS_OP_ERR) {
1282         goto on_error;
1283     }
1284     if (was_value_set) {
1285         java_packet->packet.content_type = &java_packet->content_type_cursor;
1286     }
1287 
1288     if (s_get_user_properties_from_packet_optional(
1289             env,
1290             java_publish_packet,
1291             mqtt5_publish_packet_properties.publish_user_properties_field_id,
1292             s_publish_packet_string,
1293             &java_packet->packet.user_property_count,
1294             &java_packet->jni_user_properties_holder,
1295             &java_packet->jni_user_properties_struct_holder,
1296             &java_packet->packet.user_properties) == AWS_OP_ERR) {
1297         goto on_error;
1298     }
1299 
1300     return java_packet;
1301 
1302 on_error:
1303 
1304     /* Clean up */
1305     aws_mqtt5_packet_publish_view_java_destroy(env, allocator, java_packet);
1306     return NULL;
1307 }
1308 
aws_mqtt5_packet_publish_view_get_packet(struct aws_mqtt5_packet_publish_view_java_jni * java_packet)1309 struct aws_mqtt5_packet_publish_view *aws_mqtt5_packet_publish_view_get_packet(
1310     struct aws_mqtt5_packet_publish_view_java_jni *java_packet) {
1311     if (java_packet) {
1312         return &java_packet->packet;
1313     } else {
1314         return NULL;
1315     }
1316 }
1317 
1318 /*******************************************************************************
1319  * SUBSCRIBE PACKET FUNCTIONS
1320  ******************************************************************************/
1321 
aws_mqtt5_packet_subscribe_view_java_destroy(JNIEnv * env,struct aws_allocator * allocator,struct aws_mqtt5_packet_subscribe_view_java_jni * java_packet)1322 void aws_mqtt5_packet_subscribe_view_java_destroy(
1323     JNIEnv *env,
1324     struct aws_allocator *allocator,
1325     struct aws_mqtt5_packet_subscribe_view_java_jni *java_packet) {
1326     if (!java_packet) {
1327         return;
1328     }
1329     AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying SubscribePacket", (void *)java_packet);
1330 
1331     s_cleanup_two_aws_array(
1332         env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder);
1333     s_cleanup_two_aws_array(env, &java_packet->jni_subscription_topic_filters, &java_packet->topic_filters);
1334     aws_mem_release(allocator, java_packet);
1335 }
1336 
aws_mqtt5_packet_subscribe_view_create_from_java(JNIEnv * env,struct aws_allocator * allocator,jobject java_subscribe_packet)1337 struct aws_mqtt5_packet_subscribe_view_java_jni *aws_mqtt5_packet_subscribe_view_create_from_java(
1338     JNIEnv *env,
1339     struct aws_allocator *allocator,
1340     jobject java_subscribe_packet) {
1341 
1342     jobject jni_subscriptions = (*env)->GetObjectField(
1343         env, java_subscribe_packet, mqtt5_subscribe_packet_properties.subscribe_subscriptions_field_id);
1344     if (aws_jni_check_and_clear_exception(env)) {
1345         return NULL;
1346     }
1347     if (!jni_subscriptions) {
1348         AWS_LOGF_ERROR(
1349             AWS_LS_MQTT5_CLIENT,
1350             "SubscribePacket create_from_java: Creating new SubscribePacket failed due to no subscriptions!");
1351         return NULL;
1352     }
1353     jint jni_subscriptions_size = (*env)->CallIntMethod(env, jni_subscriptions, boxed_list_properties.list_size_id);
1354     if (aws_jni_check_and_clear_exception(env)) {
1355         return NULL;
1356     }
1357     size_t subscriptions_filter_size = (size_t)jni_subscriptions_size;
1358 
1359     if (subscriptions_filter_size <= 0) {
1360         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: subscriptions count is 0");
1361         return NULL;
1362     }
1363 
1364     struct aws_mqtt5_packet_subscribe_view_java_jni *java_packet =
1365         aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_subscribe_view_java_jni));
1366     if (java_packet == NULL) {
1367         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Creating new SubscribePacket failed");
1368         return NULL;
1369     }
1370     int array_init = aws_array_list_init_dynamic(
1371         &java_packet->topic_filters, allocator, subscriptions_filter_size, sizeof(struct aws_mqtt5_subscription_view));
1372     if (array_init != AWS_OP_SUCCESS) {
1373         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Creating new SubscribePacket failed");
1374         goto on_error;
1375     }
1376     int jni_array_init = aws_array_list_init_dynamic(
1377         &java_packet->jni_subscription_topic_filters,
1378         allocator,
1379         subscriptions_filter_size,
1380         sizeof(struct buffer_and_cursor_array_holder_struct));
1381     if (jni_array_init != AWS_OP_SUCCESS) {
1382         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Creating new SubscribePacket failed");
1383         goto on_error;
1384     }
1385 
1386     /* Needed to track if optionals are set or not */
1387     bool was_value_set = false;
1388 
1389     if (aws_get_uint32_from_jobject(
1390             env,
1391             java_subscribe_packet,
1392             mqtt5_subscribe_packet_properties.subscribe_subscription_identifier_field_id,
1393             s_subscribe_packet_string,
1394             "subscription identifier",
1395             &java_packet->subscription_identifier,
1396             true,
1397             &was_value_set) == AWS_OP_ERR) {
1398         goto on_error;
1399     }
1400     if (was_value_set) {
1401         java_packet->packet.subscription_identifier = &java_packet->subscription_identifier;
1402     }
1403 
1404     java_packet->packet.subscription_count = subscriptions_filter_size;
1405     for (size_t i = 0; i < subscriptions_filter_size; i++) {
1406         /* Populate */
1407         struct aws_mqtt5_subscription_view subscription_view;
1408         struct buffer_and_cursor_array_holder_struct holder;
1409 
1410         jobject jni_packet_subscribe_subscription =
1411             (*env)->CallObjectMethod(env, jni_subscriptions, boxed_list_properties.list_get_id, (jint)i);
1412         if (aws_jni_check_and_clear_exception(env)) {
1413             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Error getting topic filters");
1414             goto on_error;
1415         }
1416 
1417         jstring jni_topic_filter = (jstring)(*env)->CallObjectMethod(
1418             env, jni_packet_subscribe_subscription, mqtt5_subscription_properties.subscribe_get_topic_filter_id);
1419         if (aws_jni_check_and_clear_exception(env)) {
1420             AWS_LOGF_ERROR(
1421                 AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Error getting subscription topic filter");
1422             goto on_error;
1423         }
1424         if (jni_topic_filter) {
1425             // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy.
1426             // This gets around JNI stuff going out of scope.
1427             struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_topic_filter);
1428             aws_byte_buf_init_copy_from_cursor(&holder.buffer, aws_jni_get_allocator(), tmp_cursor);
1429             holder.cursor = aws_byte_cursor_from_buf(&holder.buffer);
1430             aws_jni_byte_cursor_from_jstring_release(env, jni_topic_filter, tmp_cursor);
1431             subscription_view.topic_filter = holder.cursor;
1432             jni_topic_filter = NULL;
1433         } else {
1434             AWS_LOGF_ERROR(
1435                 AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: subscription topic filter is required");
1436             goto on_error;
1437         }
1438 
1439         if (s_get_qos_from_packet(
1440                 env,
1441                 jni_packet_subscribe_subscription,
1442                 mqtt5_subscription_properties.subscribe_get_qos_id,
1443                 s_subscribe_packet_string,
1444                 &subscription_view.qos,
1445                 false,
1446                 NULL) == AWS_OP_ERR) {
1447             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: subscription QoS is required");
1448             goto on_error;
1449         }
1450 
1451         uint8_t subscription_no_local;
1452         if (aws_get_boolean_from_jobject(
1453                 env,
1454                 jni_packet_subscribe_subscription,
1455                 mqtt5_subscription_properties.subscribe_no_local_field_id,
1456                 s_subscribe_packet_string,
1457                 "no local",
1458                 &subscription_no_local,
1459                 true,
1460                 &was_value_set) != AWS_OP_SUCCESS) {
1461             goto on_error;
1462         }
1463         if (was_value_set) {
1464             subscription_view.no_local = (bool)subscription_no_local;
1465         }
1466 
1467         uint8_t retain_as_published;
1468         if (aws_get_boolean_from_jobject(
1469                 env,
1470                 jni_packet_subscribe_subscription,
1471                 mqtt5_subscription_properties.subscribe_retain_as_published_field_id,
1472                 s_subscribe_packet_string,
1473                 "retain as published",
1474                 &retain_as_published,
1475                 true,
1476                 &was_value_set) != AWS_OP_SUCCESS) {
1477             goto on_error;
1478         }
1479         if (was_value_set) {
1480             subscription_view.retain_as_published = (bool)retain_as_published;
1481         }
1482 
1483         uint32_t retain_enum;
1484         if (aws_get_enum_from_jobject(
1485                 env,
1486                 jni_packet_subscribe_subscription,
1487                 mqtt5_subscription_properties.subscribe_get_retain_handling_type_id,
1488                 s_subscribe_packet_string,
1489                 "subscription retain handling type",
1490                 mqtt5_retain_handling_type_properties.retain_get_value_id,
1491                 &retain_enum,
1492                 true,
1493                 &was_value_set) == AWS_OP_ERR) {
1494             goto on_error;
1495         }
1496         if (was_value_set) {
1497             subscription_view.retain_handling_type = (enum aws_mqtt5_retain_handling_type)retain_enum;
1498         }
1499 
1500         aws_array_list_push_back(&java_packet->topic_filters, (void *)&subscription_view);
1501         aws_array_list_push_back(&java_packet->jni_subscription_topic_filters, (void *)&holder);
1502     }
1503     java_packet->packet.subscriptions = (struct aws_mqtt5_subscription_view *)java_packet->topic_filters.data;
1504 
1505     if (s_get_user_properties_from_packet_optional(
1506             env,
1507             java_subscribe_packet,
1508             mqtt5_subscribe_packet_properties.subscribe_user_properties_field_id,
1509             s_subscribe_packet_string,
1510             &java_packet->packet.user_property_count,
1511             &java_packet->jni_user_properties_holder,
1512             &java_packet->jni_user_properties_struct_holder,
1513             &java_packet->packet.user_properties) == AWS_OP_ERR) {
1514         goto on_error;
1515     }
1516 
1517     return java_packet;
1518 
1519 on_error:
1520 
1521     /* Clean up */
1522     aws_mqtt5_packet_subscribe_view_java_destroy(env, allocator, java_packet);
1523     return NULL;
1524 }
1525 
aws_mqtt5_packet_subscribe_view_get_packet(struct aws_mqtt5_packet_subscribe_view_java_jni * java_packet)1526 struct aws_mqtt5_packet_subscribe_view *aws_mqtt5_packet_subscribe_view_get_packet(
1527     struct aws_mqtt5_packet_subscribe_view_java_jni *java_packet) {
1528     if (java_packet) {
1529         return &java_packet->packet;
1530     } else {
1531         return NULL;
1532     }
1533 }
1534 
1535 /*******************************************************************************
1536  * UNSUBSCRIBE PACKET FUNCTIONS
1537  ******************************************************************************/
1538 
aws_mqtt5_packet_unsubscribe_view_java_destroy(JNIEnv * env,struct aws_allocator * allocator,struct aws_mqtt5_packet_unsubscribe_view_java_jni * java_packet)1539 void aws_mqtt5_packet_unsubscribe_view_java_destroy(
1540     JNIEnv *env,
1541     struct aws_allocator *allocator,
1542     struct aws_mqtt5_packet_unsubscribe_view_java_jni *java_packet) {
1543     if (!java_packet) {
1544         return;
1545     }
1546     AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying UnsubscribePacket", (void *)java_packet);
1547 
1548     s_cleanup_two_aws_array(
1549         env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder);
1550     s_cleanup_two_aws_array(env, &java_packet->jni_topic_filters, &java_packet->topic_filters);
1551     aws_mem_release(allocator, java_packet);
1552 }
1553 
aws_mqtt5_packet_unsubscribe_view_create_from_java(JNIEnv * env,struct aws_allocator * allocator,jobject java_unsubscribe_packet)1554 struct aws_mqtt5_packet_unsubscribe_view_java_jni *aws_mqtt5_packet_unsubscribe_view_create_from_java(
1555     JNIEnv *env,
1556     struct aws_allocator *allocator,
1557     jobject java_unsubscribe_packet) {
1558 
1559     jobject jni_topic_filters = (*env)->GetObjectField(
1560         env, java_unsubscribe_packet, mqtt5_unsubscribe_packet_properties.unsubscribe_subscriptions_field_id);
1561     if (aws_jni_check_and_clear_exception(env)) {
1562         return NULL;
1563     }
1564     if (!jni_topic_filters) {
1565         AWS_LOGF_ERROR(
1566             AWS_LS_MQTT5_CLIENT,
1567             "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed due to no topic filters");
1568         return NULL;
1569     }
1570 
1571     size_t topic_filter_size = 0;
1572     jint jni_topic_filter_size = (*env)->CallIntMethod(env, jni_topic_filters, boxed_list_properties.list_size_id);
1573     if (aws_jni_check_and_clear_exception(env)) {
1574         AWS_LOGF_ERROR(
1575             AWS_LS_MQTT5_CLIENT,
1576             "UnsubscribePacket create_from_java: Created new UnsubscribePacket failed due to no topic filters");
1577         return NULL;
1578     }
1579     int32_t jni_topic_filter_size_check = (int32_t)jni_topic_filter_size;
1580     if (jni_topic_filter_size_check < 0) {
1581         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: No topic filters found");
1582         return NULL;
1583     } else {
1584         topic_filter_size = (size_t)jni_topic_filter_size;
1585     }
1586 
1587     struct aws_mqtt5_packet_unsubscribe_view_java_jni *java_packet =
1588         aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_unsubscribe_view_java_jni));
1589     if (java_packet == NULL) {
1590         AWS_LOGF_ERROR(
1591             AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed");
1592         return NULL;
1593     }
1594     int array_init = aws_array_list_init_dynamic(
1595         &java_packet->topic_filters, allocator, topic_filter_size, sizeof(struct aws_byte_cursor));
1596     if (array_init != AWS_OP_SUCCESS) {
1597         AWS_LOGF_ERROR(
1598             AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed");
1599         goto on_error;
1600     }
1601     int jni_array_init = aws_array_list_init_dynamic(
1602         &java_packet->jni_topic_filters,
1603         allocator,
1604         topic_filter_size,
1605         sizeof(struct buffer_and_cursor_array_holder_struct));
1606     if (jni_array_init != AWS_OP_SUCCESS) {
1607         AWS_LOGF_ERROR(
1608             AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed");
1609         goto on_error;
1610     }
1611 
1612     java_packet->packet.topic_filter_count = topic_filter_size;
1613 
1614     for (size_t i = 0; i < topic_filter_size; i++) {
1615         /* Populate */
1616         struct buffer_and_cursor_array_holder_struct holder;
1617 
1618         jstring jni_topic_filter =
1619             (jstring)(*env)->CallObjectMethod(env, jni_topic_filters, boxed_list_properties.list_get_id, (jint)i);
1620         if (aws_jni_check_and_clear_exception(env)) {
1621             AWS_LOGF_ERROR(
1622                 AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Error getting subscription topic filter");
1623             goto on_error;
1624         }
1625         if (jni_topic_filter) {
1626             // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy.
1627             // This gets around JNI stuff going out of scope.
1628             struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_topic_filter);
1629             aws_byte_buf_init_copy_from_cursor(&holder.buffer, aws_jni_get_allocator(), tmp_cursor);
1630             holder.cursor = aws_byte_cursor_from_buf(&holder.buffer);
1631             aws_jni_byte_cursor_from_jstring_release(env, jni_topic_filter, tmp_cursor);
1632             jni_topic_filter = NULL;
1633         }
1634         aws_array_list_push_back(&java_packet->topic_filters, (void *)&holder.cursor);
1635         aws_array_list_push_back(&java_packet->jni_topic_filters, (void *)&holder);
1636     }
1637     java_packet->packet.topic_filters = (struct aws_byte_cursor *)java_packet->topic_filters.data;
1638 
1639     if (s_get_user_properties_from_packet_optional(
1640             env,
1641             java_unsubscribe_packet,
1642             mqtt5_unsubscribe_packet_properties.unsubscribe_user_properties_field_id,
1643             s_unsubscribe_packet_string,
1644             &java_packet->packet.user_property_count,
1645             &java_packet->jni_user_properties_holder,
1646             &java_packet->jni_user_properties_struct_holder,
1647             &java_packet->packet.user_properties) == AWS_OP_ERR) {
1648         goto on_error;
1649     }
1650 
1651     return java_packet;
1652 
1653 on_error:
1654 
1655     /* Clean up */
1656     aws_mqtt5_packet_unsubscribe_view_java_destroy(env, allocator, java_packet);
1657     return NULL;
1658 }
1659 
aws_mqtt5_packet_unsubscribe_view_get_packet(struct aws_mqtt5_packet_unsubscribe_view_java_jni * java_packet)1660 struct aws_mqtt5_packet_unsubscribe_view *aws_mqtt5_packet_unsubscribe_view_get_packet(
1661     struct aws_mqtt5_packet_unsubscribe_view_java_jni *java_packet) {
1662     if (java_packet) {
1663         return &java_packet->packet;
1664     } else {
1665         return NULL;
1666     }
1667 }
1668 
1669 #if UINTPTR_MAX == 0xffffffff
1670 #    if defined(_MSC_VER)
1671 #        pragma warning(pop)
1672 #    else
1673 #        pragma GCC diagnostic pop
1674 #    endif
1675 #endif
1676