Skip to content

Commit 84bac79

Browse files
authored
Merge pull request #214 from hap-java/fix/close-owned-jmdns
Close owned mDNS instance and remove shutdown hook on stop
2 parents d5a1d09 + 11b8813 commit 84bac79

3 files changed

Lines changed: 57 additions & 9 deletions

File tree

‎CHANGES.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# HAP-Java 2.0.10
22
* Add constructors with custom min/max to the window covering tilt angle characteristics [#162](https://github.com/hap-java/HAP-Java/issues/162)
33
* Add optional Mute characteristic to Doorbell service
4+
* Fix leak of mDNS instances and shutdown hooks when stopping `HomekitRoot`
45

56
# HAP-Java 2.0.9
67
* Fix Set Duration and Remaining Duration characteristics to advertise format `uint32` instead of `int` [#202](https://github.com/hap-java/HAP-Java/issues/202)

‎src/main/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiser.java‎

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class JmdnsHomekitAdvertiser {
1717
private static final String SERVICE_TYPE = "_hap._tcp.local.";
1818

1919
private final JmDNS jmdns;
20+
private final boolean ownsJmdns;
21+
private Thread shutdownHook;
2022
private boolean discoverable = true;
2123
private static final Logger logger = LoggerFactory.getLogger(JmdnsHomekitAdvertiser.class);
2224
private boolean isAdvertising = false;
@@ -30,11 +32,16 @@ public class JmdnsHomekitAdvertiser {
3032
private int category;
3133

3234
public JmdnsHomekitAdvertiser(JmDNS jmdns) {
33-
this.jmdns = jmdns;
35+
this(jmdns, false);
3436
}
3537

3638
public JmdnsHomekitAdvertiser(InetAddress localAddress) throws UnknownHostException, IOException {
37-
jmdns = JmDNS.create(localAddress);
39+
this(JmDNS.create(localAddress), true);
40+
}
41+
42+
JmdnsHomekitAdvertiser(JmDNS jmdns, boolean ownsJmdns) {
43+
this.jmdns = jmdns;
44+
this.ownsJmdns = ownsJmdns;
3845
}
3946

4047
public synchronized void advertise(
@@ -54,18 +61,33 @@ public synchronized void advertise(
5461

5562
registerService();
5663

57-
Runtime.getRuntime()
58-
.addShutdownHook(
59-
new Thread(
60-
() -> {
61-
logger.trace("Stopping advertising in response to shutdown.");
62-
jmdns.unregisterAllServices();
63-
}));
64+
shutdownHook =
65+
new Thread(
66+
() -> {
67+
logger.trace("Stopping advertising in response to shutdown.");
68+
jmdns.unregisterAllServices();
69+
});
70+
Runtime.getRuntime().addShutdownHook(shutdownHook);
6471
isAdvertising = true;
6572
}
6673

6774
public synchronized void stop() {
6875
unregisterService();
76+
isAdvertising = false;
77+
if (shutdownHook != null) {
78+
try {
79+
Runtime.getRuntime().removeShutdownHook(shutdownHook);
80+
} catch (IllegalStateException e) {
81+
// already shutting down
82+
}
83+
}
84+
if (ownsJmdns) {
85+
try {
86+
jmdns.close();
87+
} catch (IOException e) {
88+
logger.warn("Failed to close mDNS", e);
89+
}
90+
}
6991
}
7092

7193
public synchronized void setDiscoverable(boolean discoverable) throws IOException {

‎src/test/java/io/github/hapjava/server/impl/jmdns/JmdnsHomekitAdvertiserTest.java‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import static org.assertj.core.api.Assertions.assertThat;
44
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5+
import static org.mockito.ArgumentMatchers.any;
56
import static org.mockito.Mockito.mock;
7+
import static org.mockito.Mockito.never;
68
import static org.mockito.Mockito.verify;
79

810
import java.io.IOException;
@@ -54,6 +56,29 @@ public void testSetConfigurationIndex() throws Exception {
5456
assertThat(getArgumentFromUnregister().getPropertyString("c#")).isEqualTo("1");
5557
}
5658

59+
@Test
60+
public void testStopClosesOwnedJmdns() throws Exception {
61+
subject = new JmdnsHomekitAdvertiser(jmdns, true);
62+
advertise();
63+
subject.stop();
64+
verify(jmdns).close();
65+
}
66+
67+
@Test
68+
public void testStopDoesNotCloseSuppliedJmdns() throws Exception {
69+
advertise();
70+
subject.stop();
71+
verify(jmdns, never()).close();
72+
}
73+
74+
@Test
75+
public void testSetDiscoverableAfterStopDoesNotRegister() throws Exception {
76+
advertise();
77+
subject.stop();
78+
subject.setDiscoverable(false);
79+
verify(jmdns).registerService(any(ServiceInfo.class));
80+
}
81+
5782
private ServiceInfo getArgumentFromUnregister() {
5883
ArgumentCaptor<ServiceInfo> serviceInfoCaptor = ArgumentCaptor.forClass(ServiceInfo.class);
5984
verify(jmdns).unregisterService(serviceInfoCaptor.capture());

0 commit comments

Comments
 (0)