| /** |
| * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| * SPDX-License-Identifier: Apache-2.0. |
| */ |
| #include <jni.h> |
| |
| #include <mqtt5_packets.h> |
| |
| #include <aws/mqtt/v5/mqtt5_client.h> |
| #include <crt.h> |
| |
| #include <java_class_ids.h> |
| |
| /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */ |
| #if UINTPTR_MAX == 0xffffffff |
| # if defined(_MSC_VER) |
| # pragma warning(push) |
| # pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */ |
| # else |
| # pragma GCC diagnostic push |
| # pragma GCC diagnostic ignored "-Wpointer-to-int-cast" |
| # pragma GCC diagnostic ignored "-Wint-to-pointer-cast" |
| # endif |
| #endif |
| |
| /******************************************************************************* |
| * STRUCT DEFINITIONS |
| ******************************************************************************/ |
| |
| struct aws_mqtt5_packet_connect_view_java_jni { |
| struct aws_mqtt5_packet_connect_view packet; |
| |
| struct aws_byte_buf client_id_buf; |
| struct aws_byte_cursor client_id_cursor; |
| struct aws_byte_buf username_buf; |
| struct aws_byte_cursor username_cursor; |
| struct aws_byte_buf password_buf; |
| struct aws_byte_cursor password_cursor; |
| uint32_t session_expiry_interval_seconds; |
| uint8_t request_response_information; |
| uint8_t request_problem_information; |
| uint16_t receive_maximum; |
| uint16_t topic_alias_maximum; |
| uint32_t maximum_packet_size_bytes; |
| uint32_t will_delay_interval_seconds; |
| uint16_t keep_alive_interval_seconds; |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list jni_user_properties_holder; |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list jni_user_properties_struct_holder; |
| struct aws_mqtt5_packet_publish_view_java_jni *will_publish_packet; |
| }; |
| |
| struct aws_mqtt5_packet_disconnect_view_java_jni { |
| struct aws_mqtt5_packet_disconnect_view packet; |
| |
| struct aws_byte_buf reason_string_buf; |
| struct aws_byte_cursor reason_string_cursor; |
| struct aws_byte_buf server_reference_buf; |
| struct aws_byte_cursor server_reference_cursor; |
| uint32_t session_expiry_interval_seconds; |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list jni_user_properties_holder; |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list jni_user_properties_struct_holder; |
| }; |
| |
| struct aws_mqtt5_packet_publish_view_java_jni { |
| struct aws_mqtt5_packet_publish_view packet; |
| |
| struct aws_byte_buf payload_buf; |
| struct aws_byte_cursor payload_cursor; |
| struct aws_byte_buf topic_buf; |
| struct aws_byte_cursor topic_cursor; |
| enum aws_mqtt5_payload_format_indicator payload_format; |
| uint32_t message_expiry_interval_seconds; |
| uint16_t topic_alias; |
| struct aws_byte_buf response_topic_buf; |
| struct aws_byte_cursor response_topic_cursor; |
| struct aws_byte_buf correlation_data_buf; |
| struct aws_byte_cursor correlation_data_cursor; |
| struct aws_byte_buf content_type_buf; |
| struct aws_byte_cursor content_type_cursor; |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list jni_user_properties_holder; |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list jni_user_properties_struct_holder; |
| }; |
| |
| struct aws_mqtt5_packet_subscribe_view_java_jni { |
| struct aws_mqtt5_packet_subscribe_view packet; |
| |
| /* Contains aws_mqtt5_subscription_view pointers */ |
| struct aws_array_list topic_filters; |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list jni_subscription_topic_filters; |
| uint32_t subscription_identifier; |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list jni_user_properties_holder; |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list jni_user_properties_struct_holder; |
| }; |
| |
| struct aws_mqtt5_packet_unsubscribe_view_java_jni { |
| struct aws_mqtt5_packet_unsubscribe_view packet; |
| |
| /* Contains aws_byte_cursor pointers */ |
| struct aws_array_list topic_filters; |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list jni_topic_filters; |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list jni_user_properties_holder; |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list jni_user_properties_struct_holder; |
| }; |
| |
| struct buffer_and_cursor_array_holder_struct { |
| struct aws_byte_cursor cursor; |
| struct aws_byte_buf buffer; |
| }; |
| |
| /******************************************************************************* |
| * HELPER FUNCTIONS |
| ******************************************************************************/ |
| |
| static int 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, |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list *java_packet_user_properties_holder, |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list *java_packet_user_properties_struct_holder) { |
| |
| if (jni_user_properties_list) { |
| for (size_t i = 0; i < java_packet_native_user_property_count; i++) { |
| jobject jni_property = |
| (*env)->CallObjectMethod(env, jni_user_properties_list, boxed_list_properties.list_get_id, (jint)i); |
| if (!jni_property || aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "Could not populate user properties due to being unable to get property in list from Java"); |
| return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); |
| } |
| |
| jstring jni_property_key = |
| (jstring)(*env)->GetObjectField(env, jni_property, mqtt5_user_property_properties.property_key_id); |
| if (aws_jni_check_and_clear_exception(env) || !jni_property_key) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "Could not populate user properties due to exception when getting property key"); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| jstring jni_property_value = |
| (jstring)(*env)->GetObjectField(env, jni_property, mqtt5_user_property_properties.property_value_id); |
| if (aws_jni_check_and_clear_exception(env) || !jni_property_value) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "Could not populate user properties due to exception when getting property value"); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| |
| if (!jni_property_key) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error reading a user property: Key in user property was NULL!"); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (!jni_property_value) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error reading a user property: Key in user property was NULL!"); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| |
| // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy. |
| // This gets around JNI stuff going out of scope. |
| struct buffer_and_cursor_array_holder_struct holder_property_key; |
| struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_property_key); |
| aws_byte_buf_init_copy_from_cursor(&holder_property_key.buffer, aws_jni_get_allocator(), tmp_cursor); |
| holder_property_key.cursor = aws_byte_cursor_from_buf(&holder_property_key.buffer); |
| aws_jni_byte_cursor_from_jstring_release(env, jni_property_key, tmp_cursor); |
| jni_property_key = NULL; |
| |
| // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy. |
| // This gets around JNI stuff going out of scope. |
| struct buffer_and_cursor_array_holder_struct holder_property_value; |
| tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_property_value); |
| aws_byte_buf_init_copy_from_cursor(&holder_property_value.buffer, aws_jni_get_allocator(), tmp_cursor); |
| holder_property_value.cursor = aws_byte_cursor_from_buf(&holder_property_value.buffer); |
| aws_jni_byte_cursor_from_jstring_release(env, jni_property_value, tmp_cursor); |
| jni_property_value = NULL; |
| |
| aws_array_list_push_back(java_packet_user_properties_holder, (void *)&holder_property_key); |
| aws_array_list_push_back(java_packet_user_properties_holder, (void *)&holder_property_value); |
| |
| struct aws_mqtt5_user_property jni_property_struct = { |
| .name = holder_property_key.cursor, |
| .value = holder_property_value.cursor, |
| }; |
| aws_array_list_push_back(java_packet_user_properties_struct_holder, (void *)&jni_property_struct); |
| } |
| *java_packet_native_user_properties = |
| (struct aws_mqtt5_user_property *)java_packet_user_properties_struct_holder->data; |
| } |
| return AWS_OP_SUCCESS; |
| } |
| |
| static int s_allocate_user_properties_array_holders( |
| struct aws_allocator *allocator, |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list *holder_array, |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list *user_property_array, |
| size_t init_entries) { |
| |
| if (init_entries > 0) { |
| if (aws_array_list_init_dynamic( |
| holder_array, allocator, 2 * init_entries, sizeof(struct buffer_and_cursor_array_holder_struct)) != |
| AWS_OP_SUCCESS || |
| aws_array_list_init_dynamic( |
| user_property_array, allocator, 2 * init_entries, sizeof(struct aws_mqtt5_user_property)) != |
| AWS_OP_SUCCESS) { |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| } |
| return AWS_OP_SUCCESS; |
| } |
| |
| static void s_cleanup_two_aws_array( |
| JNIEnv *env, |
| struct aws_array_list *user_properties_holder, |
| struct aws_array_list *user_properties_struct_holder) { |
| |
| (void)env; |
| if (aws_array_list_is_valid(user_properties_holder)) { |
| /** |
| * Note that this ONLY frees the array holders for the non-struct array. |
| * We want to keep the struct one in memory since it belongs to a packet or similar. |
| * If both need to be freed, then we assume whomever is calling this will handle it. |
| */ |
| for (size_t i = 0; i < aws_array_list_length(user_properties_holder); i++) { |
| struct buffer_and_cursor_array_holder_struct holder; |
| aws_array_list_get_at(user_properties_holder, &holder, i); |
| if (aws_byte_buf_is_valid(&holder.buffer)) { |
| aws_byte_buf_clean_up(&holder.buffer); |
| } |
| } |
| aws_array_list_clean_up(user_properties_holder); |
| } |
| if (aws_array_list_is_valid(user_properties_struct_holder)) { |
| aws_array_list_clean_up(user_properties_struct_holder); |
| } |
| } |
| |
| int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| jobject jlong_obj = (*env)->GetObjectField(env, object, object_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jlong_obj) { |
| jlong jlong_value = (*env)->CallLongMethod(env, jlong_obj, boxed_long_properties.long_value_method_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| int64_t jlong_value_check = (int64_t)jlong_value; |
| if (jlong_value_check < 0) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is less than 0", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); |
| } else if (jlong_value_check > UINT16_MAX) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is more than UINT16_MAX", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); |
| } |
| *result = (uint16_t)jlong_value; |
| |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| |
| if (!optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } |
| |
| if (optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| jobject jlong_obj = (*env)->GetObjectField(env, object, object_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jlong_obj) { |
| jlong jlong_value = (*env)->CallLongMethod(env, jlong_obj, boxed_long_properties.long_value_method_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| int64_t jlong_value_check = (int64_t)jlong_value; |
| if (jlong_value_check < 0) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is less than 0", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); |
| } else if (jlong_value_check > UINT32_MAX) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is more than UINT32_MAX", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); |
| } |
| *result = (uint32_t)jlong_value_check; |
| |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| |
| if (!optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } |
| |
| if (optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| jobject jlong_obj = (*env)->GetObjectField(env, object, object_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jlong_obj) { |
| jlong jlong_value = (*env)->CallLongMethod(env, jlong_obj, boxed_long_properties.long_value_method_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| int64_t jlong_value_check = (int64_t)jlong_value; |
| if (jlong_value_check < 0) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: %s is less than 0", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); |
| } |
| *result = (uint64_t)jlong_value_check; |
| |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| |
| if (!optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } |
| |
| if (optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| jstring jstring_value = (jstring)(*env)->GetObjectField(env, object, object_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jstring_value) { |
| // Get the data, copy it, and then release the JNI stuff |
| struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jstring_value); |
| aws_byte_buf_init_copy_from_cursor(result_buf, aws_jni_get_allocator(), tmp_cursor); |
| *result_cursor = aws_byte_cursor_from_buf(result_buf); |
| aws_jni_byte_cursor_from_jstring_release(env, jstring_value, tmp_cursor); |
| |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| |
| if (!is_optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } |
| if (is_optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| jbyteArray jbyte_array_value = (jbyteArray)(*env)->GetObjectField(env, object, object_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jbyte_array_value) { |
| // Get the data, copy it, and then release the JNI stuff |
| struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jbyteArray_acquire(env, jbyte_array_value); |
| aws_byte_buf_init_copy_from_cursor(result_buf, aws_jni_get_allocator(), tmp_cursor); |
| *result_cursor = aws_byte_cursor_from_buf(result_buf); |
| aws_jni_byte_cursor_from_jbyteArray_release(env, jbyte_array_value, tmp_cursor); |
| |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| |
| if (!optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } |
| if (optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| jobject jboolean_obj = (*env)->GetObjectField(env, object, object_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jboolean_obj) { |
| jboolean jboolean_value = |
| (*env)->CallBooleanMethod(env, jboolean_obj, boxed_boolean_properties.boolean_get_value_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "%s create_from_java: Error getting native value from %s", |
| object_name, |
| field_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| *result_boolean_int = (uint8_t)jboolean_value; |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| if (!optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } |
| |
| if (optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| if (enum_value_destination == NULL) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "%s create_from_java: Error getting %s due to null destination", |
| object_name, |
| enum_name); |
| return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); |
| } |
| |
| jobject jni_retain_handling_type = (*env)->CallObjectMethod(env, object, object_enum_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting %s", object_name, enum_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jni_retain_handling_type) { |
| jint enum_value = (*env)->CallIntMethod(env, jni_retain_handling_type, enum_value_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting native value from %s", object_name, enum_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (enum_value < 0) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "%s create_from_java: Native value from %s is less than 0", |
| object_name, |
| enum_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } else if ((int32_t)enum_value > UINT16_MAX) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "%s create_from_java: Native value from %s is more than UINT16_MAX", |
| object_name, |
| enum_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| *enum_value_destination = (int32_t)enum_value; |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| if (!optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } |
| if (optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| static int s_get_user_properties_from_packet_optional( |
| JNIEnv *env, |
| jobject packet, |
| jfieldID packet_field, |
| char *packet_name, |
| size_t *packet_user_property_count, |
| /* Contains buffer_and_cursor_array_holder_struct pointers */ |
| struct aws_array_list *jni_user_properties_holder, |
| /* Contains aws_mqtt5_user_property pointers */ |
| struct aws_array_list *jni_user_properties_struct_holder, |
| const struct aws_mqtt5_user_property **packet_properties) { |
| |
| struct aws_allocator *allocator = aws_jni_get_allocator(); |
| |
| jobject jni_list = (*env)->GetObjectField(env, packet, packet_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting user properties list", packet_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| if (jni_list) { |
| jint jni_user_properties_size = (*env)->CallIntMethod(env, jni_list, boxed_list_properties.list_size_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting user properties list size", packet_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| *packet_user_property_count = (size_t)jni_user_properties_size; |
| if (AWS_OP_SUCCESS != s_allocate_user_properties_array_holders( |
| allocator, |
| jni_user_properties_holder, |
| jni_user_properties_struct_holder, |
| *packet_user_property_count)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "%s create_from_java: Could not create user properties array", packet_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| int populate_result = s_populate_user_properties( |
| env, |
| jni_list, |
| *packet_user_property_count, |
| packet_properties, |
| jni_user_properties_holder, |
| jni_user_properties_struct_holder); |
| if (populate_result != AWS_OP_SUCCESS) { |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| } |
| return AWS_OP_SUCCESS; |
| } |
| |
| static int 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) { |
| |
| if (was_value_set != NULL) { |
| *was_value_set = false; |
| } |
| |
| jobject jni_qos = (*env)->CallObjectMethod(env, packet, packet_field); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting QoS", packet_name); |
| return AWS_OP_ERR; |
| } |
| if (jni_qos) { |
| jint jni_qos_value = (*env)->CallIntMethod(env, jni_qos, mqtt5_packet_qos_properties.qos_get_value_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "%s create_from_java: Error getting native value from QoS", packet_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| *packet_qos = (enum aws_mqtt5_qos)jni_qos_value; |
| if (was_value_set != NULL) { |
| *was_value_set = true; |
| } |
| if (!optional) { |
| return AWS_OP_SUCCESS; |
| } |
| } else { |
| if (!optional) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "%s create_from_java: QoS not found", packet_name); |
| return aws_raise_error(AWS_ERROR_INVALID_STATE); |
| } |
| } |
| if (optional) { |
| return AWS_OP_SUCCESS; |
| } else { |
| return AWS_OP_ERR; |
| } |
| } |
| |
| static char s_connect_packet_string[] = "ConnectPacket"; |
| static char s_disconnect_packet_string[] = "DisconnectPacket"; |
| static char s_publish_packet_string[] = "PublishPacket"; |
| static char s_subscribe_packet_string[] = "SubscribePacket"; |
| static char s_unsubscribe_packet_string[] = "UnsubscribePacket"; |
| |
| /******************************************************************************* |
| * CONNECT PACKET FUNCTIONS |
| ******************************************************************************/ |
| |
| void aws_mqtt5_packet_connect_view_java_destroy( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| struct aws_mqtt5_packet_connect_view_java_jni *java_packet) { |
| if (!java_packet) { |
| return; |
| } |
| AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying ConnectPacket", (void *)java_packet); |
| |
| if (aws_byte_buf_is_valid(&java_packet->client_id_buf)) { |
| aws_byte_buf_clean_up(&java_packet->client_id_buf); |
| } |
| if (aws_byte_buf_is_valid(&java_packet->username_buf)) { |
| aws_byte_buf_clean_up(&java_packet->username_buf); |
| } |
| if (aws_byte_buf_is_valid(&java_packet->password_buf)) { |
| aws_byte_buf_clean_up(&java_packet->password_buf); |
| } |
| if (java_packet->will_publish_packet) { |
| aws_mqtt5_packet_publish_view_java_destroy(env, allocator, java_packet->will_publish_packet); |
| } |
| |
| s_cleanup_two_aws_array( |
| env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder); |
| aws_mem_release(allocator, java_packet); |
| } |
| |
| /** |
| * Creates a JNI connack packet from the given Java connack packet and returns it. It creates a new packet but it does |
| * NOT free it. You will need to call aws_mqtt5_packet_connect_view_java_destroy when you are done with it. |
| */ |
| struct aws_mqtt5_packet_connect_view_java_jni *aws_mqtt5_packet_connect_view_create_from_java( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| jobject java_connect_packet) { |
| struct aws_mqtt5_packet_connect_view_java_jni *java_packet = |
| aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_connect_view_java_jni)); |
| if (java_packet == NULL) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "ConnectPacket create_from_java: Creating new ConnectPacket failed"); |
| return NULL; |
| } |
| |
| /* Needed to track if optionals are set or not */ |
| bool was_value_set = false; |
| |
| if (aws_get_uint16_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_keep_alive_interval_seconds_field_id, |
| s_connect_packet_string, |
| "keep alive interval seconds", |
| &java_packet->keep_alive_interval_seconds, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.keep_alive_interval_seconds = java_packet->keep_alive_interval_seconds; |
| } |
| |
| if (aws_get_string_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_client_id_field_id, |
| s_connect_packet_string, |
| "client ID", |
| &java_packet->client_id_buf, |
| &java_packet->client_id_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.client_id = java_packet->client_id_cursor; |
| } |
| |
| if (aws_get_string_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_username_field_id, |
| s_connect_packet_string, |
| "username", |
| &java_packet->username_buf, |
| &java_packet->username_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.username = &java_packet->username_cursor; |
| } |
| |
| if (aws_get_byte_array_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_password_field_id, |
| s_connect_packet_string, |
| "password", |
| &java_packet->password_buf, |
| &java_packet->password_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.password = &java_packet->password_cursor; |
| } |
| |
| if (aws_get_uint32_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_session_expiry_interval_seconds_field_id, |
| s_connect_packet_string, |
| "session expiry interval seconds", |
| &java_packet->session_expiry_interval_seconds, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.session_expiry_interval_seconds = &java_packet->session_expiry_interval_seconds; |
| } |
| |
| if (aws_get_boolean_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_request_response_information_field_id, |
| s_connect_packet_string, |
| "request response information", |
| &java_packet->request_response_information, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.request_response_information = &java_packet->request_response_information; |
| } |
| |
| if (aws_get_boolean_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_request_problem_information_field_id, |
| s_connect_packet_string, |
| "request problem information", |
| &java_packet->request_problem_information, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.request_problem_information = &java_packet->request_problem_information; |
| } |
| |
| if (aws_get_uint16_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_receive_maximum_field_id, |
| s_connect_packet_string, |
| "receive maximum", |
| &java_packet->receive_maximum, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.receive_maximum = &java_packet->receive_maximum; |
| } |
| |
| if (aws_get_uint32_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_maximum_packet_size_bytes_field_id, |
| s_connect_packet_string, |
| "maximum packet size", |
| &java_packet->maximum_packet_size_bytes, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.maximum_packet_size_bytes = &java_packet->maximum_packet_size_bytes; |
| } |
| |
| if (aws_get_uint32_from_jobject( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_will_delay_interval_seconds_field_id, |
| s_connect_packet_string, |
| "will delay interval", |
| &java_packet->will_delay_interval_seconds, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.will_delay_interval_seconds = &java_packet->will_delay_interval_seconds; |
| } |
| |
| jobject jni_will_packet = |
| (*env)->GetObjectField(env, java_connect_packet, mqtt5_connect_packet_properties.connect_will_field_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "ConnectPacket create_from_java: Error getting will packet"); |
| goto on_error; |
| } |
| if (jni_will_packet) { |
| java_packet->will_publish_packet = |
| aws_mqtt5_packet_publish_view_create_from_java(env, allocator, jni_will_packet); |
| if (java_packet->will_publish_packet == NULL) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "ConnectPacket create_from_java: Error getting will packet"); |
| goto on_error; |
| } |
| java_packet->packet.will = &java_packet->will_publish_packet->packet; |
| } |
| |
| if (s_get_user_properties_from_packet_optional( |
| env, |
| java_connect_packet, |
| mqtt5_connect_packet_properties.connect_user_properties_field_id, |
| s_connect_packet_string, |
| &java_packet->packet.user_property_count, |
| &java_packet->jni_user_properties_holder, |
| &java_packet->jni_user_properties_struct_holder, |
| &java_packet->packet.user_properties) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| |
| return java_packet; |
| |
| on_error: |
| |
| /* Clean up */ |
| aws_mqtt5_packet_connect_view_java_destroy(env, allocator, java_packet); |
| return NULL; |
| } |
| |
| struct aws_mqtt5_packet_connect_view *aws_mqtt5_packet_connect_view_get_packet( |
| struct aws_mqtt5_packet_connect_view_java_jni *java_packet) { |
| if (java_packet) { |
| return &java_packet->packet; |
| } else { |
| return NULL; |
| } |
| } |
| |
| /******************************************************************************* |
| * PACKET DISCONNECT FUNCTIONS |
| ******************************************************************************/ |
| |
| void aws_mqtt5_packet_disconnect_view_java_destroy( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| struct aws_mqtt5_packet_disconnect_view_java_jni *java_packet) { |
| if (!java_packet) { |
| return; |
| } |
| AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying DisconnectPacket", (void *)java_packet); |
| |
| if (aws_byte_buf_is_valid(&java_packet->reason_string_buf)) { |
| aws_byte_buf_clean_up(&java_packet->reason_string_buf); |
| } |
| if (aws_byte_buf_is_valid(&java_packet->server_reference_buf)) { |
| aws_byte_buf_clean_up(&java_packet->server_reference_buf); |
| } |
| |
| s_cleanup_two_aws_array( |
| env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder); |
| aws_mem_release(allocator, java_packet); |
| } |
| |
| struct aws_mqtt5_packet_disconnect_view_java_jni *aws_mqtt5_packet_disconnect_view_create_from_java( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| jobject java_disconnect_packet) { |
| |
| struct aws_mqtt5_packet_disconnect_view_java_jni *java_packet = |
| aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_disconnect_view_java_jni)); |
| if (java_packet == NULL) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "DisconnectPacket create_from_java: Creating new DisconnectPacket failed"); |
| return NULL; |
| } |
| |
| /* Needed to track if optionals are set or not */ |
| bool was_value_set = false; |
| |
| uint32_t reason_code_enum; |
| if (aws_get_enum_from_jobject( |
| env, |
| java_disconnect_packet, |
| mqtt5_disconnect_packet_properties.disconnect_get_reason_code_id, |
| s_disconnect_packet_string, |
| "reason code", |
| mqtt5_disconnect_reason_code_properties.code_get_value_id, |
| &reason_code_enum, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.reason_code = (enum aws_mqtt5_disconnect_reason_code)reason_code_enum; |
| } |
| |
| if (aws_get_uint32_from_jobject( |
| env, |
| java_disconnect_packet, |
| mqtt5_disconnect_packet_properties.disconnect_session_expiry_interval_seconds_field_id, |
| s_disconnect_packet_string, |
| "session expiry interval seconds", |
| &java_packet->session_expiry_interval_seconds, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.session_expiry_interval_seconds = &java_packet->session_expiry_interval_seconds; |
| } |
| |
| if (aws_get_string_from_jobject( |
| env, |
| java_disconnect_packet, |
| mqtt5_disconnect_packet_properties.disconnect_reason_string_field_id, |
| s_disconnect_packet_string, |
| "reason string", |
| &java_packet->reason_string_buf, |
| &java_packet->reason_string_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.reason_string = &java_packet->reason_string_cursor; |
| } |
| |
| if (aws_get_string_from_jobject( |
| env, |
| java_disconnect_packet, |
| mqtt5_disconnect_packet_properties.disconnect_session_server_reference_field_id, |
| s_disconnect_packet_string, |
| "server reference", |
| &java_packet->server_reference_buf, |
| &java_packet->server_reference_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.server_reference = &java_packet->server_reference_cursor; |
| } |
| |
| if (s_get_user_properties_from_packet_optional( |
| env, |
| java_disconnect_packet, |
| mqtt5_disconnect_packet_properties.disconnect_user_properties_field_id, |
| s_disconnect_packet_string, |
| &java_packet->packet.user_property_count, |
| &java_packet->jni_user_properties_holder, |
| &java_packet->jni_user_properties_struct_holder, |
| &java_packet->packet.user_properties) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| |
| return java_packet; |
| |
| on_error: |
| |
| /* Clean up */ |
| aws_mqtt5_packet_disconnect_view_java_destroy(env, allocator, java_packet); |
| return NULL; |
| } |
| |
| struct aws_mqtt5_packet_disconnect_view *aws_mqtt5_packet_disconnect_view_get_packet( |
| struct aws_mqtt5_packet_disconnect_view_java_jni *java_packet) { |
| if (java_packet) { |
| return &java_packet->packet; |
| } else { |
| return NULL; |
| } |
| } |
| |
| /******************************************************************************* |
| * PUBLISH PACKET FUNCTIONS |
| ******************************************************************************/ |
| |
| void aws_mqtt5_packet_publish_view_java_destroy( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| struct aws_mqtt5_packet_publish_view_java_jni *java_packet) { |
| if (!java_packet) { |
| return; |
| } |
| AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying PublishPacket", (void *)java_packet); |
| |
| if (aws_byte_buf_is_valid(&java_packet->payload_buf)) { |
| aws_byte_buf_clean_up(&java_packet->payload_buf); |
| } |
| if (aws_byte_buf_is_valid(&java_packet->topic_buf)) { |
| aws_byte_buf_clean_up(&java_packet->topic_buf); |
| } |
| if (aws_byte_buf_is_valid(&java_packet->response_topic_buf)) { |
| aws_byte_buf_clean_up(&java_packet->response_topic_buf); |
| } |
| if (aws_byte_buf_is_valid(&java_packet->correlation_data_buf)) { |
| aws_byte_buf_clean_up(&java_packet->correlation_data_buf); |
| } |
| if (aws_byte_buf_is_valid(&java_packet->content_type_buf)) { |
| aws_byte_buf_clean_up(&java_packet->content_type_buf); |
| } |
| |
| s_cleanup_two_aws_array( |
| env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder); |
| aws_mem_release(allocator, java_packet); |
| } |
| |
| struct aws_mqtt5_packet_publish_view_java_jni *aws_mqtt5_packet_publish_view_create_from_java( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| jobject java_publish_packet) { |
| |
| struct aws_mqtt5_packet_publish_view_java_jni *java_packet = |
| aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_publish_view_java_jni)); |
| if (java_packet == NULL) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "PublishPacket create_from_java: Creating new PublishPacket failed"); |
| return NULL; |
| } |
| |
| /* Needed to track if optionals are set or not */ |
| bool was_value_set = false; |
| |
| if (aws_get_byte_array_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_payload_field_id, |
| s_publish_packet_string, |
| "payload", |
| &java_packet->correlation_data_buf, |
| &java_packet->payload_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.payload = java_packet->payload_cursor; |
| } |
| |
| if (s_get_qos_from_packet( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_get_qos_id, |
| s_publish_packet_string, |
| &java_packet->packet.qos, |
| false, |
| NULL) == AWS_OP_ERR) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "PublishPacket create_from_java: QOS not found"); |
| goto on_error; |
| } |
| |
| uint8_t packet_retain; |
| if (aws_get_boolean_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_retain_field_id, |
| s_publish_packet_string, |
| "retain", |
| &packet_retain, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.retain = (bool)packet_retain; |
| } |
| |
| if (aws_get_string_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_topic_field_id, |
| s_publish_packet_string, |
| "topic", |
| &java_packet->topic_buf, |
| &java_packet->topic_cursor, |
| false, |
| NULL) == AWS_OP_ERR) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "PublishPacket create_from_java: No topic found"); |
| goto on_error; |
| } |
| java_packet->packet.topic = java_packet->topic_cursor; |
| |
| uint32_t format_enum; |
| if (aws_get_enum_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_get_payload_format_id, |
| s_publish_packet_string, |
| "payload format", |
| mqtt5_payload_format_indicator_properties.format_get_value_id, |
| &format_enum, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->payload_format = (enum aws_mqtt5_payload_format_indicator)format_enum; |
| java_packet->packet.payload_format = &java_packet->payload_format; |
| } |
| |
| if (aws_get_uint32_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_message_expiry_interval_seconds_field_id, |
| s_publish_packet_string, |
| "message expiry interval seconds", |
| &java_packet->message_expiry_interval_seconds, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.message_expiry_interval_seconds = &java_packet->message_expiry_interval_seconds; |
| } |
| |
| if (aws_get_uint16_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_topic_alias_field_id, |
| s_publish_packet_string, |
| "topic alias", |
| &java_packet->topic_alias, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.topic_alias = &java_packet->topic_alias; |
| } |
| |
| if (aws_get_string_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_response_topic_field_id, |
| s_publish_packet_string, |
| "response topic", |
| &java_packet->response_topic_buf, |
| &java_packet->response_topic_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.response_topic = &java_packet->response_topic_cursor; |
| } |
| |
| if (aws_get_byte_array_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_correlation_data_field_id, |
| s_publish_packet_string, |
| "correlation data", |
| &java_packet->correlation_data_buf, |
| &java_packet->correlation_data_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.correlation_data = &java_packet->correlation_data_cursor; |
| } |
| |
| if (aws_get_string_from_jobject( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_content_type_field_id, |
| s_publish_packet_string, |
| "content type", |
| &java_packet->content_type_buf, |
| &java_packet->content_type_cursor, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.content_type = &java_packet->content_type_cursor; |
| } |
| |
| if (s_get_user_properties_from_packet_optional( |
| env, |
| java_publish_packet, |
| mqtt5_publish_packet_properties.publish_user_properties_field_id, |
| s_publish_packet_string, |
| &java_packet->packet.user_property_count, |
| &java_packet->jni_user_properties_holder, |
| &java_packet->jni_user_properties_struct_holder, |
| &java_packet->packet.user_properties) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| |
| return java_packet; |
| |
| on_error: |
| |
| /* Clean up */ |
| aws_mqtt5_packet_publish_view_java_destroy(env, allocator, java_packet); |
| return NULL; |
| } |
| |
| struct aws_mqtt5_packet_publish_view *aws_mqtt5_packet_publish_view_get_packet( |
| struct aws_mqtt5_packet_publish_view_java_jni *java_packet) { |
| if (java_packet) { |
| return &java_packet->packet; |
| } else { |
| return NULL; |
| } |
| } |
| |
| /******************************************************************************* |
| * SUBSCRIBE PACKET FUNCTIONS |
| ******************************************************************************/ |
| |
| void aws_mqtt5_packet_subscribe_view_java_destroy( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| struct aws_mqtt5_packet_subscribe_view_java_jni *java_packet) { |
| if (!java_packet) { |
| return; |
| } |
| AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying SubscribePacket", (void *)java_packet); |
| |
| s_cleanup_two_aws_array( |
| env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder); |
| s_cleanup_two_aws_array(env, &java_packet->jni_subscription_topic_filters, &java_packet->topic_filters); |
| aws_mem_release(allocator, java_packet); |
| } |
| |
| struct aws_mqtt5_packet_subscribe_view_java_jni *aws_mqtt5_packet_subscribe_view_create_from_java( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| jobject java_subscribe_packet) { |
| |
| jobject jni_subscriptions = (*env)->GetObjectField( |
| env, java_subscribe_packet, mqtt5_subscribe_packet_properties.subscribe_subscriptions_field_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| return NULL; |
| } |
| if (!jni_subscriptions) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "SubscribePacket create_from_java: Creating new SubscribePacket failed due to no subscriptions!"); |
| return NULL; |
| } |
| jint jni_subscriptions_size = (*env)->CallIntMethod(env, jni_subscriptions, boxed_list_properties.list_size_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| return NULL; |
| } |
| size_t subscriptions_filter_size = (size_t)jni_subscriptions_size; |
| |
| if (subscriptions_filter_size <= 0) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: subscriptions count is 0"); |
| return NULL; |
| } |
| |
| struct aws_mqtt5_packet_subscribe_view_java_jni *java_packet = |
| aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_subscribe_view_java_jni)); |
| if (java_packet == NULL) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Creating new SubscribePacket failed"); |
| return NULL; |
| } |
| int array_init = aws_array_list_init_dynamic( |
| &java_packet->topic_filters, allocator, subscriptions_filter_size, sizeof(struct aws_mqtt5_subscription_view)); |
| if (array_init != AWS_OP_SUCCESS) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Creating new SubscribePacket failed"); |
| goto on_error; |
| } |
| int jni_array_init = aws_array_list_init_dynamic( |
| &java_packet->jni_subscription_topic_filters, |
| allocator, |
| subscriptions_filter_size, |
| sizeof(struct buffer_and_cursor_array_holder_struct)); |
| if (jni_array_init != AWS_OP_SUCCESS) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Creating new SubscribePacket failed"); |
| goto on_error; |
| } |
| |
| /* Needed to track if optionals are set or not */ |
| bool was_value_set = false; |
| |
| if (aws_get_uint32_from_jobject( |
| env, |
| java_subscribe_packet, |
| mqtt5_subscribe_packet_properties.subscribe_subscription_identifier_field_id, |
| s_subscribe_packet_string, |
| "subscription identifier", |
| &java_packet->subscription_identifier, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| java_packet->packet.subscription_identifier = &java_packet->subscription_identifier; |
| } |
| |
| java_packet->packet.subscription_count = subscriptions_filter_size; |
| for (size_t i = 0; i < subscriptions_filter_size; i++) { |
| /* Populate */ |
| struct aws_mqtt5_subscription_view subscription_view; |
| struct buffer_and_cursor_array_holder_struct holder; |
| |
| jobject jni_packet_subscribe_subscription = |
| (*env)->CallObjectMethod(env, jni_subscriptions, boxed_list_properties.list_get_id, (jint)i); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Error getting topic filters"); |
| goto on_error; |
| } |
| |
| jstring jni_topic_filter = (jstring)(*env)->CallObjectMethod( |
| env, jni_packet_subscribe_subscription, mqtt5_subscription_properties.subscribe_get_topic_filter_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: Error getting subscription topic filter"); |
| goto on_error; |
| } |
| if (jni_topic_filter) { |
| // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy. |
| // This gets around JNI stuff going out of scope. |
| struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_topic_filter); |
| aws_byte_buf_init_copy_from_cursor(&holder.buffer, aws_jni_get_allocator(), tmp_cursor); |
| holder.cursor = aws_byte_cursor_from_buf(&holder.buffer); |
| aws_jni_byte_cursor_from_jstring_release(env, jni_topic_filter, tmp_cursor); |
| subscription_view.topic_filter = holder.cursor; |
| jni_topic_filter = NULL; |
| } else { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: subscription topic filter is required"); |
| goto on_error; |
| } |
| |
| if (s_get_qos_from_packet( |
| env, |
| jni_packet_subscribe_subscription, |
| mqtt5_subscription_properties.subscribe_get_qos_id, |
| s_subscribe_packet_string, |
| &subscription_view.qos, |
| false, |
| NULL) == AWS_OP_ERR) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "SubscribePacket create_from_java: subscription QoS is required"); |
| goto on_error; |
| } |
| |
| uint8_t subscription_no_local; |
| if (aws_get_boolean_from_jobject( |
| env, |
| jni_packet_subscribe_subscription, |
| mqtt5_subscription_properties.subscribe_no_local_field_id, |
| s_subscribe_packet_string, |
| "no local", |
| &subscription_no_local, |
| true, |
| &was_value_set) != AWS_OP_SUCCESS) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| subscription_view.no_local = (bool)subscription_no_local; |
| } |
| |
| uint8_t retain_as_published; |
| if (aws_get_boolean_from_jobject( |
| env, |
| jni_packet_subscribe_subscription, |
| mqtt5_subscription_properties.subscribe_retain_as_published_field_id, |
| s_subscribe_packet_string, |
| "retain as published", |
| &retain_as_published, |
| true, |
| &was_value_set) != AWS_OP_SUCCESS) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| subscription_view.retain_as_published = (bool)retain_as_published; |
| } |
| |
| uint32_t retain_enum; |
| if (aws_get_enum_from_jobject( |
| env, |
| jni_packet_subscribe_subscription, |
| mqtt5_subscription_properties.subscribe_get_retain_handling_type_id, |
| s_subscribe_packet_string, |
| "subscription retain handling type", |
| mqtt5_retain_handling_type_properties.retain_get_value_id, |
| &retain_enum, |
| true, |
| &was_value_set) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| if (was_value_set) { |
| subscription_view.retain_handling_type = (enum aws_mqtt5_retain_handling_type)retain_enum; |
| } |
| |
| aws_array_list_push_back(&java_packet->topic_filters, (void *)&subscription_view); |
| aws_array_list_push_back(&java_packet->jni_subscription_topic_filters, (void *)&holder); |
| } |
| java_packet->packet.subscriptions = (struct aws_mqtt5_subscription_view *)java_packet->topic_filters.data; |
| |
| if (s_get_user_properties_from_packet_optional( |
| env, |
| java_subscribe_packet, |
| mqtt5_subscribe_packet_properties.subscribe_user_properties_field_id, |
| s_subscribe_packet_string, |
| &java_packet->packet.user_property_count, |
| &java_packet->jni_user_properties_holder, |
| &java_packet->jni_user_properties_struct_holder, |
| &java_packet->packet.user_properties) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| |
| return java_packet; |
| |
| on_error: |
| |
| /* Clean up */ |
| aws_mqtt5_packet_subscribe_view_java_destroy(env, allocator, java_packet); |
| return NULL; |
| } |
| |
| struct aws_mqtt5_packet_subscribe_view *aws_mqtt5_packet_subscribe_view_get_packet( |
| struct aws_mqtt5_packet_subscribe_view_java_jni *java_packet) { |
| if (java_packet) { |
| return &java_packet->packet; |
| } else { |
| return NULL; |
| } |
| } |
| |
| /******************************************************************************* |
| * UNSUBSCRIBE PACKET FUNCTIONS |
| ******************************************************************************/ |
| |
| void aws_mqtt5_packet_unsubscribe_view_java_destroy( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| struct aws_mqtt5_packet_unsubscribe_view_java_jni *java_packet) { |
| if (!java_packet) { |
| return; |
| } |
| AWS_LOGF_DEBUG(AWS_LS_MQTT5_CLIENT, "id=%p: Destroying UnsubscribePacket", (void *)java_packet); |
| |
| s_cleanup_two_aws_array( |
| env, &java_packet->jni_user_properties_holder, &java_packet->jni_user_properties_struct_holder); |
| s_cleanup_two_aws_array(env, &java_packet->jni_topic_filters, &java_packet->topic_filters); |
| aws_mem_release(allocator, java_packet); |
| } |
| |
| struct aws_mqtt5_packet_unsubscribe_view_java_jni *aws_mqtt5_packet_unsubscribe_view_create_from_java( |
| JNIEnv *env, |
| struct aws_allocator *allocator, |
| jobject java_unsubscribe_packet) { |
| |
| jobject jni_topic_filters = (*env)->GetObjectField( |
| env, java_unsubscribe_packet, mqtt5_unsubscribe_packet_properties.unsubscribe_subscriptions_field_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| return NULL; |
| } |
| if (!jni_topic_filters) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed due to no topic filters"); |
| return NULL; |
| } |
| |
| size_t topic_filter_size = 0; |
| jint jni_topic_filter_size = (*env)->CallIntMethod(env, jni_topic_filters, boxed_list_properties.list_size_id); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, |
| "UnsubscribePacket create_from_java: Created new UnsubscribePacket failed due to no topic filters"); |
| return NULL; |
| } |
| int32_t jni_topic_filter_size_check = (int32_t)jni_topic_filter_size; |
| if (jni_topic_filter_size_check < 0) { |
| AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: No topic filters found"); |
| return NULL; |
| } else { |
| topic_filter_size = (size_t)jni_topic_filter_size; |
| } |
| |
| struct aws_mqtt5_packet_unsubscribe_view_java_jni *java_packet = |
| aws_mem_calloc(allocator, 1, sizeof(struct aws_mqtt5_packet_unsubscribe_view_java_jni)); |
| if (java_packet == NULL) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed"); |
| return NULL; |
| } |
| int array_init = aws_array_list_init_dynamic( |
| &java_packet->topic_filters, allocator, topic_filter_size, sizeof(struct aws_byte_cursor)); |
| if (array_init != AWS_OP_SUCCESS) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed"); |
| goto on_error; |
| } |
| int jni_array_init = aws_array_list_init_dynamic( |
| &java_packet->jni_topic_filters, |
| allocator, |
| topic_filter_size, |
| sizeof(struct buffer_and_cursor_array_holder_struct)); |
| if (jni_array_init != AWS_OP_SUCCESS) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Creating new UnsubscribePacket failed"); |
| goto on_error; |
| } |
| |
| java_packet->packet.topic_filter_count = topic_filter_size; |
| |
| for (size_t i = 0; i < topic_filter_size; i++) { |
| /* Populate */ |
| struct buffer_and_cursor_array_holder_struct holder; |
| |
| jstring jni_topic_filter = |
| (jstring)(*env)->CallObjectMethod(env, jni_topic_filters, boxed_list_properties.list_get_id, (jint)i); |
| if (aws_jni_check_and_clear_exception(env)) { |
| AWS_LOGF_ERROR( |
| AWS_LS_MQTT5_CLIENT, "UnsubscribePacket create_from_java: Error getting subscription topic filter"); |
| goto on_error; |
| } |
| if (jni_topic_filter) { |
| // Get a temporary cursor from JNI, copy it, and then destroy the JNI version, leaving the byte_buffer copy. |
| // This gets around JNI stuff going out of scope. |
| struct aws_byte_cursor tmp_cursor = aws_jni_byte_cursor_from_jstring_acquire(env, jni_topic_filter); |
| aws_byte_buf_init_copy_from_cursor(&holder.buffer, aws_jni_get_allocator(), tmp_cursor); |
| holder.cursor = aws_byte_cursor_from_buf(&holder.buffer); |
| aws_jni_byte_cursor_from_jstring_release(env, jni_topic_filter, tmp_cursor); |
| jni_topic_filter = NULL; |
| } |
| aws_array_list_push_back(&java_packet->topic_filters, (void *)&holder.cursor); |
| aws_array_list_push_back(&java_packet->jni_topic_filters, (void *)&holder); |
| } |
| java_packet->packet.topic_filters = (struct aws_byte_cursor *)java_packet->topic_filters.data; |
| |
| if (s_get_user_properties_from_packet_optional( |
| env, |
| java_unsubscribe_packet, |
| mqtt5_unsubscribe_packet_properties.unsubscribe_user_properties_field_id, |
| s_unsubscribe_packet_string, |
| &java_packet->packet.user_property_count, |
| &java_packet->jni_user_properties_holder, |
| &java_packet->jni_user_properties_struct_holder, |
| &java_packet->packet.user_properties) == AWS_OP_ERR) { |
| goto on_error; |
| } |
| |
| return java_packet; |
| |
| on_error: |
| |
| /* Clean up */ |
| aws_mqtt5_packet_unsubscribe_view_java_destroy(env, allocator, java_packet); |
| return NULL; |
| } |
| |
| struct aws_mqtt5_packet_unsubscribe_view *aws_mqtt5_packet_unsubscribe_view_get_packet( |
| struct aws_mqtt5_packet_unsubscribe_view_java_jni *java_packet) { |
| if (java_packet) { |
| return &java_packet->packet; |
| } else { |
| return NULL; |
| } |
| } |
| |
| #if UINTPTR_MAX == 0xffffffff |
| # if defined(_MSC_VER) |
| # pragma warning(pop) |
| # else |
| # pragma GCC diagnostic pop |
| # endif |
| #endif |