xref: /aosp_15_r20/external/aws-crt-java/src/native/mqtt5_utils.c (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #include <jni.h>
7 
8 #include <crt.h>
9 #include <java_class_ids.h>
10 #include <mqtt5_packets.h>
11 #include <mqtt5_utils.h>
12 
13 /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
14 #if UINTPTR_MAX == 0xffffffff
15 #    if defined(_MSC_VER)
16 #        pragma warning(push)
17 #        pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
18 #    else
19 #        pragma GCC diagnostic push
20 #        pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
21 #        pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
22 #    endif
23 #endif
24 
s_set_jni_uint32_t_field_in_packet(JNIEnv * env,const uint32_t * native_integer,jobject packet,jfieldID field_id,char * field_name,bool optional)25 int s_set_jni_uint32_t_field_in_packet(
26     JNIEnv *env,
27     const uint32_t *native_integer,
28     jobject packet,
29     jfieldID field_id,
30     char *field_name,
31     bool optional) {
32 
33     if (native_integer != NULL) {
34         jobject jni_long = (*env)->NewObject(
35             env, boxed_long_properties.long_class, boxed_long_properties.constructor, (jlong)*native_integer);
36         if (aws_jni_check_and_clear_exception(env)) {
37             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not create uint32 field %s", field_name);
38             return AWS_OP_ERR;
39         }
40         (*env)->SetObjectField(env, packet, field_id, jni_long);
41         if (aws_jni_check_and_clear_exception(env)) {
42             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set uint32 field %s", field_name);
43             return AWS_OP_ERR;
44         }
45         if (!optional) {
46             return AWS_OP_SUCCESS;
47         }
48     }
49     if (optional) {
50         return AWS_OP_SUCCESS;
51     } else {
52         return AWS_OP_ERR;
53     }
54 }
55 
s_set_jni_uint16_t_field_in_packet(JNIEnv * env,const uint16_t * native_integer,jobject packet,jfieldID field_id,char * field_name,bool optional)56 int s_set_jni_uint16_t_field_in_packet(
57     JNIEnv *env,
58     const uint16_t *native_integer,
59     jobject packet,
60     jfieldID field_id,
61     char *field_name,
62     bool optional) {
63     if (native_integer != NULL) {
64         jobject jni_int = (*env)->NewObject(
65             env,
66             boxed_integer_properties.integer_class,
67             boxed_integer_properties.integer_constructor_id,
68             (jint)*native_integer);
69         if (aws_jni_check_and_clear_exception(env)) {
70             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not create uint16 field %s", field_name);
71             return AWS_OP_ERR;
72         }
73         (*env)->SetObjectField(env, packet, field_id, jni_int);
74         if (aws_jni_check_and_clear_exception(env)) {
75             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set uint16 field %s", field_name);
76             return AWS_OP_ERR;
77         }
78         if (!optional) {
79             return AWS_OP_SUCCESS;
80         }
81     }
82     if (optional) {
83         return AWS_OP_SUCCESS;
84     } else {
85         return AWS_OP_ERR;
86     }
87 }
88 
s_set_jni_bool_field_in_packet(JNIEnv * env,const bool * native_boolean,jobject packet,jfieldID field_id,char * field_name,bool optional)89 int s_set_jni_bool_field_in_packet(
90     JNIEnv *env,
91     const bool *native_boolean,
92     jobject packet,
93     jfieldID field_id,
94     char *field_name,
95     bool optional) {
96     if (native_boolean != NULL) {
97         jobject jni_boolean = (*env)->NewObject(
98             env,
99             boxed_boolean_properties.boolean_class,
100             boxed_boolean_properties.boolean_constructor_id,
101             (jboolean)*native_boolean);
102         if (aws_jni_check_and_clear_exception(env)) {
103             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not create boolean field %s", field_name);
104             return AWS_OP_ERR;
105         }
106 
107         (*env)->SetObjectField(env, packet, field_id, jni_boolean);
108         if (aws_jni_check_and_clear_exception(env)) {
109             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set boolean field %s", field_name);
110             return AWS_OP_ERR;
111         }
112 
113         if (!optional) {
114             return AWS_OP_SUCCESS;
115         }
116     }
117     if (optional) {
118         return AWS_OP_SUCCESS;
119     } else {
120         return AWS_OP_ERR;
121     }
122 }
123 
s_set_jni_string_field_in_packet(JNIEnv * env,const struct aws_byte_cursor * native_cursor,jobject packet,jfieldID field_id,char * field_name,bool optional)124 int s_set_jni_string_field_in_packet(
125     JNIEnv *env,
126     const struct aws_byte_cursor *native_cursor,
127     jobject packet,
128     jfieldID field_id,
129     char *field_name,
130     bool optional) {
131     if (native_cursor != NULL) {
132         jstring jni_string = aws_jni_string_from_cursor(env, native_cursor);
133         (*env)->SetObjectField(env, packet, field_id, jni_string);
134         if (aws_jni_check_and_clear_exception(env)) {
135             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set string field %s", field_name);
136             return AWS_OP_ERR;
137         }
138         if (!optional) {
139             return AWS_OP_SUCCESS;
140         }
141     }
142     if (optional) {
143         return AWS_OP_SUCCESS;
144     } else {
145         return AWS_OP_ERR;
146     }
147 }
148 
s_set_jni_byte_array_field_in_packet(JNIEnv * env,const struct aws_byte_cursor * native_cursor,jobject packet,jfieldID field_id,char * field_name,bool optional)149 int s_set_jni_byte_array_field_in_packet(
150     JNIEnv *env,
151     const struct aws_byte_cursor *native_cursor,
152     jobject packet,
153     jfieldID field_id,
154     char *field_name,
155     bool optional) {
156     if (native_cursor != NULL) {
157         jbyteArray jni_byte = aws_jni_byte_array_from_cursor(env, native_cursor);
158         (*env)->SetObjectField(env, packet, field_id, jni_byte);
159         if (aws_jni_check_and_clear_exception(env)) {
160             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set string field %s", field_name);
161             return AWS_OP_ERR;
162         }
163         if (!optional) {
164             return AWS_OP_SUCCESS;
165         }
166     }
167     if (optional) {
168         return AWS_OP_SUCCESS;
169     } else {
170         return AWS_OP_ERR;
171     }
172 }
173 
s_set_user_properties_field(JNIEnv * env,const size_t user_property_count,const struct aws_mqtt5_user_property * packet_properties,jobject packet,jfieldID user_property_field_id)174 int s_set_user_properties_field(
175     JNIEnv *env,
176     const size_t user_property_count,
177     const struct aws_mqtt5_user_property *packet_properties,
178     jobject packet,
179     jfieldID user_property_field_id) {
180     /* No properties - nothing to do */
181     if (packet_properties == NULL) {
182         return AWS_OP_SUCCESS;
183     }
184 
185     if (user_property_count > 0) {
186         jobject jni_user_properties_list = (*env)->NewObject(
187             env, boxed_array_list_properties.list_class, boxed_array_list_properties.list_constructor_id);
188         if (aws_jni_check_and_clear_exception(env)) {
189             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not make new user properties list");
190             return AWS_OP_ERR;
191         }
192 
193         (*env)->SetObjectField(env, packet, user_property_field_id, jni_user_properties_list);
194         if (aws_jni_check_and_clear_exception(env)) {
195             AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set new user properties list");
196             return AWS_OP_ERR;
197         }
198 
199         for (size_t i = 0; i < user_property_count; ++i) {
200             const struct aws_mqtt5_user_property *property = &packet_properties[i];
201             jstring jni_new_property_name = aws_jni_string_from_cursor(env, &property->name);
202             jstring jni_new_property_value = aws_jni_string_from_cursor(env, &property->value);
203 
204             jobject jni_new_property = (*env)->NewObject(
205                 env,
206                 mqtt5_user_property_properties.user_property_class,
207                 mqtt5_user_property_properties.property_constructor_id,
208                 jni_new_property_name,
209                 jni_new_property_value);
210             if (aws_jni_check_and_clear_exception(env)) {
211                 AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not make new user property");
212                 return AWS_OP_ERR;
213             }
214 
215             jboolean jni_add_result = (*env)->CallBooleanMethod(
216                 env, jni_user_properties_list, boxed_list_properties.list_add_id, jni_new_property);
217             if (aws_jni_check_and_clear_exception(env)) {
218                 AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not add new user property");
219                 return AWS_OP_ERR;
220             }
221 
222             if ((bool)jni_add_result == false) {
223                 return AWS_OP_ERR;
224             }
225         }
226     }
227     return AWS_OP_SUCCESS;
228 }
229 
s_set_int_enum_in_packet(JNIEnv * env,const int * int_enum,jobject packet,jmethodID set_enum_field_id,bool optional)230 int s_set_int_enum_in_packet(
231     JNIEnv *env,
232     const int *int_enum,
233     jobject packet,
234     jmethodID set_enum_field_id,
235     bool optional) {
236 
237     if (int_enum) {
238         if (*int_enum < 0) {
239             return AWS_OP_ERR;
240         }
241         (*env)->CallVoidMethod(env, packet, set_enum_field_id, (jint)*int_enum);
242         if (aws_jni_check_and_clear_exception(env)) {
243             return AWS_OP_ERR;
244         }
245 
246         if (!optional) {
247             return AWS_OP_SUCCESS;
248         }
249     }
250 
251     if (optional) {
252         return AWS_OP_SUCCESS;
253     } else {
254         return AWS_OP_ERR;
255     }
256 }
257 
s_aws_mqtt5_client_create_jni_connack_packet_from_native(JNIEnv * env,const struct aws_mqtt5_packet_connack_view * native_connack_data)258 jobject s_aws_mqtt5_client_create_jni_connack_packet_from_native(
259     JNIEnv *env,
260     const struct aws_mqtt5_packet_connack_view *native_connack_data) {
261 
262     jobject connack_data = (*env)->NewObject(
263         env,
264         mqtt5_connack_packet_properties.connack_packet_class,
265         mqtt5_connack_packet_properties.connack_constructor_id);
266 
267     (*env)->SetBooleanField(
268         env,
269         connack_data,
270         mqtt5_connack_packet_properties.connack_session_present_field_id,
271         (jboolean)native_connack_data->session_present);
272 
273     int reason_code_int = (int)native_connack_data->reason_code;
274     if (reason_code_int < 0) {
275         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating ConnAckPacket from native: Reason code is negative!");
276         return NULL;
277     }
278     (*env)->CallVoidMethod(
279         env, connack_data, mqtt5_connack_packet_properties.connack_native_add_reason_code_id, (jint)reason_code_int);
280 
281     /* Set all of the optional data in Java classes */
282     if (s_set_jni_uint32_t_field_in_packet(
283             env,
284             native_connack_data->session_expiry_interval,
285             connack_data,
286             mqtt5_connack_packet_properties.connack_session_expiry_interval_field_id,
287             "session expiry interval",
288             true) != AWS_OP_SUCCESS) {
289         return NULL;
290     }
291     if (s_set_jni_uint16_t_field_in_packet(
292             env,
293             native_connack_data->receive_maximum,
294             connack_data,
295             mqtt5_connack_packet_properties.connack_receive_maximum_field_id,
296             "receive maximum",
297             true) != AWS_OP_SUCCESS) {
298         return NULL;
299     };
300 
301     if (native_connack_data->maximum_qos) {
302         int *maximum_qos_int = (int *)native_connack_data->maximum_qos;
303         if (s_set_int_enum_in_packet(
304                 env,
305                 maximum_qos_int,
306                 connack_data,
307                 mqtt5_connack_packet_properties.connack_native_add_maximum_qos_id,
308                 true) != AWS_OP_SUCCESS) {
309             AWS_LOGF_ERROR(
310                 AWS_LS_MQTT5_CLIENT, "Error when creating ConnAckPacket from native: Could not set maximum QOS");
311             return NULL;
312         }
313     }
314 
315     if (s_set_jni_bool_field_in_packet(
316             env,
317             native_connack_data->retain_available,
318             connack_data,
319             mqtt5_connack_packet_properties.connack_retain_available_field_id,
320             "retain available",
321             true) != AWS_OP_SUCCESS) {
322         return NULL;
323     }
324     if (s_set_jni_uint32_t_field_in_packet(
325             env,
326             native_connack_data->maximum_packet_size,
327             connack_data,
328             mqtt5_connack_packet_properties.connack_maximum_packet_size_field_id,
329             "maximum packet size",
330             true) != AWS_OP_SUCCESS) {
331         return NULL;
332     }
333     if (s_set_jni_string_field_in_packet(
334             env,
335             native_connack_data->assigned_client_identifier,
336             connack_data,
337             mqtt5_connack_packet_properties.connack_assigned_client_identifier_field_id,
338             "assigned client identifier",
339             true) != AWS_OP_SUCCESS) {
340         return NULL;
341     }
342     if (s_set_jni_uint16_t_field_in_packet(
343             env,
344             native_connack_data->topic_alias_maximum,
345             connack_data,
346             mqtt5_connack_packet_properties.connack_topic_alias_maximum_field_id,
347             "topic alias maximum",
348             true) != AWS_OP_SUCCESS) {
349         return NULL;
350     };
351     if (s_set_jni_string_field_in_packet(
352             env,
353             native_connack_data->reason_string,
354             connack_data,
355             mqtt5_connack_packet_properties.connack_reason_string_field_id,
356             "reason string",
357             true) != AWS_OP_SUCCESS) {
358         return NULL;
359     }
360     if (s_set_jni_bool_field_in_packet(
361             env,
362             native_connack_data->wildcard_subscriptions_available,
363             connack_data,
364             mqtt5_connack_packet_properties.connack_wildcard_subscriptions_available_field_id,
365             "wildcard subscriptions available",
366             true) != AWS_OP_SUCCESS) {
367         return NULL;
368     };
369     if (s_set_jni_bool_field_in_packet(
370             env,
371             native_connack_data->subscription_identifiers_available,
372             connack_data,
373             mqtt5_connack_packet_properties.connack_subscription_identifiers_available_field_id,
374             "subscription identifiers available",
375             true) != AWS_OP_SUCCESS) {
376         return NULL;
377     };
378     if (s_set_jni_bool_field_in_packet(
379             env,
380             native_connack_data->shared_subscriptions_available,
381             connack_data,
382             mqtt5_connack_packet_properties.connack_shared_subscriptions_available_field_id,
383             "shared subscriptions available",
384             true) != AWS_OP_SUCCESS) {
385         return NULL;
386     };
387     if (s_set_jni_uint16_t_field_in_packet(
388             env,
389             native_connack_data->server_keep_alive,
390             connack_data,
391             mqtt5_connack_packet_properties.connack_server_keep_alive_field_id,
392             "server keep alive",
393             true) != AWS_OP_SUCCESS) {
394         return NULL;
395     };
396     if (s_set_jni_string_field_in_packet(
397             env,
398             native_connack_data->response_information,
399             connack_data,
400             mqtt5_connack_packet_properties.connack_response_information_field_id,
401             "response information",
402             true) != AWS_OP_SUCCESS) {
403         return NULL;
404     }
405     if (s_set_jni_string_field_in_packet(
406             env,
407             native_connack_data->server_reference,
408             connack_data,
409             mqtt5_connack_packet_properties.connack_server_reference_field_id,
410             "server reference",
411             true) != AWS_OP_SUCCESS) {
412         return NULL;
413     }
414 
415     if (s_set_user_properties_field(
416             env,
417             native_connack_data->user_property_count,
418             native_connack_data->user_properties,
419             connack_data,
420             mqtt5_connack_packet_properties.connack_user_properties_field_id) != AWS_OP_SUCCESS) {
421         AWS_LOGF_ERROR(
422             AWS_LS_MQTT5_CLIENT, "Error when creating ConnAckPacket from native: could not add user property!");
423         return NULL;
424     }
425 
426     return connack_data;
427 }
428 
s_aws_mqtt5_client_create_jni_disconnect_packet_from_native(JNIEnv * env,const struct aws_mqtt5_packet_disconnect_view * native_disconnect_data)429 jobject s_aws_mqtt5_client_create_jni_disconnect_packet_from_native(
430     JNIEnv *env,
431     const struct aws_mqtt5_packet_disconnect_view *native_disconnect_data) {
432 
433     jobject disconnect_packet_data = (*env)->NewObject(
434         env,
435         mqtt5_disconnect_packet_properties.disconnect_packet_class,
436         mqtt5_disconnect_packet_properties.disconnect_constructor_id);
437 
438     int reason_code_int = (int)native_disconnect_data->reason_code;
439     if (s_set_int_enum_in_packet(
440             env,
441             &reason_code_int,
442             disconnect_packet_data,
443             mqtt5_disconnect_packet_properties.disconnect_native_add_disconnect_reason_code_id,
444             false) != AWS_OP_SUCCESS) {
445         AWS_LOGF_ERROR(
446             AWS_LS_MQTT5_CLIENT, "Error when creating DisconnectPacket from native: Could not set reason code");
447         return NULL;
448     }
449 
450     if (s_set_jni_uint32_t_field_in_packet(
451             env,
452             native_disconnect_data->session_expiry_interval_seconds,
453             disconnect_packet_data,
454             mqtt5_disconnect_packet_properties.disconnect_session_expiry_interval_seconds_field_id,
455             "session expiry interval seconds",
456             true) != AWS_OP_SUCCESS) {
457         return NULL;
458     }
459     if (s_set_jni_string_field_in_packet(
460             env,
461             native_disconnect_data->reason_string,
462             disconnect_packet_data,
463             mqtt5_disconnect_packet_properties.disconnect_reason_string_field_id,
464             "reason string",
465             true) != AWS_OP_SUCCESS) {
466         return NULL;
467     }
468     if (s_set_jni_string_field_in_packet(
469             env,
470             native_disconnect_data->server_reference,
471             disconnect_packet_data,
472             mqtt5_disconnect_packet_properties.disconnect_session_server_reference_field_id,
473             "server reference",
474             true) != AWS_OP_SUCCESS) {
475         return NULL;
476     }
477 
478     if (s_set_user_properties_field(
479             env,
480             native_disconnect_data->user_property_count,
481             native_disconnect_data->user_properties,
482             disconnect_packet_data,
483             mqtt5_disconnect_packet_properties.disconnect_user_properties_field_id) != AWS_OP_SUCCESS) {
484         AWS_LOGF_ERROR(
485             AWS_LS_MQTT5_CLIENT, "Error when creating DisconnectPacket from native: could not add user property!");
486         return NULL;
487     }
488 
489     return disconnect_packet_data;
490 }
491 
s_aws_mqtt5_client_create_jni_negotiated_settings_from_native(JNIEnv * env,const struct aws_mqtt5_negotiated_settings * native_negotiated_settings_data)492 jobject s_aws_mqtt5_client_create_jni_negotiated_settings_from_native(
493     JNIEnv *env,
494     const struct aws_mqtt5_negotiated_settings *native_negotiated_settings_data) {
495 
496     jobject negotiated_settings_data = (*env)->NewObject(
497         env,
498         mqtt5_negotiated_settings_properties.negotiated_settings_class,
499         mqtt5_negotiated_settings_properties.negotiated_settings_constructor_id);
500 
501     (*env)->CallVoidMethod(
502         env,
503         negotiated_settings_data,
504         mqtt5_negotiated_settings_properties.negotiated_settings_native_set_qos_id,
505         (jint)native_negotiated_settings_data->maximum_qos);
506     aws_jni_check_and_clear_exception(env); /* To hide JNI warning */
507 
508     (*env)->SetLongField(
509         env,
510         negotiated_settings_data,
511         mqtt5_negotiated_settings_properties.negotiated_settings_session_expiry_interval_field_id,
512         (jlong)native_negotiated_settings_data->session_expiry_interval);
513     (*env)->SetIntField(
514         env,
515         negotiated_settings_data,
516         mqtt5_negotiated_settings_properties.negotiated_settings_receive_maximum_from_server_field_id,
517         (jint)native_negotiated_settings_data->receive_maximum_from_server);
518     (*env)->SetLongField(
519         env,
520         negotiated_settings_data,
521         mqtt5_negotiated_settings_properties.negotiated_settings_maximum_packet_size_to_server_field_id,
522         (jlong)native_negotiated_settings_data->maximum_packet_size_to_server);
523     (*env)->SetIntField(
524         env,
525         negotiated_settings_data,
526         mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_server_field_id,
527         (jint)native_negotiated_settings_data->topic_alias_maximum_to_server);
528     (*env)->SetIntField(
529         env,
530         negotiated_settings_data,
531         mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_client_field_id,
532         (jint)native_negotiated_settings_data->topic_alias_maximum_to_client);
533     (*env)->SetIntField(
534         env,
535         negotiated_settings_data,
536         mqtt5_negotiated_settings_properties.negotiated_settings_server_keep_alive_field_id,
537         (jint)native_negotiated_settings_data->server_keep_alive);
538     (*env)->SetBooleanField(
539         env,
540         negotiated_settings_data,
541         mqtt5_negotiated_settings_properties.negotiated_settings_retain_available_field_id,
542         (jboolean)native_negotiated_settings_data->retain_available);
543     (*env)->SetBooleanField(
544         env,
545         negotiated_settings_data,
546         mqtt5_negotiated_settings_properties.negotiated_settings_wildcard_subscriptions_available_field_id,
547         (jboolean)native_negotiated_settings_data->wildcard_subscriptions_available);
548     (*env)->SetBooleanField(
549         env,
550         negotiated_settings_data,
551         mqtt5_negotiated_settings_properties.negotiated_settings_subscription_identifiers_available_field_id,
552         (jboolean)native_negotiated_settings_data->subscription_identifiers_available);
553     (*env)->SetBooleanField(
554         env,
555         negotiated_settings_data,
556         mqtt5_negotiated_settings_properties.negotiated_settings_shared_subscriptions_available_field_id,
557         (jboolean)native_negotiated_settings_data->shared_subscriptions_available);
558     (*env)->SetBooleanField(
559         env,
560         negotiated_settings_data,
561         mqtt5_negotiated_settings_properties.negotiated_settings_rejoined_session_field_id,
562         (jboolean)native_negotiated_settings_data->rejoined_session);
563 
564     struct aws_byte_cursor client_id_storage_cursor =
565         aws_byte_cursor_from_buf(&native_negotiated_settings_data->client_id_storage);
566     jstring jni_assigned_client_id = aws_jni_string_from_cursor(env, &client_id_storage_cursor);
567     (*env)->SetObjectField(
568         env,
569         negotiated_settings_data,
570         mqtt5_negotiated_settings_properties.negotiated_settings_assigned_client_id_field_id,
571         jni_assigned_client_id);
572 
573     return negotiated_settings_data;
574 }
575 
s_aws_mqtt5_client_create_jni_publish_packet_from_native(JNIEnv * env,const struct aws_mqtt5_packet_publish_view * publish)576 jobject s_aws_mqtt5_client_create_jni_publish_packet_from_native(
577     JNIEnv *env,
578     const struct aws_mqtt5_packet_publish_view *publish) {
579     jobject publish_packet_data = (*env)->NewObject(
580         env,
581         mqtt5_publish_packet_properties.publish_packet_class,
582         mqtt5_publish_packet_properties.publish_constructor_id);
583 
584     jbyteArray jni_payload = aws_jni_byte_array_from_cursor(env, &publish->payload);
585     (*env)->SetObjectField(
586         env, publish_packet_data, mqtt5_publish_packet_properties.publish_payload_field_id, jni_payload);
587 
588     int publish_qos_int = (int)publish->qos;
589     if (s_set_int_enum_in_packet(
590             env,
591             &publish_qos_int,
592             publish_packet_data,
593             mqtt5_publish_packet_properties.publish_native_set_qos_id,
594             false) != AWS_OP_SUCCESS) {
595         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating PublishPacket from native: Could not set QOS");
596         return NULL;
597     }
598 
599     if (s_set_jni_bool_field_in_packet(
600             env,
601             &publish->retain,
602             publish_packet_data,
603             mqtt5_publish_packet_properties.publish_retain_field_id,
604             "retain",
605             false) != AWS_OP_SUCCESS) {
606         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating PublishPacket from native: Could not set retain");
607         return NULL;
608     }
609 
610     jstring jni_topic = aws_jni_string_from_cursor(env, &publish->topic);
611     (*env)->SetObjectField(env, publish_packet_data, mqtt5_publish_packet_properties.publish_topic_field_id, jni_topic);
612 
613     if (publish->payload_format) {
614         if (s_set_int_enum_in_packet(
615                 env,
616                 (int *)publish->payload_format,
617                 publish_packet_data,
618                 mqtt5_publish_packet_properties.publish_native_set_payload_format_indicator_id,
619                 true) != AWS_OP_SUCCESS) {
620             AWS_LOGF_ERROR(
621                 AWS_LS_MQTT5_CLIENT, "Error when creating PublishPacket from native: Could not set payload format");
622             return NULL;
623         }
624     }
625 
626     if (s_set_jni_uint32_t_field_in_packet(
627             env,
628             publish->message_expiry_interval_seconds,
629             publish_packet_data,
630             mqtt5_publish_packet_properties.publish_message_expiry_interval_seconds_field_id,
631             "message expiry interval seconds",
632             true) != AWS_OP_SUCCESS) {
633         return NULL;
634     }
635 
636     if (s_set_jni_uint16_t_field_in_packet(
637             env,
638             publish->topic_alias,
639             publish_packet_data,
640             mqtt5_publish_packet_properties.publish_topic_alias_field_id,
641             "topic alias",
642             true) != AWS_OP_SUCCESS) {
643         return NULL;
644     }
645 
646     if (s_set_jni_string_field_in_packet(
647             env,
648             publish->response_topic,
649             publish_packet_data,
650             mqtt5_publish_packet_properties.publish_response_topic_field_id,
651             "response topic",
652             true) != AWS_OP_SUCCESS) {
653         return NULL;
654     }
655 
656     if (s_set_jni_byte_array_field_in_packet(
657             env,
658             publish->correlation_data,
659             publish_packet_data,
660             mqtt5_publish_packet_properties.publish_correlation_data_field_id,
661             "correlation data",
662             true) != AWS_OP_SUCCESS) {
663         return NULL;
664     }
665 
666     if (s_set_jni_string_field_in_packet(
667             env,
668             publish->content_type,
669             publish_packet_data,
670             mqtt5_publish_packet_properties.publish_content_type_field_id,
671             "content type",
672             true) != AWS_OP_SUCCESS) {
673         return NULL;
674     }
675 
676     if (publish->subscription_identifier_count && publish->subscription_identifiers) {
677         jobject jni_subscription_identifiers = (*env)->NewObject(
678             env, boxed_array_list_properties.list_class, boxed_array_list_properties.list_constructor_id);
679         (*env)->SetObjectField(
680             env,
681             publish_packet_data,
682             mqtt5_publish_packet_properties.publish_subscription_identifiers_field_id,
683             jni_subscription_identifiers);
684 
685         for (size_t i = 0; i < publish->subscription_identifier_count; ++i) {
686             const uint32_t *identifier = &publish->subscription_identifiers[i];
687             jobject jni_identifier_obj = (*env)->NewObject(
688                 env, boxed_long_properties.long_class, boxed_long_properties.constructor, (jlong)*identifier);
689             jboolean jni_add_result = (*env)->CallBooleanMethod(
690                 env, jni_subscription_identifiers, boxed_list_properties.list_add_id, jni_identifier_obj);
691             if (aws_jni_check_and_clear_exception(env)) {
692                 AWS_LOGF_ERROR(
693                     AWS_LS_MQTT5_CLIENT,
694                     "When creating PublishPacket from native could not add subscription identifier!");
695                 return NULL;
696             }
697             if ((bool)jni_add_result == false) {
698                 AWS_LOGF_ERROR(
699                     AWS_LS_MQTT5_CLIENT,
700                     "When creating PublishPacket from native could not add subscription identifier!");
701                 return NULL;
702             }
703         }
704     }
705 
706     if (s_set_user_properties_field(
707             env,
708             publish->user_property_count,
709             publish->user_properties,
710             publish_packet_data,
711             mqtt5_publish_packet_properties.publish_user_properties_field_id) == AWS_OP_ERR) {
712         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "When creating PublishPacket from native could not add user properties!");
713         return NULL;
714     }
715 
716     return publish_packet_data;
717 }
718 
s_aws_mqtt5_client_create_jni_puback_packet_from_native(JNIEnv * env,struct aws_mqtt5_packet_puback_view * puback_packet)719 jobject s_aws_mqtt5_client_create_jni_puback_packet_from_native(
720     JNIEnv *env,
721     struct aws_mqtt5_packet_puback_view *puback_packet) {
722     /* Make the PubAck packet */
723     jobject puback_packet_data = (*env)->NewObject(
724         env, mqtt5_puback_packet_properties.puback_packet_class, mqtt5_puback_packet_properties.puback_constructor_id);
725 
726     int reason_code_int = (int)puback_packet->reason_code;
727     if (s_set_int_enum_in_packet(
728             env,
729             &reason_code_int,
730             puback_packet_data,
731             mqtt5_puback_packet_properties.puback_native_add_reason_code_id,
732             false) != AWS_OP_SUCCESS) {
733         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating PubAck result from native: Could not set reason code");
734         return NULL;
735     }
736     if (s_set_jni_string_field_in_packet(
737             env,
738             puback_packet->reason_string,
739             puback_packet_data,
740             mqtt5_puback_packet_properties.puback_reason_string_field_id,
741             "reason string",
742             true) != AWS_OP_SUCCESS) {
743         return NULL;
744     }
745     if (s_set_user_properties_field(
746             env,
747             puback_packet->user_property_count,
748             puback_packet->user_properties,
749             puback_packet_data,
750             mqtt5_puback_packet_properties.puback_user_properties_field_id) == AWS_OP_ERR) {
751         AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "When creating PubAckPacket from native could not add user property!");
752         return NULL;
753     }
754     return puback_packet_data;
755 }
756