/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include #include #include #include #include /* 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 int s_set_jni_uint32_t_field_in_packet( JNIEnv *env, const uint32_t *native_integer, jobject packet, jfieldID field_id, char *field_name, bool optional) { if (native_integer != NULL) { jobject jni_long = (*env)->NewObject( env, boxed_long_properties.long_class, boxed_long_properties.constructor, (jlong)*native_integer); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not create uint32 field %s", field_name); return AWS_OP_ERR; } (*env)->SetObjectField(env, packet, field_id, jni_long); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set uint32 field %s", field_name); return AWS_OP_ERR; } if (!optional) { return AWS_OP_SUCCESS; } } if (optional) { return AWS_OP_SUCCESS; } else { return AWS_OP_ERR; } } int s_set_jni_uint16_t_field_in_packet( JNIEnv *env, const uint16_t *native_integer, jobject packet, jfieldID field_id, char *field_name, bool optional) { if (native_integer != NULL) { jobject jni_int = (*env)->NewObject( env, boxed_integer_properties.integer_class, boxed_integer_properties.integer_constructor_id, (jint)*native_integer); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not create uint16 field %s", field_name); return AWS_OP_ERR; } (*env)->SetObjectField(env, packet, field_id, jni_int); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set uint16 field %s", field_name); return AWS_OP_ERR; } if (!optional) { return AWS_OP_SUCCESS; } } if (optional) { return AWS_OP_SUCCESS; } else { return AWS_OP_ERR; } } int s_set_jni_bool_field_in_packet( JNIEnv *env, const bool *native_boolean, jobject packet, jfieldID field_id, char *field_name, bool optional) { if (native_boolean != NULL) { jobject jni_boolean = (*env)->NewObject( env, boxed_boolean_properties.boolean_class, boxed_boolean_properties.boolean_constructor_id, (jboolean)*native_boolean); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not create boolean field %s", field_name); return AWS_OP_ERR; } (*env)->SetObjectField(env, packet, field_id, jni_boolean); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set boolean field %s", field_name); return AWS_OP_ERR; } if (!optional) { return AWS_OP_SUCCESS; } } if (optional) { return AWS_OP_SUCCESS; } else { return AWS_OP_ERR; } } int s_set_jni_string_field_in_packet( JNIEnv *env, const struct aws_byte_cursor *native_cursor, jobject packet, jfieldID field_id, char *field_name, bool optional) { if (native_cursor != NULL) { jstring jni_string = aws_jni_string_from_cursor(env, native_cursor); (*env)->SetObjectField(env, packet, field_id, jni_string); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set string field %s", field_name); return AWS_OP_ERR; } if (!optional) { return AWS_OP_SUCCESS; } } if (optional) { return AWS_OP_SUCCESS; } else { return AWS_OP_ERR; } } int s_set_jni_byte_array_field_in_packet( JNIEnv *env, const struct aws_byte_cursor *native_cursor, jobject packet, jfieldID field_id, char *field_name, bool optional) { if (native_cursor != NULL) { jbyteArray jni_byte = aws_jni_byte_array_from_cursor(env, native_cursor); (*env)->SetObjectField(env, packet, field_id, jni_byte); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set string field %s", field_name); return AWS_OP_ERR; } if (!optional) { return AWS_OP_SUCCESS; } } if (optional) { return AWS_OP_SUCCESS; } else { return AWS_OP_ERR; } } int s_set_user_properties_field( JNIEnv *env, const size_t user_property_count, const struct aws_mqtt5_user_property *packet_properties, jobject packet, jfieldID user_property_field_id) { /* No properties - nothing to do */ if (packet_properties == NULL) { return AWS_OP_SUCCESS; } if (user_property_count > 0) { jobject jni_user_properties_list = (*env)->NewObject( env, boxed_array_list_properties.list_class, boxed_array_list_properties.list_constructor_id); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not make new user properties list"); return AWS_OP_ERR; } (*env)->SetObjectField(env, packet, user_property_field_id, jni_user_properties_list); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not set new user properties list"); return AWS_OP_ERR; } for (size_t i = 0; i < user_property_count; ++i) { const struct aws_mqtt5_user_property *property = &packet_properties[i]; jstring jni_new_property_name = aws_jni_string_from_cursor(env, &property->name); jstring jni_new_property_value = aws_jni_string_from_cursor(env, &property->value); jobject jni_new_property = (*env)->NewObject( env, mqtt5_user_property_properties.user_property_class, mqtt5_user_property_properties.property_constructor_id, jni_new_property_name, jni_new_property_value); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not make new user property"); return AWS_OP_ERR; } jboolean jni_add_result = (*env)->CallBooleanMethod( env, jni_user_properties_list, boxed_list_properties.list_add_id, jni_new_property); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Could not add new user property"); return AWS_OP_ERR; } if ((bool)jni_add_result == false) { return AWS_OP_ERR; } } } return AWS_OP_SUCCESS; } int s_set_int_enum_in_packet( JNIEnv *env, const int *int_enum, jobject packet, jmethodID set_enum_field_id, bool optional) { if (int_enum) { if (*int_enum < 0) { return AWS_OP_ERR; } (*env)->CallVoidMethod(env, packet, set_enum_field_id, (jint)*int_enum); if (aws_jni_check_and_clear_exception(env)) { return AWS_OP_ERR; } if (!optional) { return AWS_OP_SUCCESS; } } if (optional) { return AWS_OP_SUCCESS; } else { return AWS_OP_ERR; } } jobject s_aws_mqtt5_client_create_jni_connack_packet_from_native( JNIEnv *env, const struct aws_mqtt5_packet_connack_view *native_connack_data) { jobject connack_data = (*env)->NewObject( env, mqtt5_connack_packet_properties.connack_packet_class, mqtt5_connack_packet_properties.connack_constructor_id); (*env)->SetBooleanField( env, connack_data, mqtt5_connack_packet_properties.connack_session_present_field_id, (jboolean)native_connack_data->session_present); int reason_code_int = (int)native_connack_data->reason_code; if (reason_code_int < 0) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating ConnAckPacket from native: Reason code is negative!"); return NULL; } (*env)->CallVoidMethod( env, connack_data, mqtt5_connack_packet_properties.connack_native_add_reason_code_id, (jint)reason_code_int); /* Set all of the optional data in Java classes */ if (s_set_jni_uint32_t_field_in_packet( env, native_connack_data->session_expiry_interval, connack_data, mqtt5_connack_packet_properties.connack_session_expiry_interval_field_id, "session expiry interval", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_uint16_t_field_in_packet( env, native_connack_data->receive_maximum, connack_data, mqtt5_connack_packet_properties.connack_receive_maximum_field_id, "receive maximum", true) != AWS_OP_SUCCESS) { return NULL; }; if (native_connack_data->maximum_qos) { int *maximum_qos_int = (int *)native_connack_data->maximum_qos; if (s_set_int_enum_in_packet( env, maximum_qos_int, connack_data, mqtt5_connack_packet_properties.connack_native_add_maximum_qos_id, true) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR( AWS_LS_MQTT5_CLIENT, "Error when creating ConnAckPacket from native: Could not set maximum QOS"); return NULL; } } if (s_set_jni_bool_field_in_packet( env, native_connack_data->retain_available, connack_data, mqtt5_connack_packet_properties.connack_retain_available_field_id, "retain available", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_uint32_t_field_in_packet( env, native_connack_data->maximum_packet_size, connack_data, mqtt5_connack_packet_properties.connack_maximum_packet_size_field_id, "maximum packet size", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_string_field_in_packet( env, native_connack_data->assigned_client_identifier, connack_data, mqtt5_connack_packet_properties.connack_assigned_client_identifier_field_id, "assigned client identifier", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_uint16_t_field_in_packet( env, native_connack_data->topic_alias_maximum, connack_data, mqtt5_connack_packet_properties.connack_topic_alias_maximum_field_id, "topic alias maximum", true) != AWS_OP_SUCCESS) { return NULL; }; if (s_set_jni_string_field_in_packet( env, native_connack_data->reason_string, connack_data, mqtt5_connack_packet_properties.connack_reason_string_field_id, "reason string", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_bool_field_in_packet( env, native_connack_data->wildcard_subscriptions_available, connack_data, mqtt5_connack_packet_properties.connack_wildcard_subscriptions_available_field_id, "wildcard subscriptions available", true) != AWS_OP_SUCCESS) { return NULL; }; if (s_set_jni_bool_field_in_packet( env, native_connack_data->subscription_identifiers_available, connack_data, mqtt5_connack_packet_properties.connack_subscription_identifiers_available_field_id, "subscription identifiers available", true) != AWS_OP_SUCCESS) { return NULL; }; if (s_set_jni_bool_field_in_packet( env, native_connack_data->shared_subscriptions_available, connack_data, mqtt5_connack_packet_properties.connack_shared_subscriptions_available_field_id, "shared subscriptions available", true) != AWS_OP_SUCCESS) { return NULL; }; if (s_set_jni_uint16_t_field_in_packet( env, native_connack_data->server_keep_alive, connack_data, mqtt5_connack_packet_properties.connack_server_keep_alive_field_id, "server keep alive", true) != AWS_OP_SUCCESS) { return NULL; }; if (s_set_jni_string_field_in_packet( env, native_connack_data->response_information, connack_data, mqtt5_connack_packet_properties.connack_response_information_field_id, "response information", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_string_field_in_packet( env, native_connack_data->server_reference, connack_data, mqtt5_connack_packet_properties.connack_server_reference_field_id, "server reference", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_user_properties_field( env, native_connack_data->user_property_count, native_connack_data->user_properties, connack_data, mqtt5_connack_packet_properties.connack_user_properties_field_id) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR( AWS_LS_MQTT5_CLIENT, "Error when creating ConnAckPacket from native: could not add user property!"); return NULL; } return connack_data; } jobject s_aws_mqtt5_client_create_jni_disconnect_packet_from_native( JNIEnv *env, const struct aws_mqtt5_packet_disconnect_view *native_disconnect_data) { jobject disconnect_packet_data = (*env)->NewObject( env, mqtt5_disconnect_packet_properties.disconnect_packet_class, mqtt5_disconnect_packet_properties.disconnect_constructor_id); int reason_code_int = (int)native_disconnect_data->reason_code; if (s_set_int_enum_in_packet( env, &reason_code_int, disconnect_packet_data, mqtt5_disconnect_packet_properties.disconnect_native_add_disconnect_reason_code_id, false) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR( AWS_LS_MQTT5_CLIENT, "Error when creating DisconnectPacket from native: Could not set reason code"); return NULL; } if (s_set_jni_uint32_t_field_in_packet( env, native_disconnect_data->session_expiry_interval_seconds, disconnect_packet_data, mqtt5_disconnect_packet_properties.disconnect_session_expiry_interval_seconds_field_id, "session expiry interval seconds", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_string_field_in_packet( env, native_disconnect_data->reason_string, disconnect_packet_data, mqtt5_disconnect_packet_properties.disconnect_reason_string_field_id, "reason string", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_string_field_in_packet( env, native_disconnect_data->server_reference, disconnect_packet_data, mqtt5_disconnect_packet_properties.disconnect_session_server_reference_field_id, "server reference", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_user_properties_field( env, native_disconnect_data->user_property_count, native_disconnect_data->user_properties, disconnect_packet_data, mqtt5_disconnect_packet_properties.disconnect_user_properties_field_id) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR( AWS_LS_MQTT5_CLIENT, "Error when creating DisconnectPacket from native: could not add user property!"); return NULL; } return disconnect_packet_data; } jobject s_aws_mqtt5_client_create_jni_negotiated_settings_from_native( JNIEnv *env, const struct aws_mqtt5_negotiated_settings *native_negotiated_settings_data) { jobject negotiated_settings_data = (*env)->NewObject( env, mqtt5_negotiated_settings_properties.negotiated_settings_class, mqtt5_negotiated_settings_properties.negotiated_settings_constructor_id); (*env)->CallVoidMethod( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_native_set_qos_id, (jint)native_negotiated_settings_data->maximum_qos); aws_jni_check_and_clear_exception(env); /* To hide JNI warning */ (*env)->SetLongField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_session_expiry_interval_field_id, (jlong)native_negotiated_settings_data->session_expiry_interval); (*env)->SetIntField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_receive_maximum_from_server_field_id, (jint)native_negotiated_settings_data->receive_maximum_from_server); (*env)->SetLongField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_maximum_packet_size_to_server_field_id, (jlong)native_negotiated_settings_data->maximum_packet_size_to_server); (*env)->SetIntField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_server_field_id, (jint)native_negotiated_settings_data->topic_alias_maximum_to_server); (*env)->SetIntField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_client_field_id, (jint)native_negotiated_settings_data->topic_alias_maximum_to_client); (*env)->SetIntField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_server_keep_alive_field_id, (jint)native_negotiated_settings_data->server_keep_alive); (*env)->SetBooleanField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_retain_available_field_id, (jboolean)native_negotiated_settings_data->retain_available); (*env)->SetBooleanField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_wildcard_subscriptions_available_field_id, (jboolean)native_negotiated_settings_data->wildcard_subscriptions_available); (*env)->SetBooleanField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_subscription_identifiers_available_field_id, (jboolean)native_negotiated_settings_data->subscription_identifiers_available); (*env)->SetBooleanField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_shared_subscriptions_available_field_id, (jboolean)native_negotiated_settings_data->shared_subscriptions_available); (*env)->SetBooleanField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_rejoined_session_field_id, (jboolean)native_negotiated_settings_data->rejoined_session); struct aws_byte_cursor client_id_storage_cursor = aws_byte_cursor_from_buf(&native_negotiated_settings_data->client_id_storage); jstring jni_assigned_client_id = aws_jni_string_from_cursor(env, &client_id_storage_cursor); (*env)->SetObjectField( env, negotiated_settings_data, mqtt5_negotiated_settings_properties.negotiated_settings_assigned_client_id_field_id, jni_assigned_client_id); return negotiated_settings_data; } jobject s_aws_mqtt5_client_create_jni_publish_packet_from_native( JNIEnv *env, const struct aws_mqtt5_packet_publish_view *publish) { jobject publish_packet_data = (*env)->NewObject( env, mqtt5_publish_packet_properties.publish_packet_class, mqtt5_publish_packet_properties.publish_constructor_id); jbyteArray jni_payload = aws_jni_byte_array_from_cursor(env, &publish->payload); (*env)->SetObjectField( env, publish_packet_data, mqtt5_publish_packet_properties.publish_payload_field_id, jni_payload); int publish_qos_int = (int)publish->qos; if (s_set_int_enum_in_packet( env, &publish_qos_int, publish_packet_data, mqtt5_publish_packet_properties.publish_native_set_qos_id, false) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating PublishPacket from native: Could not set QOS"); return NULL; } if (s_set_jni_bool_field_in_packet( env, &publish->retain, publish_packet_data, mqtt5_publish_packet_properties.publish_retain_field_id, "retain", false) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating PublishPacket from native: Could not set retain"); return NULL; } jstring jni_topic = aws_jni_string_from_cursor(env, &publish->topic); (*env)->SetObjectField(env, publish_packet_data, mqtt5_publish_packet_properties.publish_topic_field_id, jni_topic); if (publish->payload_format) { if (s_set_int_enum_in_packet( env, (int *)publish->payload_format, publish_packet_data, mqtt5_publish_packet_properties.publish_native_set_payload_format_indicator_id, true) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR( AWS_LS_MQTT5_CLIENT, "Error when creating PublishPacket from native: Could not set payload format"); return NULL; } } if (s_set_jni_uint32_t_field_in_packet( env, publish->message_expiry_interval_seconds, publish_packet_data, mqtt5_publish_packet_properties.publish_message_expiry_interval_seconds_field_id, "message expiry interval seconds", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_uint16_t_field_in_packet( env, publish->topic_alias, publish_packet_data, mqtt5_publish_packet_properties.publish_topic_alias_field_id, "topic alias", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_string_field_in_packet( env, publish->response_topic, publish_packet_data, mqtt5_publish_packet_properties.publish_response_topic_field_id, "response topic", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_byte_array_field_in_packet( env, publish->correlation_data, publish_packet_data, mqtt5_publish_packet_properties.publish_correlation_data_field_id, "correlation data", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_jni_string_field_in_packet( env, publish->content_type, publish_packet_data, mqtt5_publish_packet_properties.publish_content_type_field_id, "content type", true) != AWS_OP_SUCCESS) { return NULL; } if (publish->subscription_identifier_count && publish->subscription_identifiers) { jobject jni_subscription_identifiers = (*env)->NewObject( env, boxed_array_list_properties.list_class, boxed_array_list_properties.list_constructor_id); (*env)->SetObjectField( env, publish_packet_data, mqtt5_publish_packet_properties.publish_subscription_identifiers_field_id, jni_subscription_identifiers); for (size_t i = 0; i < publish->subscription_identifier_count; ++i) { const uint32_t *identifier = &publish->subscription_identifiers[i]; jobject jni_identifier_obj = (*env)->NewObject( env, boxed_long_properties.long_class, boxed_long_properties.constructor, (jlong)*identifier); jboolean jni_add_result = (*env)->CallBooleanMethod( env, jni_subscription_identifiers, boxed_list_properties.list_add_id, jni_identifier_obj); if (aws_jni_check_and_clear_exception(env)) { AWS_LOGF_ERROR( AWS_LS_MQTT5_CLIENT, "When creating PublishPacket from native could not add subscription identifier!"); return NULL; } if ((bool)jni_add_result == false) { AWS_LOGF_ERROR( AWS_LS_MQTT5_CLIENT, "When creating PublishPacket from native could not add subscription identifier!"); return NULL; } } } if (s_set_user_properties_field( env, publish->user_property_count, publish->user_properties, publish_packet_data, mqtt5_publish_packet_properties.publish_user_properties_field_id) == AWS_OP_ERR) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "When creating PublishPacket from native could not add user properties!"); return NULL; } return publish_packet_data; } jobject s_aws_mqtt5_client_create_jni_puback_packet_from_native( JNIEnv *env, struct aws_mqtt5_packet_puback_view *puback_packet) { /* Make the PubAck packet */ jobject puback_packet_data = (*env)->NewObject( env, mqtt5_puback_packet_properties.puback_packet_class, mqtt5_puback_packet_properties.puback_constructor_id); int reason_code_int = (int)puback_packet->reason_code; if (s_set_int_enum_in_packet( env, &reason_code_int, puback_packet_data, mqtt5_puback_packet_properties.puback_native_add_reason_code_id, false) != AWS_OP_SUCCESS) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "Error when creating PubAck result from native: Could not set reason code"); return NULL; } if (s_set_jni_string_field_in_packet( env, puback_packet->reason_string, puback_packet_data, mqtt5_puback_packet_properties.puback_reason_string_field_id, "reason string", true) != AWS_OP_SUCCESS) { return NULL; } if (s_set_user_properties_field( env, puback_packet->user_property_count, puback_packet->user_properties, puback_packet_data, mqtt5_puback_packet_properties.puback_user_properties_field_id) == AWS_OP_ERR) { AWS_LOGF_ERROR(AWS_LS_MQTT5_CLIENT, "When creating PubAckPacket from native could not add user property!"); return NULL; } return puback_packet_data; }