Browse Source

Merge 4718fb7556 into be3207ab65

pull/15651/merge
Oleksandra Matviienko 2 days ago
committed by GitHub
parent
commit
110eec3ab5
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 56
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java
  2. 79
      common/coap-server/src/test/java/org/thingsboard/server/coapserver/DefaultCoapServerServiceTest.java
  3. 22
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java
  4. 115
      common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServiceTest.java

56
common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java

@ -106,26 +106,46 @@ public class DefaultCoapServerService implements CoapServerService, SmartInitial
private CoapServer createCoapServer() throws UnknownHostException {
Configuration networkConfig = createNetworkConfiguration();
server = new CoapServer(networkConfig);
try {
CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder();
InetAddress addr = InetAddress.getByName(coapServerContext.getHost());
InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort());
noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr);
noSecCoapEndpointBuilder.setConfiguration(networkConfig);
CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build();
server.addEndpoint(noSecCoapEndpoint);
if (isDtlsEnabled()) {
createDtlsEndpoint(networkConfig);
dtlsSessionsExecutor = ThingsBoardExecutors.newSingleThreadScheduledExecutor(getClass().getSimpleName());
dtlsSessionsExecutor.scheduleAtFixedRate(this::evictTimeoutSessions, new Random().nextInt((int) getDtlsSessionReportTimeout()), getDtlsSessionReportTimeout(), TimeUnit.MILLISECONDS);
}
Resource root = server.getRoot();
TbCoapServerMessageDeliverer messageDeliverer = new TbCoapServerMessageDeliverer(root);
server.setMessageDeliverer(messageDeliverer);
CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder();
InetAddress addr = InetAddress.getByName(coapServerContext.getHost());
InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort());
noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr);
noSecCoapEndpointBuilder.setConfiguration(networkConfig);
CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build();
server.addEndpoint(noSecCoapEndpoint);
if (isDtlsEnabled()) {
createDtlsEndpoint(networkConfig);
dtlsSessionsExecutor = ThingsBoardExecutors.newSingleThreadScheduledExecutor(getClass().getSimpleName());
dtlsSessionsExecutor.scheduleAtFixedRate(this::evictTimeoutSessions, new Random().nextInt((int) getDtlsSessionReportTimeout()), getDtlsSessionReportTimeout(), TimeUnit.MILLISECONDS);
server.start();
return server;
} catch (RuntimeException | UnknownHostException e) {
log.error("Failed to start CoAP server, releasing resources", e);
try {
if (dtlsSessionsExecutor != null) {
dtlsSessionsExecutor.shutdownNow();
}
if (server != null) {
server.destroy();
}
} catch (Exception suppressed) {
e.addSuppressed(suppressed);
} finally {
server = null;
dtlsSessionsExecutor = null;
dtlsConnector = null;
dtlsCoapEndpoint = null;
tbDtlsCertificateVerifier = null;
}
throw e;
}
Resource root = server.getRoot();
TbCoapServerMessageDeliverer messageDeliverer = new TbCoapServerMessageDeliverer(root);
server.setMessageDeliverer(messageDeliverer);
server.start();
return server;
}
private boolean isDtlsEnabled() {

79
common/coap-server/src/test/java/org/thingsboard/server/coapserver/DefaultCoapServerServiceTest.java

@ -0,0 +1,79 @@
/**
* Copyright © 2016-2026 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.coapserver;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class DefaultCoapServerServiceTest {
private static final String HOST = "127.0.0.1";
@Mock
private CoapServerContext mockCoapServerContext;
private DefaultCoapServerService service;
private DatagramSocket occupiedSocket;
private int occupiedPort;
@BeforeEach
public void setUp() throws Exception {
occupiedSocket = new DatagramSocket(new InetSocketAddress(InetAddress.getByName(HOST), 0));
occupiedPort = occupiedSocket.getLocalPort();
service = new DefaultCoapServerService();
ReflectionTestUtils.setField(service, "coapServerContext", mockCoapServerContext);
when(mockCoapServerContext.getHost()).thenReturn(HOST);
when(mockCoapServerContext.getPort()).thenReturn(occupiedPort);
when(mockCoapServerContext.getDtlsSettings()).thenReturn(null);
}
@AfterEach
public void tearDown() {
if (occupiedSocket != null && !occupiedSocket.isClosed()) {
occupiedSocket.close();
}
}
@Test
public void whenPlainBindFails_thenInitThrowsAndReleasesCoapServer() {
assertThatThrownBy(() -> service.init())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("None of the server endpoints could be started");
assertThat(ReflectionTestUtils.getField(service, "server")).isNull();
assertThat(ReflectionTestUtils.getField(service, "dtlsSessionsExecutor")).isNull();
assertThat(ReflectionTestUtils.getField(service, "dtlsConnector")).isNull();
assertThat(ReflectionTestUtils.getField(service, "dtlsCoapEndpoint")).isNull();
assertThat(ReflectionTestUtils.getField(service, "tbDtlsCertificateVerifier")).isNull();
}
}

22
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java

@ -82,13 +82,29 @@ public class LwM2MTransportBootstrapService implements SmartInitializingSingleto
@PostConstruct
public void init() {
log.info("Starting LwM2M transport bootstrap server...");
this.server = getLhBootstrapServer();
this.server.start();
log.info("Started LwM2M transport bootstrap server.");
LeshanBootstrapServer bootstrapServer = getLhBootstrapServer();
try {
this.server = bootstrapServer;
bootstrapServer.start();
log.info("Started LwM2M transport bootstrap server.");
} catch (RuntimeException e) {
log.error("Failed to start LwM2M transport bootstrap server, releasing resources", e);
try {
bootstrapServer.destroy();
} catch (Exception suppressed) {
e.addSuppressed(suppressed);
} finally {
this.server = null;
}
throw e;
}
}
@PreDestroy
public void shutdown() {
if (server == null) {
return;
}
try {
log.info("Stopping LwM2M transport bootstrap server!");
server.destroy();

115
common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServiceTest.java

@ -0,0 +1,115 @@
/**
* Copyright © 2016-2026 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.bootstrap;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.test.util.ReflectionTestUtils;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.TbLwM2MDtlsBootstrapCertificateVerifier;
import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore;
import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MInMemoryBootstrapConfigStore;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class LwM2MTransportBootstrapServiceTest {
private static final String HOST = "127.0.0.1";
@Mock
private LwM2MTransportServerConfig serverConfig;
@Mock
private LwM2MTransportBootstrapConfig bootstrapConfig;
@Mock
private LwM2MBootstrapSecurityStore lwM2MBootstrapSecurityStore;
@Mock
private LwM2MInMemoryBootstrapConfigStore lwM2MInMemoryBootstrapConfigStore;
@Mock
private TransportService transportService;
@Mock
private TbLwM2MDtlsBootstrapCertificateVerifier certificateVerifier;
private LwM2MTransportBootstrapService service;
private DatagramSocket occupiedPlain;
private DatagramSocket occupiedSecure;
@BeforeEach
public void setUp() throws Exception {
occupiedPlain = new DatagramSocket(new InetSocketAddress(InetAddress.getByName(HOST), 0));
occupiedSecure = new DatagramSocket(new InetSocketAddress(InetAddress.getByName(HOST), 0));
when(bootstrapConfig.getHost()).thenReturn(HOST);
when(bootstrapConfig.getPort()).thenReturn(occupiedPlain.getLocalPort());
when(bootstrapConfig.getSecureHost()).thenReturn(HOST);
when(bootstrapConfig.getSecurePort()).thenReturn(occupiedSecure.getLocalPort());
when(bootstrapConfig.getSslCredentials()).thenReturn(null);
when(serverConfig.isRecommendedCiphers()).thenReturn(false);
when(serverConfig.isRecommendedSupportedGroups()).thenReturn(false);
when(serverConfig.getDtlsRetransmissionTimeout()).thenReturn(9000);
when(serverConfig.getDtlsCidLength()).thenReturn(null);
service = new LwM2MTransportBootstrapService(
serverConfig,
bootstrapConfig,
lwM2MBootstrapSecurityStore,
lwM2MInMemoryBootstrapConfigStore,
transportService,
certificateVerifier
);
}
@AfterEach
public void tearDown() {
if (occupiedPlain != null && !occupiedPlain.isClosed()) {
occupiedPlain.close();
}
if (occupiedSecure != null && !occupiedSecure.isClosed()) {
occupiedSecure.close();
}
}
@Test
public void whenEndpointsFailToStart_thenInitThrowsAndReleasesBootstrapServer() {
assertThatThrownBy(() -> service.init())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("None of the server endpoints could be started");
assertThat(ReflectionTestUtils.getField(service, "server")).isNull();
}
}
Loading…
Cancel
Save