blob: ee00262db50fa6eb29d3b91b1fbbba30bfc80964 [file] [edit]
/**
* 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