updated Californium and Leshan versions

This commit is contained in:
YevhenBondarenko 2022-01-20 09:41:36 +02:00
parent 652071fdb7
commit 292220cddc
40 changed files with 251 additions and 228 deletions

View File

@ -52,6 +52,8 @@ import static org.junit.Assert.assertNotNull;
@Slf4j
public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest {
protected final byte[] EMPTY_PAYLOAD = new byte[0];
protected CoapClient client;
@Override

View File

@ -25,15 +25,13 @@ import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.gen.transport.TransportProtos;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertTrue;
@Slf4j
@ -88,7 +86,7 @@ public abstract class AbstractCoapAttributesUpdatesProtoIntegrationTest extends
}
protected void validateEmptyCurrentStateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException {
assertNull(callback.getPayloadBytes());
assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode());
assertEquals(0, callback.getObserve().intValue());

View File

@ -31,13 +31,12 @@ import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -186,7 +185,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
}
private void validateCurrentStateNotification(TestCoapCallback callback) {
assertNull(callback.getPayloadBytes());
assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes());
assertNotNull(callback.getObserve());
assertEquals(callback.getResponseCode(), CoAP.ResponseCode.VALID);
assertEquals(0, callback.getObserve().intValue());

View File

@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.io.IOUtils;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.leshan.client.object.Security;
import org.junit.After;
import org.junit.Assert;
@ -174,7 +174,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest
public void basicTestConnectionObserveTelemetry(Security security,
LwM2MClientCredential credentials,
NetworkConfig coapConfig,
Configuration coapConfig,
String endpoint) throws Exception {
createDeviceProfile(TRANSPORT_CONFIGURATION);
Device device = createDevice(credentials);
@ -259,7 +259,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest
this.resources = resources;
}
public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc, String endpoint) throws Exception {
public void createNewClient(Security security, Configuration coapConfig, boolean isRpc, String endpoint) throws Exception {
clientDestroy();
client = new LwM2MTestClient(this.executor, endpoint);
int clientPort = SocketUtils.findAvailableTcpPort();

View File

@ -15,9 +15,11 @@
*/
package org.thingsboard.server.transport.lwm2m;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.leshan.client.object.Security;
import static org.eclipse.californium.core.config.CoapConfig.COAP_PORT;
import static org.eclipse.californium.core.config.CoapConfig.COAP_SECURE_PORT;
import static org.eclipse.leshan.client.object.Security.noSec;
public class Lwm2mTestHelper {
@ -32,10 +34,10 @@ public class Lwm2mTestHelper {
public static final int SHORT_SERVER_ID = 123;
public static final int SHORT_SERVER_ID_BS = 111;
public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT));
public static final Configuration SECURE_COAP_CONFIG = new Configuration().set(COAP_SECURE_PORT, SECURE_PORT);
public static final String SECURE_URI = "coaps://" + HOST + ":" + SECURE_PORT;
public static final Security SECURITY = noSec("coap://"+ HOST +":" + PORT, SHORT_SERVER_ID);
public static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT));
public static final Configuration COAP_CONFIG = new Configuration().set(COAP_PORT, PORT);
// Models
public static final String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"};

View File

@ -131,10 +131,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
scheduler.schedule(() -> {
try {
state.set(1);
fireResourcesChange(3);
fireResourceChange(3);
Thread.sleep(100);
state.set(2);
fireResourcesChange(3);
fireResourceChange(3);
} catch (Exception e) {
}
}, 100, TimeUnit.MILLISECONDS);
@ -144,10 +144,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
scheduler.schedule(() -> {
try {
state.set(3);
fireResourcesChange(3);
fireResourceChange(3);
Thread.sleep(100);
updateResult.set(1);
fireResourcesChange(5);
fireResourceChange(5);
} catch (Exception e) {
}
}, 100, TimeUnit.MILLISECONDS);

View File

@ -17,10 +17,7 @@ package org.thingsboard.server.transport.lwm2m.client;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.core.observe.ObservationStore;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.leshan.client.californium.LeshanClient;
import org.eclipse.leshan.client.californium.LeshanClientBuilder;
@ -32,7 +29,6 @@ import org.eclipse.leshan.client.resource.DummyInstanceEnabler;
import org.eclipse.leshan.client.resource.ObjectsInitializer;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.californium.EndpointFactory;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ObjectLoader;
@ -44,15 +40,15 @@ import org.eclipse.leshan.core.request.BootstrapRequest;
import org.eclipse.leshan.core.request.DeregisterRequest;
import org.eclipse.leshan.core.request.RegisterRequest;
import org.eclipse.leshan.core.request.UpdateRequest;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import org.junit.Assert;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY;
import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL;
import static org.eclipse.leshan.core.LwM2mId.DEVICE;
import static org.eclipse.leshan.core.LwM2mId.FIRMWARE;
@ -61,10 +57,10 @@ import static org.eclipse.leshan.core.LwM2mId.SECURITY;
import static org.eclipse.leshan.core.LwM2mId.SERVER;
import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources;
@ -84,7 +80,7 @@ public class LwM2MTestClient {
private LwM2MLocationParams locationParams;
private LwM2mTemperatureSensor lwM2MTemperatureSensor;
public void init(Security security, NetworkConfig coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException {
public void init(Security security, Configuration coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException {
Assert.assertNull("client already initialized", client);
List<ObjectModel> models = new ArrayList<>();
for (String resourceName : resources) {
@ -106,44 +102,19 @@ public class LwM2MTestClient {
initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, OBJECT_INSTANCE_ID_0));
initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_0), new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_12));
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
dtlsConfig.setRecommendedCipherSuitesOnly(true);
dtlsConfig.setClientOnly();
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(coapConfig);
dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, true);
DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory();
engineFactory.setReconnectOnUpdate(false);
engineFactory.setResumeOnConnect(true);
EndpointFactory endpointFactory = new EndpointFactory() {
@Override
public CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig,
ObservationStore store) {
CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
builder.setInetSocketAddress(address);
builder.setNetworkConfig(coapConfig);
return builder.build();
}
@Override
public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig,
ObservationStore store) {
CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
DtlsConnectorConfig.Builder dtlsConfigBuilder = new DtlsConnectorConfig.Builder(dtlsConfig);
builder.setConnector(new DTLSConnector(dtlsConfigBuilder.build()));
builder.setNetworkConfig(coapConfig);
return builder.build();
}
};
LeshanClientBuilder builder = new LeshanClientBuilder(endpoint);
builder.setLocalAddress("0.0.0.0", port);
builder.setObjects(initializer.createAll());
builder.setCoapConfig(coapConfig);
builder.setDtlsConfig(dtlsConfig);
builder.setRegistrationEngineFactory(engineFactory);
builder.setEndpointFactory(endpointFactory);
builder.setSharedExecutor(executor);
builder.setDecoder(new DefaultLwM2mDecoder(false));

View File

@ -81,8 +81,11 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements
public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) {
try {
if (id != null) this.setId(id);
executorService.scheduleWithFixedDelay(() ->
fireResourcesChange(0, 2), 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN
executorService.scheduleWithFixedDelay(() -> {
fireResourceChange(0);
fireResourceChange(2);
}
, 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN
} catch (Throwable e) {
log.error("[{}]Throwable", e.toString());
e.printStackTrace();
@ -126,23 +129,23 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements
}
case 1:
setPriority((Integer) (value.getValue() instanceof Long ? ((Long) value.getValue()).intValue() : value.getValue()));
fireResourcesChange(resourceId);
fireResourceChange(resourceId);
return WriteResponse.success();
case 2:
setTimestamp(((Date) value.getValue()).getTime());
fireResourcesChange(resourceId);
fireResourceChange(resourceId);
return WriteResponse.success();
case 3:
setDescription((String) value.getValue());
fireResourcesChange(resourceId);
fireResourceChange(resourceId);
return WriteResponse.success();
case 4:
setDataFormat((String) value.getValue());
fireResourcesChange(resourceId);
fireResourceChange(resourceId);
return WriteResponse.success();
case 5:
setAppID((Integer) value.getValue());
fireResourcesChange(resourceId);
fireResourceChange(resourceId);
return WriteResponse.success();
default:
return super.write(identity, replace, resourceId, value);
@ -185,7 +188,7 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements
try {
if (value instanceof LwM2mMultipleResource) {
if (replace || this.data == null) {
this.data = new HashMap<>();
this.data = new HashMap<>();
}
value.getInstances().values().forEach(v -> {
this.data.put(v.getId(), (byte[]) v.getValue());

View File

@ -74,8 +74,10 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable {
}
this.scaleFactor = scaleFactor;
timestamp = new Date();
executorService.scheduleWithFixedDelay(() ->
fireResourcesChange(0, 1), 10000, 10000, TimeUnit.MILLISECONDS);
executorService.scheduleWithFixedDelay(() -> {
fireResourceChange(0);
fireResourceChange(1);
}, 10000, 10000, TimeUnit.MILLISECONDS);
} catch (Throwable e) {
log.error("[{}]Throwable", e.toString());
e.printStackTrace();
@ -117,13 +119,16 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable {
private void moveLatitude(float delta) {
latitude = latitude + delta * scaleFactor;
timestamp = new Date();
fireResourcesChange(0, 5);
fireResourceChange(0);
fireResourceChange(5);
}
private void moveLongitude(float delta) {
longitude = longitude + delta * scaleFactor;
timestamp = new Date();
fireResourcesChange(1, 5);
fireResourceChange(1);
fireResourceChange(5);
}
public float getLatitude() {

View File

@ -93,10 +93,9 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr
float delta = (RANDOM.nextInt(20) - 10) / 10f;
currentTemp += delta;
Integer changedResource = adjustMinMaxMeasuredValue(currentTemp);
fireResourceChange(5700);
if (changedResource != null) {
fireResourcesChange(5700, changedResource);
} else {
fireResourcesChange(5700);
fireResourceChange(changedResource);
}
}
@ -127,5 +126,4 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr
}
}

View File

@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.client;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.Destroyable;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mResource;
@ -25,7 +26,6 @@ import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import javax.security.auth.Destroyable;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
@ -103,11 +103,11 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
return WriteResponse.notFound();
case 14:
setUtcOffset((String) value.getValue());
fireResourcesChange(resourceId);
fireResourceChange(resourceId);
return WriteResponse.success();
case 15:
setTimezone((String) value.getValue());
fireResourcesChange(resourceId);
fireResourceChange(resourceId);
return WriteResponse.success();
default:
return super.write(identity, replace, resourceId, value);

View File

@ -128,16 +128,17 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
try {
state.set(1);
updateResult.set(1);
fireResourcesChange(7, 9);
fireResourceChange(7);
fireResourceChange(9);
Thread.sleep(100);
state.set(2);
fireResourcesChange(7);
fireResourceChange(7);
Thread.sleep(100);
state.set(3);
fireResourcesChange(7);
fireResourceChange(7);
Thread.sleep(100);
updateResult.set(3);
fireResourcesChange(9);
fireResourceChange(9);
} catch (Exception e) {
}
@ -148,7 +149,8 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
scheduler.schedule(() -> {
state.set(4);
updateResult.set(2);
fireResourcesChange(7, 9);
fireResourceChange(7);
fireResourceChange(9);
}, 100, TimeUnit.MILLISECONDS);
}

View File

@ -201,9 +201,9 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest {
@Test
public void testSoftwareUpdateByObject9() throws Exception {
createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA9);
NoSecClientCredential credentials = createNoSecClientCredentials(CLIENT_ENDPOINT_OTA9);
final Device device = createDevice(credentials);
createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA9);
createNewClient(SECURITY, COAP_CONFIG, false, CLIENT_ENDPOINT_OTA9);
Thread.sleep(1000);

View File

@ -52,8 +52,8 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration
Set actualObjects = ConcurrentHashMap.newKeySet();
Set actualInstances = ConcurrentHashMap.newKeySet();
rpcActualValue.forEach(node -> {
if (!node.get("url").asText().equals("/")) {
LwM2mPath path = new LwM2mPath(node.get("url").asText());
if (!node.get("uriReference").asText().equals("/")) {
LwM2mPath path = new LwM2mPath(node.get("uriReference").asText());
actualObjects.add("/" + path.getObjectId());
if (path.isObjectInstance()) {
actualInstances.add("/" + path.getObjectId() + "/" + path.getObjectInstanceId());

View File

@ -17,6 +17,7 @@ package org.thingsboard.server.coapserver;
import org.eclipse.californium.core.CoapServer;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentMap;
@ -24,7 +25,7 @@ public interface CoapServerService {
CoapServer getCoapServer() throws UnknownHostException;
ConcurrentMap<String, TbCoapDtlsSessionInfo> getDtlsSessionsMap();
ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> getDtlsSessionsMap();
long getTimeout();

View File

@ -18,8 +18,9 @@ package org.thingsboard.server.coapserver;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.springframework.beans.factory.annotation.Autowired;
@ -37,7 +38,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME;
import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS;
@Slf4j
@Component
@ -78,8 +79,8 @@ public class DefaultCoapServerService implements CoapServerService {
}
@Override
public ConcurrentMap<String, TbCoapDtlsSessionInfo> getDtlsSessionsMap() {
return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionIdsMap() : null;
public ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> getDtlsSessionsMap() {
return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionsMap() : null;
}
@Override
@ -88,16 +89,16 @@ public class DefaultCoapServerService implements CoapServerService {
}
private CoapServer createCoapServer() throws UnknownHostException {
NetworkConfig networkConfig = new NetworkConfig();
networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
networkConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME);
networkConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
networkConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED");
networkConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024);
networkConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
networkConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4);
networkConfig.setInt(NetworkConfig.Keys.COAP_PORT, coapServerContext.getPort());
Configuration networkConfig = new Configuration();
networkConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
networkConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
networkConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS);
networkConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
networkConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED);
networkConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024);
networkConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024);
networkConfig.set(CoapConfig.MAX_RETRANSMIT, 4);
networkConfig.set(CoapConfig.COAP_PORT, coapServerContext.getPort());
server = new CoapServer(networkConfig);
CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder();
@ -105,15 +106,15 @@ public class DefaultCoapServerService implements CoapServerService {
InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort());
noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr);
noSecCoapEndpointBuilder.setNetworkConfig(networkConfig);
noSecCoapEndpointBuilder.setConfiguration(networkConfig);
CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build();
server.addEndpoint(noSecCoapEndpoint);
if (isDtlsEnabled()) {
CoapEndpoint.Builder dtlsCoapEndpointBuilder = new CoapEndpoint.Builder();
TbCoapDtlsSettings dtlsSettings = coapServerContext.getDtlsSettings();
DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig();
networkConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort());
dtlsCoapEndpointBuilder.setNetworkConfig(networkConfig);
DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(networkConfig);
networkConfig.set(CoapConfig.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort());
dtlsCoapEndpointBuilder.setConfiguration(networkConfig);
DTLSConnector connector = new DTLSConnector(dtlsConnectorConfig);
dtlsCoapEndpointBuilder.setConnector(connector);
CoapEndpoint dtlsCoapEndpoint = dtlsCoapEndpointBuilder.build();

View File

@ -23,7 +23,6 @@ import org.eclipse.californium.scandium.dtls.CertificateMessage;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
import org.eclipse.californium.scandium.dtls.ConnectionId;
import org.eclipse.californium.scandium.dtls.DTLSSession;
import org.eclipse.californium.scandium.dtls.HandshakeException;
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
@ -34,13 +33,13 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.auth.SessionInfoCreator;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.common.transport.util.SslUtil;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import javax.security.auth.x500.X500Principal;
import java.net.InetSocketAddress;
import java.security.cert.CertPath;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateExpiredException;
@ -48,7 +47,6 @@ import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -71,12 +69,12 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
}
@Override
public List<CertificateType> getSupportedCertificateType() {
public List<CertificateType> getSupportedCertificateTypes() {
return Collections.singletonList(CertificateType.X_509);
}
@Override
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) {
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, CertificateMessage message) {
try {
CertPath certpath = message.getCertificateChain();
X509Certificate[] chain = certpath.getCertificates().toArray(new X509Certificate[0]);
@ -111,7 +109,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
if (msg != null && strCert.equals(msg.getCredentials())) {
DeviceProfile deviceProfile = msg.getDeviceProfile();
if (msg.hasDeviceInfo() && deviceProfile != null) {
tbCoapDtlsSessionInMemoryStorage.put(session.getSessionIdentifier().toString(), new TbCoapDtlsSessionInfo(msg, deviceProfile));
tbCoapDtlsSessionInMemoryStorage.put(remotePeer, new TbCoapDtlsSessionInfo(msg, deviceProfile));
}
break;
}
@ -120,8 +118,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
CertificateExpiredException |
CertificateNotYetValidException e) {
log.error(e.getMessage(), e);
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE,
session.getPeer());
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE);
throw new HandshakeException("Certificate chain could not be validated", alert);
}
}
@ -141,8 +138,8 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri
public void setResultHandler(HandshakeResultHandler resultHandler) {
}
public ConcurrentMap<String, TbCoapDtlsSessionInfo> getTbCoapDtlsSessionIdsMap() {
return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionIdMap();
public ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> getTbCoapDtlsSessionsMap() {
return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionsMap();
}
public void evictTimeoutSessions() {

View File

@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -25,7 +26,7 @@ import java.util.concurrent.ConcurrentMap;
@Data
public class TbCoapDtlsSessionInMemoryStorage {
private final ConcurrentMap<String, TbCoapDtlsSessionInfo> dtlsSessionIdMap = new ConcurrentHashMap<>();
private final ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> dtlsSessionsMap = new ConcurrentHashMap<>();
private long dtlsSessionInactivityTimeout;
private long dtlsSessionReportTimeout;
@ -35,14 +36,14 @@ public class TbCoapDtlsSessionInMemoryStorage {
this.dtlsSessionReportTimeout = dtlsSessionReportTimeout;
}
public void put(String dtlsSessionId, TbCoapDtlsSessionInfo dtlsSessionInfo) {
log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", dtlsSessionId, dtlsSessionInfo.getLastActivityTime());
dtlsSessionIdMap.putIfAbsent(dtlsSessionId, dtlsSessionInfo);
public void put(InetSocketAddress remotePeer, TbCoapDtlsSessionInfo dtlsSessionInfo) {
log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", remotePeer, dtlsSessionInfo.getLastActivityTime());
dtlsSessionsMap.putIfAbsent(remotePeer, dtlsSessionInfo);
}
public void evictTimeoutSessions() {
long expTime = System.currentTimeMillis() - dtlsSessionInactivityTimeout;
dtlsSessionIdMap.entrySet().removeIf(entry -> {
dtlsSessionsMap.entrySet().removeIf(entry -> {
if (entry.getValue().getLastActivityTime() < expTime) {
log.trace("DTLS session was removed from in-memory store: [{}]", entry.getKey());
return true;

View File

@ -16,9 +16,13 @@
package org.thingsboard.server.coapserver;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.elements.config.CertificateAuthenticationMode;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
@ -26,17 +30,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.ResourceUtils;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.config.ssl.SslCredentials;
import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.util.Collections;
@Slf4j
@ -75,15 +76,14 @@ public class TbCoapDtlsSettings {
@Autowired
private TbServiceInfoProvider serviceInfoProvider;
public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException {
DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder();
public DtlsConnectorConfig dtlsConnectorConfig(Configuration configuration) throws UnknownHostException {
DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(configuration);
configBuilder.setAddress(getInetSocketAddress());
SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials();
SslContextUtil.Credentials serverCredentials =
new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain());
configBuilder.setServerOnly(true);
configBuilder.setClientAuthenticationRequired(false);
configBuilder.setClientAuthenticationWanted(true);
configBuilder.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY);
configBuilder.set(DtlsConfig.DTLS_CLIENT_AUTHENTICATION_MODE, CertificateAuthenticationMode.WANTED);
configBuilder.setAdvancedCertificateVerifier(
new TbCoapDtlsCertificateVerifier(
transportService,
@ -93,8 +93,8 @@ public class TbCoapDtlsSettings {
skipValidityCheckForClientCert
)
);
configBuilder.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(),
Collections.singletonList(CertificateType.X_509));
configBuilder.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(),
Collections.singletonList(CertificateType.X_509)));
return configBuilder.build();
}

View File

@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.coap.OptionSet;
import org.eclipse.californium.core.network.Exchange;
import org.eclipse.californium.core.server.DelivererException;
import org.eclipse.californium.core.server.ServerMessageDeliverer;
import org.eclipse.californium.core.server.resources.Resource;
import org.springframework.util.CollectionUtils;
@ -32,7 +33,7 @@ public class TbCoapServerMessageDeliverer extends ServerMessageDeliverer {
}
@Override
protected Resource findResource(Exchange exchange) {
protected Resource findResource(Exchange exchange) throws DelivererException {
validateUriPath(exchange);
return findResource(exchange.getRequest().getOptions().getUriPath());
}

View File

@ -30,7 +30,6 @@ import org.thingsboard.server.coapserver.TbCoapDtlsSessionInfo;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.msg.session.FeatureType;
@ -48,6 +47,7 @@ import org.thingsboard.server.transport.coap.callback.ToServerRpcSyncSessionCall
import org.thingsboard.server.transport.coap.client.CoapClientContext;
import org.thingsboard.server.transport.coap.client.TbCoapClientState;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Optional;
import java.util.Random;
@ -56,6 +56,8 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.eclipse.californium.elements.DtlsEndpointContext.KEY_SESSION_ID;
@Slf4j
public class CoapTransportResource extends AbstractCoapTransportResource {
private static final int ACCESS_TOKEN_POSITION = 3;
@ -64,9 +66,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
private static final int FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST = 3;
private static final int REQUEST_ID_POSITION_CERTIFICATE_REQUEST = 4;
private static final String DTLS_SESSION_ID_KEY = "DTLS_SESSION_ID";
private final ConcurrentMap<String, TbCoapDtlsSessionInfo> dtlsSessionIdMap;
private final ConcurrentMap<InetSocketAddress, TbCoapDtlsSessionInfo> dtlsSessionsMap;
private final long timeout;
private final CoapClientContext clients;
@ -74,7 +75,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
super(ctx, name);
this.setObservable(true); // enable observing
this.addObserver(new CoapResourceObserver());
this.dtlsSessionIdMap = coapServerService.getDtlsSessionsMap();
this.dtlsSessionsMap = coapServerService.getDtlsSessionsMap();
this.timeout = coapServerService.getTimeout();
this.clients = ctx.getClientContext();
long sessionReportTimeout = ctx.getSessionReportTimeout();
@ -91,7 +92,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
if (relation == null || relation.isCanceled()) {
return; // because request did not try to establish a relation
}
if (CoAP.ResponseCode.isSuccess(response.getCode())) {
if (response.getCode().isSuccess()) {
if (!relation.isEstablished()) {
relation.setEstablished();
addObserveRelation(relation);
@ -198,10 +199,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
Exchange advanced = exchange.advanced();
Request request = advanced.getRequest();
String dtlsSessionIdStr = request.getSourceContext().get(DTLS_SESSION_ID_KEY);
if (dtlsSessionIdMap != null && StringUtils.isNotEmpty(dtlsSessionIdStr)) {
TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionIdMap
.computeIfPresent(dtlsSessionIdStr, (dtlsSessionId, dtlsSessionInfo) -> {
var dtlsSessionId = request.getSourceContext().get(KEY_SESSION_ID);
if (dtlsSessionsMap != null && dtlsSessionId != null && !dtlsSessionId.isEmpty()) {
TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionsMap
.computeIfPresent(request.getSourceContext().getPeerAddress(), (dtlsSessionIdStr, dtlsSessionInfo) -> {
dtlsSessionInfo.setLastActivityTime(System.currentTimeMillis());
return dtlsSessionInfo;
});

View File

@ -29,6 +29,11 @@ public class TbCoapMessageObserver implements MessageObserver {
private final Consumer<Integer> onAcknowledge;
private final Consumer<Integer> onTimeout;
@Override
public boolean isInternal() {
return false;
}
@Override
public void onRetransmission() {
@ -86,13 +91,18 @@ public class TbCoapMessageObserver implements MessageObserver {
}
@Override
public void onResponseHandlingError(Throwable cause) {
}
@Override
public void onContextEstablished(EndpointContext endpointContext) {
}
@Override
public void onComplete() {
public void onTransferComplete() {
}
}

View File

@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.elements.DtlsEndpointContext;
import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.exception.ConnectorException;
import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
@ -118,7 +120,7 @@ public class SecureClientNoAuth {
String keyStorePassword = args[6];
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder();
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration());
setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword);
DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
SecureClientNoAuth client = new SecureClientNoAuth(dtlsConnector, host, port, accessToken, clientKeys, sharedKeys);
@ -134,7 +136,7 @@ public class SecureClientNoAuth {
keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray());
trustBuilder.setTrustedCertificates(trustedCertificates);
config.setAdvancedCertificateVerifier(trustBuilder.build());
config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509));
config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)));
} catch (GeneralSecurityException e) {
System.err.println("certificates are invalid!");
throw new IllegalArgumentException(e.getMessage());

View File

@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.elements.DtlsEndpointContext;
import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.exception.ConnectorException;
import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
@ -117,7 +119,7 @@ public class SecureClientX509 {
String keyStorePassword = args[5];
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder();
DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration());
setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword);
DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
SecureClientX509 client = new SecureClientX509(dtlsConnector, host, port, clientKeys, sharedKeys);
@ -133,7 +135,7 @@ public class SecureClientX509 {
keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray());
trustBuilder.setTrustedCertificates(trustedCertificates);
config.setAdvancedCertificateVerifier(trustBuilder.build());
config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509));
config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)));
} catch (GeneralSecurityException e) {
System.err.println("certificates are invalid!");
throw new IllegalArgumentException(e.getMessage());

View File

@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager;
import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
@ -36,6 +37,8 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.security.cert.X509Certificate;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig;
@Slf4j
@ -86,10 +89,10 @@ public class LwM2MTransportBootstrapService {
/* Create and Set DTLS Config */
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups());
dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers());
dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES);
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig));
dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, serverConfig.isRecommendedSupportedGroups());
dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, serverConfig.isRecommendedCiphers());
dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES);
/* Set DTLS Config */
builder.setDtlsConfig(dtlsConfig);

View File

@ -16,7 +16,7 @@
package org.thingsboard.server.transport.lwm2m.bootstrap.store;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.request.BootstrapDeleteRequest;
@ -134,18 +134,18 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi
log.info("Object after discover: [{}]", objectLinks);
this.securityInstances = new HashMap<>();
for (Link link : objectLinks) {
if (link.getUrl().startsWith("/0/")) {
if (link.getUriReference().startsWith("/0/")) {
try {
LwM2mPath path = new LwM2mPath(link.getUrl());
LwM2mPath path = new LwM2mPath(link.getUriReference());
if (path.isObjectInstance()) {
if (link.getAttributes().containsKey("ssid")) {
int serverId = Integer.parseInt(link.getAttributes().get("ssid"));
if (link.getLinkParams().containsKey("ssid")) {
int serverId = Integer.parseInt(link.getLinkParams().get("ssid").getUnquoted());
if (!this.securityInstances.containsKey(serverId)) {
this.securityInstances.put(serverId, path.getObjectInstanceId());
} else {
log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId());
}
this.securityInstances.put(Integer.valueOf(link.getAttributes().get("ssid")), path.getObjectInstanceId());
this.securityInstances.put(Integer.valueOf(link.getLinkParams().get("ssid").getUnquoted()), path.getObjectInstanceId());
} else {
if (!this.securityInstances.containsKey(0)) {
this.securityInstances.put(0, path.getObjectInstanceId());
@ -188,10 +188,10 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi
private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) {
Link[] links = response.getObjectLinks();
Arrays.stream(links).forEach(link -> {
LwM2mPath path = new LwM2mPath(link.getUrl());
LwM2mPath path = new LwM2mPath(link.getUriReference());
if (!path.isRoot() && path.getObjectId() < 3) {
if (path.isObject()) {
String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver") : "1.0";
String ver = link.getLinkParams().get("ver") != null ? link.getLinkParams().get("ver").getUnquoted() : "1.0";
this.supportedObjects.put(path.getObjectId(), ver);
}
}

View File

@ -16,31 +16,31 @@
package org.thingsboard.server.transport.lwm2m.config;
import lombok.Getter;
import org.eclipse.leshan.core.LwM2m.Version;
import org.eclipse.leshan.core.LwM2m.LwM2mVersion;
import org.eclipse.leshan.core.request.ContentFormat;
public enum LwM2mVersion {
VERSION_1_0(0, Version.V1_0, ContentFormat.TLV, false),
VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT, true);
public enum TbLwM2mVersion {
VERSION_1_0(0, LwM2mVersion.V1_0, ContentFormat.TLV, false),
VERSION_1_1(1, LwM2mVersion.V1_1, ContentFormat.TEXT, true);
@Getter
private final int code;
@Getter
private final Version version;
private final LwM2mVersion version;
@Getter
private final ContentFormat contentFormat;
@Getter
private final boolean composite;
LwM2mVersion(int code, Version version, ContentFormat contentFormat, boolean composite) {
TbLwM2mVersion(int code, LwM2mVersion version, ContentFormat contentFormat, boolean composite) {
this.code = code;
this.version = version;
this.contentFormat = contentFormat;
this.composite = composite;
}
public static LwM2mVersion fromVersion(Version version) {
for (LwM2mVersion to : LwM2mVersion.values()) {
public static TbLwM2mVersion fromVersion(LwM2mVersion version) {
for (TbLwM2mVersion to : TbLwM2mVersion.values()) {
if (to.version.equals(version)) {
return to;
}
@ -48,8 +48,8 @@ public enum LwM2mVersion {
throw new IllegalArgumentException(String.format("Unsupported typeLwM2mVersion type : %s", version));
}
public static LwM2mVersion fromVersionStr(String versionStr) {
for (LwM2mVersion to : LwM2mVersion.values()) {
public static TbLwM2mVersion fromVersionStr(String versionStr) {
for (TbLwM2mVersion to : TbLwM2mVersion.values()) {
if (to.version.toString().equals(versionStr)) {
return to;
}
@ -57,8 +57,8 @@ public enum LwM2mVersion {
throw new IllegalArgumentException(String.format("Unsupported contentFormatLwM2mVersion version : %s", versionStr));
}
public static LwM2mVersion fromCode(int code) {
for (LwM2mVersion to : LwM2mVersion.values()) {
public static TbLwM2mVersion fromCode(int code) {
for (TbLwM2mVersion to : TbLwM2mVersion.values()) {
if (to.code == code) {
return to;
}

View File

@ -17,19 +17,18 @@ package org.thingsboard.server.transport.lwm2m.secure;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.elements.auth.RawPublicKeyIdentity;
import org.eclipse.californium.elements.util.CertPathUtil;
import org.eclipse.californium.scandium.dtls.AlertMessage;
import org.eclipse.californium.scandium.dtls.CertificateMessage;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.CertificateVerificationResult;
import org.eclipse.californium.scandium.dtls.ConnectionId;
import org.eclipse.californium.scandium.dtls.DTLSSession;
import org.eclipse.californium.scandium.dtls.HandshakeException;
import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;
import org.eclipse.californium.scandium.util.ServerNames;
import org.eclipse.leshan.core.util.SecurityUtil;
import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@ -50,6 +49,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore;
import javax.annotation.PostConstruct;
import javax.security.auth.x500.X500Principal;
import java.net.InetSocketAddress;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
@ -81,18 +81,16 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator;
private final TbMainSecurityStore securityStore;
@SuppressWarnings("deprecation")
private StaticCertificateVerifier staticCertificateVerifier;
private StaticNewAdvancedCertificateVerifier staticCertificateVerifier;
@Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}")
private boolean skipValidityCheckForClientCert;
@Override
public List<CertificateType> getSupportedCertificateType() {
public List<CertificateType> getSupportedCertificateTypes() {
return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY);
}
@SuppressWarnings("deprecation")
@PostConstruct
public void init() {
try {
@ -101,14 +99,14 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
if (config.getTrustSslCredentials() != null) {
trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates();
}
staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates);
staticCertificateVerifier = new StaticNewAdvancedCertificateVerifier(trustedCertificates, new RawPublicKeyIdentity[]{}, null);
} catch (Exception e) {
log.info("Failed to initialize the ");
}
}
@Override
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) {
public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, CertificateMessage message) {
CertPath certChain = message.getCertificateChain();
if (certChain == null) {
//We trust all RPK on this layer, and use TbLwM2MAuthorizer
@ -177,10 +175,9 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
}
if (!x509CredentialsFound) {
if (staticCertificateVerifier != null) {
staticCertificateVerifier.verifyCertificate(message, session);
staticCertificateVerifier.verifyCertificate(cid, serverName, remotePeer, clientUsage, verifySubject, truncateCertificatePath, message);
} else {
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR,
session.getPeer());
AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR);
throw new HandshakeException("x509 verification not enabled!", alert);
}
}

View File

@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.scandium.config.DtlsConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.cipher.CipherSuite;
import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder;
@ -40,6 +41,8 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import javax.annotation.PreDestroy;
import java.security.cert.X509Certificate;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY;
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256;
@ -121,11 +124,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
/* Create DTLS Config */
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(config.getPort(), config.getSecurePort(), config));
dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY);
dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, config.isRecommendedSupportedGroups());
dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, config.isRecommendedCiphers());
dtlsConfig.setServerOnly(true);
dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups());
dtlsConfig.setRecommendedCipherSuitesOnly(config.isRecommendedCiphers());
/* Create credentials */
this.setServerWithCredentials(builder, dtlsConfig);
@ -144,12 +148,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
builder.setCertificateChain(sslCredentials.getCertificateChain());
dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier);
builder.setAuthorizer(authorizer);
dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES);
dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, RPK_OR_X509_CIPHER_SUITES);
} else {
/* by default trust all */
builder.setTrustedCertificates(new X509Certificate[0]);
log.info("Unable to load X509 files for LWM2MServer");
dtlsConfig.setSupportedCipherSuites(PSK_CIPHER_SUITES);
dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, PSK_CIPHER_SUITES);
}
}

View File

@ -15,27 +15,30 @@
*/
package org.thingsboard.server.transport.lwm2m.server;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.core.network.config.NetworkConfigDefaults;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.elements.config.Configuration;
import org.springframework.util.CollectionUtils;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS;
public class LwM2MNetworkConfig {
public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) {
NetworkConfig coapConfig = new NetworkConfig();
coapConfig.setInt(NetworkConfig.Keys.COAP_PORT, serverPortNoSec);
coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, serverSecurePort);
public static Configuration getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) {
Configuration coapConfig = new Configuration();
coapConfig.set(CoapConfig.COAP_PORT, serverPortNoSec);
coapConfig.set(CoapConfig.COAP_SECURE_PORT, serverSecurePort);
/**
Example:Property for large packet:
#NetworkConfig config = new NetworkConfig();
#config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32);
#config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32);
#config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048);
#config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3);
#config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000);
#config.setInt(CoapConfig.MAX_MESSAGE_SIZE,32);
#config.setInt(CoapConfig.PREFERRED_BLOCK_SIZE,32);
#config.setInt(CoapConfig.MAX_RESOURCE_BODY_SIZE,2048);
#config.setInt(CoapConfig.MAX_RETRANSMIT,3);
#config.setInt(CoapConfig.MAX_TRANSMIT_WAIT,120000);
*/
/**
@ -46,14 +49,14 @@ public class LwM2MNetworkConfig {
CoAP client will try to use block mode
or adapt the block size when receiving a 4.13 Entity too large response code
*/
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
coapConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
/**
Property to indicate if the response should always include the Block2 option \
when client request early blockwise negociation but the response can be sent on one packet.
- value of false indicate that the server will respond without block2 option if no further blocks are required.
- value of true indicate that the server will response with block2 option event if no further blocks are required.
*/
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
coapConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
/**
* The maximum amount of time (in milliseconds) allowed between
* transfers of individual blocks in a blockwise transfer before the
@ -62,7 +65,7 @@ public class LwM2MNetworkConfig {
* The default value of this property is
* {@link NetworkConfigDefaults#DEFAULT_BLOCKWISE_STATUS_LIFETIME} = 5 * 60 * 1000; // 5 mins [ms].
*/
coapConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME);
coapConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS);
/**
!!! REQUEST_ENTITY_TOO_LARGE CODE=4.13
The maximum size of a resource body (in bytes) that will be accepted
@ -77,7 +80,7 @@ public class LwM2MNetworkConfig {
The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192
A value of {@code 0} turns off transparent handling of blockwise transfers altogether.
*/
coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
coapConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
/**
The default DTLS response matcher.
Supported values are STRICT, RELAXED, or PRINCIPAL.
@ -88,13 +91,13 @@ public class LwM2MNetworkConfig {
true with address check, (STRICT, UDP) - if port Registration of client is changed - it is bad
- false, without
*/
coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED");
coapConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED);
/**
https://tools.ietf.org/html/rfc7959#section-2.9.3
The block size (number of bytes) to use when doing a blockwise transfer. \
This value serves as the upper limit for block size in blockwise transfers
*/
coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024);
coapConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024);
/**
The maximum payload size (in bytes) that can be transferred in a
single message, i.e. without requiring a blockwise transfer.
@ -102,12 +105,14 @@ public class LwM2MNetworkConfig {
In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol
DEFAULT_VALUE = 1024
*/
coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
coapConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024);
coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10);
coapConfig.set(CoapConfig.MAX_RETRANSMIT, 10);
if (!CollectionUtils.isEmpty(config.getNetworkConfig())) {
config.getNetworkConfig().forEach(p -> coapConfig.setString(p.getKey(), p.getValue()));
Properties networkProps = new Properties();
config.getNetworkConfig().forEach(p -> networkProps.put(p.getKey(), p.getValue()));
coapConfig.add(networkProps);
}
return coapConfig;

View File

@ -16,7 +16,10 @@
package org.thingsboard.server.transport.lwm2m.server;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.observation.CompositeObservation;
import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.observation.SingleObservation;
import org.eclipse.leshan.core.response.ObserveCompositeResponse;
import org.eclipse.leshan.core.response.ObserveResponse;
import org.eclipse.leshan.server.observation.ObservationListener;
import org.eclipse.leshan.server.queue.PresenceListener;
@ -86,26 +89,34 @@ public class LwM2mServerListener {
@Override
public void cancelled(Observation observation) {
log.trace("Canceled Observation {}.", observation.getPath());
//TODO: should be able to use CompositeObservation
log.trace("Canceled Observation {}.", ((SingleObservation)observation).getPath());
}
@Override
public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
public void onResponse(SingleObservation observation, Registration registration, ObserveResponse response) {
if (registration != null) {
service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response);
}
}
@Override
public void onResponse(CompositeObservation observation, Registration registration, ObserveCompositeResponse response) {
throw new RuntimeException("Not implemented yet!");
}
@Override
public void onError(Observation observation, Registration registration, Exception error) {
if (error != null) {
log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage());
//TODO: should be able to use CompositeObservation
log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), ((SingleObservation)observation).getPath(), error.getMessage());
}
}
@Override
public void newObservation(Observation observation, Registration registration) {
log.trace("Successful start newObservation {}.", observation.getPath());
//TODO: should be able to use CompositeObservation
log.trace("Successful start newObservation {}.", ((SingleObservation)observation).getPath());
}
};
}

View File

@ -56,7 +56,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
if (relation == null || relation.isCanceled()) {
return; // because request did not try to establish a relation
}
if (CoAP.ResponseCode.isSuccess(response.getCode())) {
if (response.getCode().isSuccess()) {
if (!relation.isEstablished()) {
relation.setEstablished();

View File

@ -39,7 +39,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion;
import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion;
import java.io.IOException;
import java.io.ObjectInputStream;
@ -423,14 +423,14 @@ public class LwM2mClient implements Serializable {
if (registration == null) {
return ContentFormat.DEFAULT;
} else{
return LwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat();
return TbLwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat();
}
}
static private Set<ContentFormat> clientSupportContentFormat(Registration registration) {
Set<ContentFormat> contentFormats = new HashSet<>();
contentFormats.add(ContentFormat.DEFAULT);
String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")).findFirst().get().getAttributes().get("ct");
String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUriReference().equals("/")).findFirst().get().getLinkParams().get("ct").getUnquoted();
if (code != null) {
Set<ContentFormat> codes = Stream.of(code.replaceAll("\"", "").split(" ", -1))
.map(String::trim)

View File

@ -393,9 +393,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
public Set<String> getSupportedIdVerInClient(LwM2mClient client) {
Set<String> clientObjects = ConcurrentHashMap.newKeySet();
Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
LwM2mPath pathIds = new LwM2mPath(link.getUrl());
LwM2mPath pathIds = new LwM2mPath(link.getUriReference());
if (!pathIds.isRoot()) {
clientObjects.add(convertObjectIdToVersionedId(link.getUrl(), client.getRegistration()));
clientObjects.add(convertObjectIdToVersionedId(link.getUriReference(), client.getRegistration()));
}
});
return (clientObjects.size() > 0) ? clientObjects : null;

View File

@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.LwM2m;
import org.eclipse.leshan.core.attributes.Attribute;
import org.eclipse.leshan.core.attributes.AttributeSet;
@ -29,6 +29,7 @@ import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.observation.SingleObservation;
import org.eclipse.leshan.core.request.CompositeDownlinkRequest;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.CreateRequest;
@ -160,7 +161,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
validateVersionedId(client, request);
LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) {
//TODO: should be able to use CompositeObservation
if (observations.stream().noneMatch(observation -> ((SingleObservation)observation).getPath().equals(resultIds))) {
ObserveRequest downlink;
ContentFormat contentFormat = getReadRequestContentFormat(client, request, modelProvider);
if (resultIds.isResource()) {
@ -183,7 +185,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
@Override
public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback<TbLwM2MObserveAllRequest, Set<String>> callback) {
Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
Set<String> paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
//TODO: should be able to use CompositeObservation
Set<String> paths = observations.stream().map(observation -> ((SingleObservation)observation).getPath().toString()).collect(Collectors.toUnmodifiableSet());
callback.onSuccess(request, paths);
}
@ -620,9 +623,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
}
private static ContentFormat getContentFormatForComplex(LwM2mClient client) {
if (LwM2m.Version.V1_0.equals(client.getRegistration().getLwM2mVersion())) {
if (LwM2m.LwM2mVersion.V1_0.equals(client.getRegistration().getLwM2mVersion())) {
return ContentFormat.TLV;
} else if (LwM2m.Version.V1_1.equals(client.getRegistration().getLwM2mVersion())) {
} else if (LwM2m.LwM2mVersion.V1_1.equals(client.getRegistration().getLwM2mVersion())) {
ContentFormat result = findFirst(client.getClientSupportContentFormats(), null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON);
if (result != null) {
return result;

View File

@ -15,7 +15,7 @@
*/
package org.thingsboard.server.transport.lwm2m.server.downlink;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.CreateRequest;
import org.eclipse.leshan.core.request.DeleteRequest;

View File

@ -15,7 +15,8 @@
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.link.DefaultLinkSerializer;
import org.eclipse.leshan.core.link.LinkSerializer;
import org.eclipse.leshan.core.request.DiscoverRequest;
import org.eclipse.leshan.core.response.DiscoverResponse;
import org.thingsboard.server.common.transport.TransportService;
@ -27,12 +28,14 @@ import java.util.Optional;
public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback<DiscoverRequest, DiscoverResponse> {
private final LinkSerializer serializer = new DefaultLinkSerializer();
public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<DiscoverRequest, DiscoverResponse> callback) {
super(transportService, client, requestMsg, callback);
}
protected Optional<String> serializeSuccessfulResponse(DiscoverResponse response) {
return Optional.of(Link.serialize(response.getObjectLinks()));
return Optional.of(serializer.serialize(response.getObjectLinks()));
}
}

View File

@ -22,10 +22,11 @@ import org.eclipse.leshan.core.Destroyable;
import org.eclipse.leshan.core.Startable;
import org.eclipse.leshan.core.Stoppable;
import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.observation.SingleObservation;
import org.eclipse.leshan.core.request.Identity;
import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.core.util.Validate;
import org.eclipse.leshan.server.californium.observation.ObserveUtil;
import org.eclipse.leshan.core.californium.ObserveUtil;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.redis.RedisRegistrationStore;
import org.eclipse.leshan.server.redis.serialization.IdentitySerDes;
@ -455,7 +456,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
// cancel existing observations for the same path and registration id.
for (Observation obs : getObservations(connection, registrationId)) {
if (observation.getPath().equals(obs.getPath())
//TODO: should be able to use CompositeObservation
if (((SingleObservation)observation).getPath().equals(((SingleObservation)obs).getPath())
&& !Arrays.equals(observation.getId(), obs.getId())) {
removed.add(obs);
unsafeRemoveObservation(connection, registrationId, obs.getId());

View File

@ -30,7 +30,6 @@ import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest;
@ -44,7 +43,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion;
import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion;
import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
@ -236,7 +235,7 @@ public class LwM2MTransportUtil {
public static String convertObjectIdToVersionedId(String path, Registration registration) {
String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
ver = ver != null ? ver : LwM2mVersion.VERSION_1_0.getVersion().toString();
ver = ver != null ? ver : TbLwM2mVersion.VERSION_1_0.getVersion().toString();
try {
String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1) {

View File

@ -68,8 +68,8 @@
<jackson.version>2.12.1</jackson.version>
<fasterxml-classmate.version>1.3.4</fasterxml-classmate.version>
<json-schema-validator.version>2.2.6</json-schema-validator.version>
<californium.version>2.6.1</californium.version>
<leshan.version>2.0.0-M4</leshan.version>
<californium.version>3.0.0</californium.version>
<leshan.version>2.0.0-M5</leshan.version>
<gson.version>2.6.2</gson.version>
<freemarker.version>2.3.30</freemarker.version>
<mail.version>1.6.2</mail.version>