Skip to content

Commit 3349898

Browse files
authored
Fix memory leaks on multiple MQTT connect attempts (#958)
1 parent bf7f7b1 commit 3349898

4 files changed

Lines changed: 50 additions & 18 deletions

File tree

src/native/mqtt_connection.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,6 @@ static void s_mqtt_connection_destroy(JNIEnv *env, struct mqtt_jni_connection *c
437437
(*env)->DeleteGlobalRef(env, connection->java_mqtt_connection);
438438
}
439439

440-
aws_tls_connection_options_clean_up(&connection->tls_options);
441-
442440
struct aws_allocator *allocator = aws_jni_get_allocator();
443441
aws_mem_release(allocator, connection);
444442
}
@@ -587,11 +585,11 @@ void JNICALL Java_software_amazon_awssdk_crt_mqtt_MqttClientConnection_mqttClien
587585

588586
/* if a tls_ctx was provided, initialize tls options */
589587
struct aws_tls_ctx *tls_ctx = (struct aws_tls_ctx *)jni_tls_ctx;
590-
struct aws_tls_connection_options *tls_options = NULL;
588+
struct aws_tls_connection_options tls_options;
589+
AWS_ZERO_STRUCT(tls_options);
591590
if (tls_ctx) {
592-
tls_options = &connection->tls_options;
593-
aws_tls_connection_options_init_from_ctx(tls_options, tls_ctx);
594-
aws_tls_connection_options_set_server_name(tls_options, aws_jni_get_allocator(), &endpoint);
591+
aws_tls_connection_options_init_from_ctx(&tls_options, tls_ctx);
592+
aws_tls_connection_options_set_server_name(&tls_options, aws_jni_get_allocator(), &endpoint);
595593
}
596594

597595
client_id = aws_jni_byte_cursor_from_jstring_acquire(env, jni_client_id);
@@ -602,7 +600,7 @@ void JNICALL Java_software_amazon_awssdk_crt_mqtt_MqttClientConnection_mqttClien
602600
connect_options.host_name = endpoint;
603601
connect_options.port = port;
604602
connect_options.socket_options = &connection->socket_options;
605-
connect_options.tls_options = tls_options;
603+
connect_options.tls_options = tls_ctx ? &tls_options : NULL;
606604
connect_options.client_id = client_id;
607605
connect_options.keep_alive_time_secs = (uint16_t)keep_alive_secs;
608606
connect_options.ping_timeout_ms = ping_timeout_ms;
@@ -620,6 +618,7 @@ void JNICALL Java_software_amazon_awssdk_crt_mqtt_MqttClientConnection_mqttClien
620618
}
621619

622620
cleanup:
621+
aws_tls_connection_options_clean_up(&tls_options);
623622
aws_jni_byte_cursor_from_jstring_release(env, jni_endpoint, endpoint);
624623
aws_jni_byte_cursor_from_jstring_release(env, jni_client_id, client_id);
625624
}

src/native/mqtt_connection.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ struct mqtt_jni_connection {
3434
struct aws_mqtt_client *client; /* Provided to mqtt_connect */
3535
struct aws_mqtt_client_connection *client_connection;
3636
struct aws_socket_options socket_options;
37-
struct aws_tls_connection_options tls_options;
3837

3938
JavaVM *jvm;
4039
jobject java_mqtt_connection; /* MqttClientConnection instance */

src/test/java/software/amazon/awssdk/crt/test/MqttClientConnectionFixture.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,15 @@ void reset() {
176176
connectionEventsStatistics = new ConnectionEventsStatistics();
177177
}
178178

179-
void connectDirect(TlsContext tlsContext, String endpoint, int port, String username, String password, HttpProxyOptions httpProxyOptions) throws Exception
180-
{
181-
reset();
182-
183-
try(EventLoopGroup elg = new EventLoopGroup(1);
184-
HostResolver hr = new HostResolver(elg);
185-
ClientBootstrap bootstrap = new ClientBootstrap(elg, hr)) {
179+
MqttClientConnection createMqttClientConnection(TlsContext tlsContext,
180+
String endpoint,
181+
int port,
182+
String username,
183+
String password,
184+
HttpProxyOptions httpProxyOptions) throws Exception {
185+
try (EventLoopGroup elg = new EventLoopGroup(1);
186+
HostResolver hr = new HostResolver(elg);
187+
ClientBootstrap bootstrap = new ClientBootstrap(elg, hr)) {
186188

187189
// Connection callback events
188190
MqttClientConnectionEvents events = new MqttClientConnectionEvents() {
@@ -256,12 +258,19 @@ public void onConnectionClosed(OnConnectionClosedReturn data) {
256258
if (connectionMessageTransfomer != null) {
257259
connection.onMessage(connectionMessageTransfomer);
258260
}
259-
CompletableFuture<Boolean> connected = connection.connect();
260-
connected.get();
261+
262+
return connection;
261263
}
262264
}
263265
}
264266

267+
void connectDirect(TlsContext tlsContext, String endpoint, int port, String username, String password, HttpProxyOptions httpProxyOptions) throws Exception {
268+
reset();
269+
MqttClientConnection connection = createMqttClientConnection(tlsContext, endpoint, port, username, password, httpProxyOptions);
270+
CompletableFuture<Boolean> connected = connection.connect();
271+
connected.get(30, TimeUnit.SECONDS);
272+
}
273+
265274
void connectWebsockets(CredentialsProvider credentialsProvider, String endpoint, int port, TlsContext tlsContext, String username, String password, HttpProxyOptions httpProxyOptions) throws Exception
266275
{
267276
String clientId = TEST_CLIENTID + (UUID.randomUUID()).toString();

src/test/java/software/amazon/awssdk/crt/test/MqttClientConnectionTest.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
package software.amazon.awssdk.crt.test;
77

88
import org.junit.Assume;
9-
import static org.junit.Assert.assertTrue;
109
import static org.junit.Assert.assertEquals;
10+
import static org.junit.Assert.assertTrue;
11+
import static org.junit.Assert.assertThrows;
1112
import static org.junit.Assert.fail;
1213
import java.util.UUID;
1314
import java.util.concurrent.CompletableFuture;
@@ -261,4 +262,28 @@ public void testConnectDisconnectEventsUnhappy() {
261262
close();
262263
}
263264
}
265+
266+
/* This scenario once led to memory leaks, so this test primarily checks that there is no memory leaks. */
267+
@Test
268+
public void testMultipleFailedAttemptsOnSingleConnection() {
269+
skipIfNetworkUnavailable();
270+
Assume.assumeNotNull(AWS_TEST_MQTT311_IOT_CORE_HOST);
271+
try (TlsContextOptions contextOptions = TlsContextOptions.createDefaultClient();
272+
TlsContext context = new TlsContext(contextOptions)) {
273+
try (MqttClientConnection connection = createMqttClientConnection(
274+
context,
275+
AWS_TEST_MQTT311_IOT_CORE_HOST,
276+
8883,
277+
null,
278+
null,
279+
null)) {
280+
for (int i = 0; i < 2; i++) {
281+
CompletableFuture<Boolean> connected = connection.connect();
282+
assertThrows(Exception.class, () -> connected.get(30, TimeUnit.SECONDS));
283+
}
284+
} catch (Exception ex) {
285+
fail(ex.toString());
286+
}
287+
}
288+
}
264289
};

0 commit comments

Comments
 (0)