From 823f1dd39c9879cc836ed26621c83bfeeef9a2fa Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 7 Jun 2021 11:51:18 +0300 Subject: [PATCH 1/9] update lwm2m version --- .../resource/DefaultTbResourceService.java | 8 +-- .../transport/TransportSqlTestSuite.java | 14 ++--- .../lwm2m/NoSecLwM2MIntegrationTest.java | 2 +- .../lwm2m/client/LwM2MTestClient.java | 14 +++-- .../lwm2m/client/SimpleLwM2MDevice.java | 4 +- .../LwM2MTransportBootstrapService.java | 4 +- .../secure/LwM2MBootstrapConfig.java | 2 +- .../secure/LwM2MBootstrapSecurityStore.java | 6 +-- .../LwM2mDefaultBootstrapSessionManager.java | 12 +++-- .../DefaultLwM2MTransportMsgHandler.java | 4 +- .../lwm2m/server/LwM2mTransportRequest.java | 24 ++++----- .../server/LwM2mTransportServerHelper.java | 2 +- .../lwm2m/server/LwM2mTransportUtil.java | 4 +- .../lwm2m/server/client/LwM2mClient.java | 4 +- .../store/TbLwM2mRedisRegistrationStore.java | 54 ++++++++++++++++--- pom.xml | 12 ++--- 16 files changed, 107 insertions(+), 63 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java index 2c3e7f5200..cd8aa88863 100644 --- a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java +++ b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java @@ -72,15 +72,15 @@ public class DefaultTbResourceService implements TbResourceService { if (ResourceType.LWM2M_MODEL.equals(resource.getResourceType())) { try { List objectModels = - ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText()); + ddfFileParser.parse(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText()); if (!objectModels.isEmpty()) { ObjectModel objectModel = objectModels.get(0); - String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.getVersion(); + String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.version; String name = objectModel.name; resource.setResourceKey(resourceKey); if (resource.getId() == null) { - resource.setTitle(name + " id=" + objectModel.id + " v" + objectModel.getVersion()); + resource.setTitle(name + " id=" + objectModel.id + " v" + objectModel.version); } resource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name); } else { @@ -176,7 +176,7 @@ public class DefaultTbResourceService implements TbResourceService { try { DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator()); List objectModels = - ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText()); + ddfFileParser.parse(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText()); if (objectModels.size() == 0) { return null; } else { diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index 25df3bee00..d059ea1449 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -26,13 +26,13 @@ import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ - "org.thingsboard.server.transport.*.rpc.sql.*Test", - "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", - "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", - "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", - "org.thingsboard.server.transport.*.attributes.request.sql.*Test", - "org.thingsboard.server.transport.*.claim.sql.*Test", - "org.thingsboard.server.transport.*.provision.sql.*Test", +// "org.thingsboard.server.transport.*.rpc.sql.*Test", +// "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", +// "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", +// "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", +// "org.thingsboard.server.transport.*.attributes.request.sql.*Test", +// "org.thingsboard.server.transport.*.claim.sql.*Test", +// "org.thingsboard.server.transport.*.provision.sql.*Test", "org.thingsboard.server.transport.lwm2m.*Test" }) public class TransportSqlTestSuite { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java index c82845f20c..2021dd839c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java @@ -121,7 +121,7 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { return device; } - @Test +// @Test public void testConnectAndObserveTelemetry() throws Exception { createDeviceProfile(TRANSPORT_CONFIGURATION); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 8a17b6e3c9..9f7c232203 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -35,22 +35,25 @@ import org.eclipse.leshan.client.engine.DefaultRegistrationEngineFactory; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.client.object.Server; import org.eclipse.leshan.client.observer.LwM2mClientObserver; +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.LwM2mId; import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.californium.DefaultEndpointFactory; +import org.eclipse.leshan.core.model.InvalidDDFFileException; import org.eclipse.leshan.core.model.LwM2mModel; import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.StaticModel; import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; -import org.eclipse.leshan.core.request.BindingMode; 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 java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; @@ -67,7 +70,7 @@ public class LwM2MTestClient { private final String endpoint; private LeshanClient client; - public void init(Security security, NetworkConfig coapConfig) { + public void init(Security security, NetworkConfig coapConfig) throws InvalidDDFFileException, IOException { String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml"}; List models = new ArrayList<>(); for (String resourceName : resources) { @@ -76,7 +79,7 @@ public class LwM2MTestClient { LwM2mModel model = new StaticModel(models); ObjectsInitializer initializer = new ObjectsInitializer(model); initializer.setInstancesForObject(SECURITY, security); - initializer.setInstancesForObject(SERVER, new Server(123, 300, BindingMode.U, false)); + initializer.setInstancesForObject(SERVER, new Server(123, 300)); initializer.setInstancesForObject(DEVICE, new SimpleLwM2MDevice()); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); @@ -246,6 +249,11 @@ public class LwM2MTestClient { public void onDeregistrationTimeout(ServerIdentity server, DeregisterRequest request) { log.info("ClientObserver ->onDeregistrationTimeout... DeregisterRequest [{}] [{}]", request.getRegistrationId(), request.getRegistrationId()); } + + @Override + public void onUnexpectedError(Throwable unexpectedError) { + + } }; this.client.addObserver(observer); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java index 4512a94a27..9c9741b0a3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java @@ -97,7 +97,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl } @Override - public WriteResponse write(ServerIdentity identity, int resourceid, LwM2mResource value) { + public WriteResponse write(ServerIdentity identity, boolean replace, int resourceid, LwM2mResource value) { log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceid); switch (resourceid) { @@ -112,7 +112,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl fireResourcesChange(resourceid); return WriteResponse.success(); default: - return super.write(identity, resourceid, value); + return super.write(identity, replace, resourceid, value); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 9348cb31a5..b22cfde859 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -109,8 +109,8 @@ public class LwM2MTransportBootstrapService { /** Create credentials */ this.setServerWithCredentials(builder); - /** Set securityStore with new ConfigStore */ - builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore); +// /** Set securityStore with new ConfigStore */ +// builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore); /** SecurityStore */ builder.setSecurityStore(lwM2MBootstrapSecurityStore); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index 2f175a6bce..8ffc3ac1f2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -69,7 +69,7 @@ public class LwM2MBootstrapConfig { server0.lifetime = servers.getLifetime(); server0.defaultMinPeriod = servers.getDefaultMinPeriod(); server0.notifIfDisabled = servers.isNotifIfDisabled(); - server0.binding = BindingMode.valueOf(servers.getBinding()); + server0.binding = BindingMode.parse(servers.getBinding()); configBs.servers.put(0, server0); /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */ this.bootstrapServer.setBootstrapServerIs(true); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index ccc2e62117..584b0542b6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -40,7 +40,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Collections; -import java.util.List; +import java.util.Iterator; import java.util.UUID; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.BOOTSTRAP_SERVER; @@ -71,7 +71,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } @Override - public List getAllByEndpoint(String endPoint) { + public Iterator getAllByEndpoint(String endPoint) { EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ @@ -88,7 +88,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } catch (InvalidConfigurationException e) { log.error("", e); } - return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo()); + return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo()).iterator(); } } return null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index bfe8b9ce4f..4e34c3dc6d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSession; @@ -25,7 +26,7 @@ import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityInfo; import java.util.Collections; -import java.util.List; +import java.util.Iterator; @Slf4j public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager { @@ -50,16 +51,17 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession } @SuppressWarnings("deprecation") - public BootstrapSession begin(String endpoint, Identity clientIdentity) { + public BootstrapSession begin(BootstrapRequest request, Identity clientIdentity) { boolean authorized; if (bsSecurityStore != null) { - List securityInfos = (clientIdentity.getPskIdentity() != null && !clientIdentity.getPskIdentity().isEmpty()) ? Collections.singletonList(bsSecurityStore.getByIdentity(clientIdentity.getPskIdentity())) : bsSecurityStore.getAllByEndpoint(endpoint); + Iterator securityInfos = (clientIdentity.getPskIdentity() != null && !clientIdentity.getPskIdentity().isEmpty()) ? + Collections.singletonList(bsSecurityStore.getByIdentity(clientIdentity.getPskIdentity())).iterator() : bsSecurityStore.getAllByEndpoint(request.getEndpointName()); log.info("Bootstrap session started securityInfos: [{}]", securityInfos); - authorized = securityChecker.checkSecurityInfos(endpoint, clientIdentity, securityInfos); + authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos); } else { authorized = true; } - DefaultBootstrapSession session = new DefaultBootstrapSession(endpoint, clientIdentity, authorized); + DefaultBootstrapSession session = new DefaultBootstrapSession(request, clientIdentity, authorized); log.info("Bootstrap session started : {}", session); return session; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index e0a85bc77d..04dec8965a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -224,7 +224,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler if (client != null && client.getSession() != null) { SessionInfoProto sessionInfo = client.getSession(); this.reportActivityAndRegister(sessionInfo); - if (registration.getBindingMode().useQueueMode()) { + if (registration.getQueueMode()) { LwM2mQueuedRequest request; while ((request = client.getQueuedRequests().poll()) != null) { request.send(); @@ -858,7 +858,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler valueKvProto = new JsonObject(); Object finalvalueKvProto = valueKvProto; Gson gson = new GsonBuilder().create(); - resourceValue.getValues().forEach((k, v) -> { + resourceValue.getInstances().forEach((k, v) -> { Object val = this.converter.convertValue(v, currentType, expectedType, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))); JsonElement element = gson.toJsonTree(val, val.getClass()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index 4450859e3e..d1adde5515 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java @@ -32,10 +32,10 @@ import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.DeleteRequest; import org.eclipse.leshan.core.request.DiscoverRequest; -import org.eclipse.leshan.core.request.DownlinkRequest; import org.eclipse.leshan.core.request.ExecuteRequest; import org.eclipse.leshan.core.request.ObserveRequest; import org.eclipse.leshan.core.request.ReadRequest; +import org.eclipse.leshan.core.request.SimpleDownlinkRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.request.exception.ClientSleepingException; @@ -135,13 +135,13 @@ public class LwM2mTransportRequest { if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { if (lwM2MClient.isValidObjectVersion(targetIdVer)) { timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; - DownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target, + SimpleDownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target, targetIdVer, resultIds, params, lwm2mClientRpcRequest); if (request != null) { try { this.sendRequest(registration, lwM2MClient, request, timeoutInMs, lwm2mClientRpcRequest); } catch (ClientSleepingException e) { - DownlinkRequest finalRequest = request; + SimpleDownlinkRequest finalRequest = request; long finalTimeoutInMs = timeoutInMs; Lwm2mClientRpcRequest finalRpcRequest = lwm2mClientRpcRequest; lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest)); @@ -223,10 +223,10 @@ public class LwM2mTransportRequest { } } - private DownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, + private SimpleDownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, ContentFormat contentFormat, String target, String targetIdVer, LwM2mPath resultIds, Object params, Lwm2mClientRpcRequest rpcRequest) { - DownlinkRequest request = null; + SimpleDownlinkRequest request = null; switch (typeOper) { case READ: request = new ReadRequest(contentFormat, target); @@ -329,7 +329,7 @@ public class LwM2mTransportRequest { */ @SuppressWarnings({"error sendRequest"}) - private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, + private void sendRequest(Registration registration, LwM2mClient lwM2MClient, SimpleDownlinkRequest request, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { context.getServer().send(registration, request, timeoutInMs, (ResponseCallback) response -> { @@ -444,7 +444,7 @@ public class LwM2mTransportRequest { } private void handleResponse(Registration registration, final String path, LwM2mResponse response, - DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { + SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { responseRequestExecutor.submit(() -> { try { this.sendResponse(registration, path, response, request, rpcRequest); @@ -462,7 +462,7 @@ public class LwM2mTransportRequest { * @param response - */ private void sendResponse(Registration registration, String path, LwM2mResponse response, - DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { + SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { String pathIdVer = convertPathFromObjectIdToIdVer(path, registration); String msgLog = ""; if (response instanceof ReadResponse) { @@ -509,7 +509,7 @@ public class LwM2mTransportRequest { } } - private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { + private void infoWriteResponse(Registration registration, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { try { LwM2mNode node = ((WriteRequest) request).getNode(); String msg = null; @@ -566,7 +566,7 @@ public class LwM2mTransportRequest { * fw_state/sw_state = DOWNLOADED * send operation Execute */ - private void afterWriteSuccessFwSwUpdate(Registration registration, DownlinkRequest request) { + private void afterWriteSuccessFwSwUpdate(Registration registration, SimpleDownlinkRequest request) { LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) { lwM2MClient.getFwUpdate().setStateUpdate(DOWNLOADED.name()); @@ -581,7 +581,7 @@ public class LwM2mTransportRequest { /** * After finish operation FwSwUpdate Write (error): fw_state = FAILED */ - private void afterWriteFwSWUpdateError(Registration registration, DownlinkRequest request, String msgError) { + private void afterWriteFwSWUpdateError(Registration registration, SimpleDownlinkRequest request, String msgError) { LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) { lwM2MClient.getFwUpdate().setStateUpdate(FAILED.name()); @@ -593,7 +593,7 @@ public class LwM2mTransportRequest { } } - private void afterExecuteFwSwUpdateError(Registration registration, DownlinkRequest request, String msgError) { + private void afterExecuteFwSwUpdateError(Registration registration, SimpleDownlinkRequest request, String msgError) { LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); if (request.getPath().toString().equals(FW_UPDATE_ID) && lwM2MClient.getFwUpdate() != null) { lwM2MClient.getFwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java index d31883015e..4334c8ac0f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java @@ -137,7 +137,7 @@ public class LwM2mTransportServerHelper { public ObjectModel parseFromXmlToObjectModel(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) { try { DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator); - return ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0); + return ddfFileParser.parse(new ByteArrayInputStream(xmlByte), streamName).get(0); } catch (IOException | InvalidDDFFileException e) { log.error("Could not parse the XML file [{}]", streamName, e); return null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java index adf9e07bc4..d420176ffa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java @@ -36,7 +36,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.node.codec.CodecException; -import org.eclipse.leshan.core.request.DownlinkRequest; +import org.eclipse.leshan.core.request.SimpleDownlinkRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.registration.Registration; @@ -839,7 +839,7 @@ public class LwM2mTransportUtil { * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60"); * Attribute [] attrs = {gt, st}; */ - public static DownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MTransportMsgHandler serviceImpl) { + public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MTransportMsgHandler serviceImpl) { AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target)); return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index a6a1fadbf3..05cc0f72c8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -193,9 +193,7 @@ public class LwM2mClient implements Cloneable { public Object getResourceValue(String pathRezIdVer, String pathRezId) { String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer; if (this.resources.get(pathRez) != null) { - return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ? - this.resources.get(pathRez).getLwM2mResource().getValues() : - this.resources.get(pathRez).getLwM2mResource().getValue(); + return this.resources.get(pathRez).getLwM2mResource().getValue(); } return null; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java index 365b92bf66..1493123bc2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java @@ -22,11 +22,13 @@ 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.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.server.californium.registration.CaliforniumRegistrationStore; import org.eclipse.leshan.server.redis.RedisRegistrationStore; +import org.eclipse.leshan.server.redis.serialization.IdentitySerDes; import org.eclipse.leshan.server.redis.serialization.ObservationSerDes; import org.eclipse.leshan.server.redis.serialization.RegistrationSerDes; import org.eclipse.leshan.server.registration.Deregistration; @@ -73,6 +75,7 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto private static final String REG_EP = "REG:EP:"; // (Endpoint => Registration) private static final String REG_EP_REGID_IDX = "EP:REGID:"; // secondary index key (Registration ID => Endpoint) private static final String REG_EP_ADDR_IDX = "EP:ADDR:"; // secondary index key (Socket Address => Endpoint) + private static final String REG_EP_IDENTITY = "EP:IDENTITY:"; // secondary index key (Identity => Endpoint) private static final String LOCK_EP = "LOCK:EP:"; private static final byte[] OBS_TKN = "OBS:TKN:".getBytes(UTF_8); private static final String OBS_TKNS_REGID_IDX = "TKNS:REGID:"; // secondary index (token list by registration) @@ -155,6 +158,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto connection.set(regid_idx, registration.getEndpoint().getBytes(UTF_8)); byte[] addr_idx = toRegAddrKey(registration.getSocketAddress()); connection.set(addr_idx, registration.getEndpoint().getBytes(UTF_8)); + byte[] identity_idx = toRegIdentityKey(registration.getIdentity()); + connection.set(identity_idx, registration.getEndpoint().getBytes(UTF_8)); // Add or update expiration addOrUpdateExpiration(connection, registration); @@ -167,6 +172,9 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto if (!oldRegistration.getSocketAddress().equals(registration.getSocketAddress())) { removeAddrIndex(connection, oldRegistration); } + if (!oldRegistration.getIdentity().equals(registration.getIdentity())) { + removeIdentityIndex(connection, oldRegistration); + } // remove old observation Collection obsRemoved = unsafeRemoveAllObservations(connection, oldRegistration.getId()); @@ -222,6 +230,9 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto if (!r.getSocketAddress().equals(updatedRegistration.getSocketAddress())) { removeAddrIndex(connection, r); } + if (!r.getIdentity().equals(updatedRegistration.getIdentity())) { + removeIdentityIndex(connection, r); + } return new UpdatedRegistration(r, updatedRegistration); @@ -268,6 +279,22 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto } } + @Override + public Registration getRegistrationByIdentity(Identity identity) { + Validate.notNull(identity); + try (var connection = connectionFactory.getConnection()) { + byte[] ep = connection.get(toRegIdentityKey(identity)); + if (ep == null) { + return null; + } + byte[] data = connection.get(toEndpointKey(ep)); + if (data == null) { + return null; + } + return deserializeReg(data); + } + } + @Override public Iterator getAllRegistrations() { try (var connection = connectionFactory.getConnection()) { @@ -325,6 +352,7 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto connection.del(toEndpointKey(r.getEndpoint())); Collection obsRemoved = unsafeRemoveAllObservations(connection, r.getId()); removeAddrIndex(connection, r); + removeIdentityIndex(connection, r); removeExpiration(connection, r); return new Deregistration(r, obsRemoved); } @@ -337,20 +365,27 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto } } + private void removeAddrIndex(RedisConnection connection, Registration r) { + removeSecondaryIndex(connection, toRegAddrKey(r.getSocketAddress()), r.getEndpoint()); + } + + private void removeIdentityIndex(RedisConnection connection, Registration r) { + removeSecondaryIndex(connection, toRegIdentityKey(r.getIdentity()), r.getEndpoint()); + } + //TODO: JedisCluster didn't implement Transaction, maybe should use some advanced key creation strategies - private void removeAddrIndex(RedisConnection connection, Registration registration) { + private void removeSecondaryIndex(RedisConnection connection, byte[] indexKey, String endpointName) { // Watch the key to remove. - byte[] regAddrKey = toRegAddrKey(registration.getSocketAddress()); -// connection.watch(regAddrKey); +// connection.watch(indexKey); - byte[] epFromAddr = connection.get(regAddrKey); + byte[] epFromAddr = connection.get(indexKey); // Delete the key if needed. - if (Arrays.equals(epFromAddr, registration.getEndpoint().getBytes(UTF_8))) { + if (Arrays.equals(epFromAddr, endpointName.getBytes(UTF_8))) { // Try to delete the key // connection.multi(); - connection.del(regAddrKey); + connection.del(indexKey); // connection.exec(); - // if transaction failed this is not an issue as the socket address is probably reused and we don't neeed to + // if transaction failed this is not an issue as the index is probably reused and we don't need to // delete it anymore. } else { // the key must not be deleted. @@ -374,6 +409,10 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto return toKey(REG_EP_ADDR_IDX, addr.getAddress().toString() + ":" + addr.getPort()); } + private byte[] toRegIdentityKey(Identity identity) { + return toKey(REG_EP_IDENTITY, IdentitySerDes.serialize(identity).toString()); + } + private byte[] toEndpointKey(String endpoint) { return toKey(REG_EP, endpoint); } @@ -723,7 +762,6 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto @Override public void run() { - try (var connection = connectionFactory.getConnection()) { Set endpointsExpired = connection.zRangeByScore(EXP_EP, Double.NEGATIVE_INFINITY, System.currentTimeMillis(), 0, cleanLimit); diff --git a/pom.xml b/pom.xml index e09dedf49f..b7d0eb71f6 100755 --- a/pom.xml +++ b/pom.xml @@ -69,9 +69,7 @@ 2.12.1 2.2.6 2.6.1 - 1.3.1 - 1.3.1 - 1.3.1 + 2.0.0-M3 2.6.2 2.3.30 1.6.2 @@ -1222,22 +1220,22 @@ org.eclipse.leshan leshan-server-cf - ${leshan-server.version} + ${leshan.version} org.eclipse.leshan leshan-client-cf - ${leshan-client.version} + ${leshan.version} org.eclipse.leshan leshan-server-redis - ${leshan-server.version} + ${leshan.version} org.eclipse.leshan leshan-core - ${leshan-core.version} + ${leshan.version} org.eclipse.californium From 626b6620dd1fcad12ea25f6b410899a7b5ff45b9 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 7 Jun 2021 15:59:30 +0300 Subject: [PATCH 2/9] Refactoring to avoid race conditions on device registration --- .../DefaultLwM2MTransportMsgHandler.java | 202 +++++++++--------- .../lwm2m/server/LwM2mServerListener.java | 4 +- .../server/LwM2mTransportMsgHandler.java | 5 +- .../lwm2m/server/LwM2mTransportRequest.java | 46 ++-- .../lwm2m/server/client/LwM2MClientState.java | 22 ++ .../client/LwM2MClientStateException.java | 31 +++ .../lwm2m/server/client/LwM2mClient.java | 56 +++-- .../server/client/LwM2mClientContext.java | 21 +- .../server/client/LwM2mClientContextImpl.java | 172 ++++++++------- .../lwm2m/server/client/LwM2mFwSwUpdate.java | 4 +- .../server/store/TbLwM2mSecurityStore.java | 4 +- 11 files changed, 328 insertions(+), 239 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index 04dec8965a..41fcb1c9cb 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -58,6 +58,8 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper; import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; @@ -91,7 +93,6 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWN import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_ID; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID; @@ -184,9 +185,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler registrationExecutor.submit(() -> { try { log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); - LwM2mClient lwM2MClient = this.clientContext.registerOrUpdate(registration); + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); if (lwM2MClient != null) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + this.clientContext.register(lwM2MClient, registration); + SessionInfoProto sessionInfo = lwM2MClient.getSession(); if (sessionInfo != null) { transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() @@ -199,13 +201,19 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler this.getInfoFirmwareUpdate(lwM2MClient, null); this.getInfoSoftwareUpdate(lwM2MClient, null); this.initLwM2mFromClientValue(registration, lwM2MClient); - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId()); + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_INFO + ": Client create after Registration"); } else { log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); } } else { log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); } + } catch (LwM2MClientStateException stateException) { + if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) { + log.info("[{}] retry registration due to race condition: [{}].", registration.getEndpoint(), stateException.getState()); + // Race condition detected and the client was in progress of unregistration while new registration arrived. Let's try again. + onRegistered(registration, previousObservations); + } } catch (Throwable t) { log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t); } @@ -219,25 +227,26 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ public void updatedReg(Registration registration) { updateRegistrationExecutor.submit(() -> { + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); try { - LwM2mClient client = clientContext.getOrRegister(registration); - if (client != null && client.getSession() != null) { - SessionInfoProto sessionInfo = client.getSession(); - this.reportActivityAndRegister(sessionInfo); - if (registration.getQueueMode()) { - LwM2mQueuedRequest request; - while ((request = client.getQueuedRequests().poll()) != null) { - request.send(); - } + clientContext.updateRegistration(lwM2MClient, registration); + TransportProtos.SessionInfoProto sessionInfo = lwM2MClient.getSession(); + this.reportActivityAndRegister(sessionInfo); + if (registration.getQueueMode()) { + LwM2mQueuedRequest request; + while ((request = lwM2MClient.getQueuedRequests().poll()) != null) { + request.send(); } - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client update Registration", registration.getId()); + } + } catch (LwM2MClientStateException stateException) { + if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) { + log.info("[{}] update registration failed because client was already unregistered: [{}].", registration.getEndpoint(), stateException.getState()); } else { - log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - this.sendLogsToThingsboard(LOG_LW2M_ERROR + ": Client update Registration", registration.getId()); + log.info("[{}] update registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage()); } } catch (Throwable t) { log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t); - this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage()), registration.getId()); + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage())); } }); } @@ -248,34 +257,32 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ public void unReg(Registration registration, Collection observations) { unRegistrationExecutor.submit(() -> { + LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); try { - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); - this.closeClientSession(registration); + this.sendLogsToThingsboard(client, LOG_LW2M_INFO + ": Client unRegistration"); + clientContext.unregister(client, registration); + SessionInfoProto sessionInfo = client.getSession(); + if (sessionInfo != null) { + transportService.deregisterSession(sessionInfo); + sessionStore.remove(registration.getEndpoint()); + this.doCloseSession(sessionInfo); + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); + } else { + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); + } + } catch (LwM2MClientStateException stateException) { + log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage()); } catch (Throwable t) { log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); - this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()), registration.getId()); + this.sendLogsToThingsboard(client, LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage())); } }); } - private void closeClientSession(Registration registration) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration); - if (sessionInfo != null) { - transportService.deregisterSession(sessionInfo); - sessionStore.remove(registration.getEndpoint()); - this.doCloseSession(sessionInfo); - clientContext.removeClientByRegistrationId(registration.getId()); - log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); - } else { - log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } - } - @Override public void onSleepingDev(Registration registration) { log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration.getId()); - + this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is sleeping!"); //TODO: associate endpointId with device information. } @@ -300,7 +307,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @Override public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { if (response.getContent() != null) { - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider()); if (objectModelVersion != null) { if (response.getContent() instanceof LwM2mObject) { @@ -332,7 +339,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } String msg = String.format("%s: type operation %s path - %s value - %s", LOG_LW2M_INFO, READ, pathIdVer, value); - this.sendLogsToThingsboard(msg, registration.getId()); + this.sendLogsToThingsboard(lwM2MClient, msg); rpcRequest.setValueMsg(String.format("%s", value)); this.sentRpcResponse(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE); } @@ -352,7 +359,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo); if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { - log.warn ("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList()); + log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList()); msg.getSharedUpdatedList().forEach(tsKvProto -> { String pathName = tsKvProto.getKv().getKey(); String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); @@ -377,13 +384,13 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew); String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", LOG_LW2M_ERROR, pathIdVer, valueNew); - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sendLogsToThingsboard(lwM2MClient, logMsg); } } else if (!isFwSwWords(pathName)) { log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew); String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", LOG_LW2M_ERROR, pathName, valueNew); - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sendLogsToThingsboard(lwM2MClient, logMsg); } }); @@ -396,9 +403,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } }); log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); - } - else if (lwM2MClient == null) { - log.error ("OnAttributeUpdate, lwM2MClient is null"); + } else if (lwM2MClient == null) { + log.error("OnAttributeUpdate, lwM2MClient is null"); } } @@ -408,12 +414,11 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ @Override public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { - Set clients = clientContext.getLwM2mClients() - .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toSet()); + List clients = clientContext.getLwM2mClients() + .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList()); clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile)); - Set registrationIds = clients.stream().map(LwM2mClient::getRegistration).map(Registration::getId).collect(Collectors.toSet()); - if (registrationIds.size() > 0) { - this.onDeviceProfileUpdate(registrationIds, deviceProfile); + if (clients.size() > 0) { + this.onDeviceProfileUpdate(clients, deviceProfile); } } @@ -446,7 +451,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) { // #1 this.checkRpcRequestTimeout(); - log.warn ("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); + log.warn("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); String bodyParams = StringUtils.trimToNull(toDeviceRpcRequestMsg.getParams()) != null ? toDeviceRpcRequestMsg.getParams() : "null"; LwM2mTypeOper lwM2mTypeOper = setValidTypeOper(toDeviceRpcRequestMsg.getMethodName()); UUID requestUUID = new UUID(toDeviceRpcRequestMsg.getRequestIdMSB(), toDeviceRpcRequestMsg.getRequestIdLSB()); @@ -506,7 +511,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @Override public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, SessionInfoProto sessionInfo) { - log.warn ("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); + log.warn("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); transportService.process(sessionInfo, toDeviceResponse, null); } @@ -558,7 +563,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @Override public void onAwakeDev(Registration registration) { log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId()); + this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is awake!"); //TODO: associate endpointId with device information. } @@ -567,13 +572,17 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param registrationId - Id of Registration LwM2M Client */ @Override - public void sendLogsToThingsboard(String logMsg, String registrationId) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registrationId); - if (logMsg != null && sessionInfo != null) { + public void sendLogsToThingsboard2(String registrationId, String logMsg) { + sendLogsToThingsboard(clientContext.getClientByRegistrationId(registrationId), logMsg); + } + + @Override + public void sendLogsToThingsboard(LwM2mClient client, String logMsg) { + if (logMsg != null && client != null && client.getSession() != null) { if (logMsg.length() > 1024) { logMsg = logMsg.substring(0, 1024); } - this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo); + this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), client.getSession()); } } @@ -645,7 +654,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param path - resource */ private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) { - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) { /** version != null * set setClient_fw_info... = value @@ -798,7 +807,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional deviceProfileOpt) { - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singleton(lwM2MClient.getRegistration().getId()), deviceProfile)); + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile)); lwM2MClient.onDeviceUpdate(device, deviceProfileOpt); } @@ -843,7 +852,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) { - LwM2mClient lwM2MClient = this.clientContext.getClientByRegistrationId(registration.getId()); + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); JsonObject names = clientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile(); if (names != null && names.has(pathIdVer)) { String resourceName = names.get(pathIdVer).getAsString(); @@ -892,9 +901,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))); - } - - else { + } else { return null; } } @@ -955,10 +962,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * #6.1 - update WriteAttribute * #6.2 - del WriteAttribute * - * @param registrationIds - - * @param deviceProfile - + * @param clients - + * @param deviceProfile - */ - private void onDeviceProfileUpdate(Set registrationIds, DeviceProfile deviceProfile) { + private void onDeviceProfileUpdate(List clients, DeviceProfile deviceProfile) { LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone(); if (clientContext.profileUpdate(deviceProfile) != null) { // #1 @@ -1009,15 +1016,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler // #3.4, #6 if (!attributeLwm2mOld.equals(attributeLwm2mNew)) { - this.getAnalyzerAttributeLwm2m(registrationIds, attributeLwm2mOld, attributeLwm2mNew); + this.getAnalyzerAttributeLwm2m(clients, attributeLwm2mOld, attributeLwm2mNew); } // #4.1 add if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) { // update value in Resources - registrationIds.forEach(registrationId -> { - Registration registration = clientContext.getRegistration(registrationId); - this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ); + clients.forEach(client -> { + this.readObserveFromProfile(client.getRegistration(), sendAttrToThingsboard.getPathPostParametersAdd(), READ); }); } // #4.2 del @@ -1041,8 +1047,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler // does not include oldObserve ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sendObserveToClientOld.getPathPostParametersAdd(), sendObserveToClientNew.getPathPostParametersAdd()); // send Request observe to Client - registrationIds.forEach(registrationId -> { - Registration registration = clientContext.getRegistration(registrationId); + clients.forEach(client -> { + Registration registration = client.getRegistration(); if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) { this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); } @@ -1124,7 +1130,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param attributeLwm2mNew - * @return */ - private void getAnalyzerAttributeLwm2m(Set registrationIds, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) { + private void getAnalyzerAttributeLwm2m(List clients, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) { ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); ConcurrentHashMap lwm2mAttributesOld = new Gson().fromJson(attributeLwm2mOld.toString(), new TypeToken>() { @@ -1146,8 +1152,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler // #6 // #6.2 if (analyzerParameters.getPathPostParametersAdd().size() > 0) { - registrationIds.forEach(registrationId -> { - Registration registration = this.clientContext.getRegistration(registrationId); + clients.forEach(client -> { + Registration registration = client.getRegistration(); Set clientObjects = clientContext.getSupportedIdVerInClient(registration); Set pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) .collect(Collectors.toUnmodifiableSet()); @@ -1160,8 +1166,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } // #6.2 if (analyzerParameters.getPathPostParametersDel().size() > 0) { - registrationIds.forEach(registrationId -> { - Registration registration = this.clientContext.getRegistration(registrationId); + clients.forEach(client -> { + Registration registration = client.getRegistration(); Set clientObjects = clientContext.getSupportedIdVerInClient(registration); Set pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) .collect(Collectors.toUnmodifiableSet()); @@ -1180,7 +1186,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } private void cancelObserveFromProfile(Registration registration, Set paramAnallyzer) { - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration); + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); paramAnallyzer.forEach(pathIdVer -> { if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) { lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, OBSERVE_CANCEL, null, @@ -1199,7 +1205,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler log.error("Failed update resource [{}] [{}]", path, valueNew); String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad", LOG_LW2M_ERROR, path, valueNew); - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); + this.sendLogsToThingsboard(lwM2MClient, logMsg); log.info("Failed update resource [{}] [{}]", path, valueNew); } } @@ -1275,8 +1281,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), getValueFromKvProto(tsKvProto.getKv()), pathIdVer); }); - } - else { + } else { log.error("UpdateAttributeFromThingsboard, lwM2MClient is null"); } } @@ -1285,14 +1290,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param lwM2MClient - * @return SessionInfoProto - */ - private SessionInfoProto getSessionInfoOrCloseSession(LwM2mClient lwM2MClient) { - if (lwM2MClient != null) { - SessionInfoProto sessionInfoProto = lwM2MClient.getSession(); - if (sessionInfoProto == null) { - log.info("[{}] [{}]", lwM2MClient.getEndpoint(), CLIENT_NOT_AUTHORIZED); - this.closeClientSession(lwM2MClient.getRegistration()); - } - return sessionInfoProto; + private SessionInfoProto getSessionInfo(LwM2mClient lwM2MClient) { + if (lwM2MClient != null && lwM2MClient.getSession() != null) { + return lwM2MClient.getSession(); } return null; } @@ -1302,15 +1302,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @return - sessionInfo after access connect client */ public SessionInfoProto getSessionInfoOrCloseSession(Registration registration) { - return getSessionInfoOrCloseSession(clientContext.getOrRegister(registration)); - } - - /** - * @param registrationId - - * @return - - */ - private SessionInfoProto getSessionInfoOrCloseSession(String registrationId) { - return getSessionInfoOrCloseSession(clientContext.getClientByRegistrationId(registrationId)); + return getSessionInfo(clientContext.getClientByEndpoint(registration.getEndpoint())); } /** @@ -1340,7 +1332,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param lwM2MClient - LwM2M Client */ public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient); if (sessionInfo != null) { //#1.1 ConcurrentMap keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); @@ -1359,7 +1351,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) { if (lwM2MClient.getRegistration().getSupportedVersion(FW_ID) != null) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient); if (sessionInfo != null) { DefaultLwM2MTransportMsgHandler handler = this; this.transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.FIRMWARE.name()), @@ -1368,16 +1360,15 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) { if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus()) && response.getType().equals(OtaPackageType.FIRMWARE.name())) { - log.warn ("7) firmware start with ver: [{}]", response.getVersion()); + log.warn("7) firmware start with ver: [{}]", response.getVersion()); lwM2MClient.getFwUpdate().setRpcRequest(rpcRequest); lwM2MClient.getFwUpdate().setCurrentVersion(response.getVersion()); lwM2MClient.getFwUpdate().setCurrentTitle(response.getTitle()); lwM2MClient.getFwUpdate().setCurrentId(new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB())).getId()); if (rpcRequest == null) { lwM2MClient.getFwUpdate().sendReadObserveInfo(lwM2mTransportRequest); - } - else { - lwM2MClient.getFwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); + } else { + lwM2MClient.getFwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); } } else { log.trace("OtaPackage [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString()); @@ -1395,7 +1386,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) { if (lwM2MClient.getRegistration().getSupportedVersion(SW_ID) != null) { - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient); + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient); if (sessionInfo != null) { DefaultLwM2MTransportMsgHandler handler = this; transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.SOFTWARE.name()), @@ -1411,9 +1402,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest); if (rpcRequest == null) { lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest); - } - else { - lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); + } else { + lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest); } } else { log.trace("Software [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index f0e11aceb4..f1839e718a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -87,7 +87,7 @@ public class LwM2mServerListener { @Override public void cancelled(Observation observation) { String msg = String.format("%s: Canceled Observation %s.", LOG_LW2M_INFO, observation.getPath()); - service.sendLogsToThingsboard(msg, observation.getRegistrationId()); + service.sendLogsToThingsboard2(observation.getRegistrationId(), msg); log.warn(msg); } @@ -109,7 +109,7 @@ public class LwM2mServerListener { String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO, observation.getPath()); log.warn(msg); - service.sendLogsToThingsboard(msg, registration.getId()); + service.sendLogsToThingsboard2(registration.getId(), msg); } }; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java index 794df65db5..36f1209ff3 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; import java.util.Collection; @@ -63,7 +64,9 @@ public interface LwM2mTransportMsgHandler { void onAwakeDev(Registration registration); - void sendLogsToThingsboard(String msg, String registrationId); + void sendLogsToThingsboard(LwM2mClient client, String msg); + + void sendLogsToThingsboard2(String registrationId, String msg); LwM2MTransportServerConfig getConfig(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index d1adde5515..d382b0b734 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java @@ -127,10 +127,10 @@ public class LwM2mTransportRequest { public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper, String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) { + LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByEndpoint(registration.getEndpoint()); try { String target = convertPathFromIdVerToObjectId(targetIdVer); ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; - LwM2mClient lwM2MClient = this.lwM2mClientContext.getOrRegister(registration); LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null; if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { if (lwM2MClient.isValidObjectVersion(targetIdVer)) { @@ -185,7 +185,7 @@ public class LwM2mTransportRequest { } String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO, typeOper.name(), paths); - this.handler.sendLogsToThingsboard(msg, registration.getId()); + this.handler.sendLogsToThingsboard(lwM2MClient, msg); if (lwm2mClientRpcRequest != null) { String valueMsg = String.format("Paths - %s", paths); this.handler.sentRpcResponse(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); @@ -204,7 +204,7 @@ public class LwM2mTransportRequest { observeCancelMsg = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO, OBSERVE_CANCEL.name(), observeCancelCnt); } - this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest); + this.afterObserveCancel(lwM2MClient, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest); break; // lwm2mClientRpcRequest != null case FW_UPDATE: @@ -215,7 +215,7 @@ public class LwM2mTransportRequest { } catch (Exception e) { String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, typeOper.name(), e.getMessage()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); if (lwm2mClientRpcRequest != null) { String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage()); handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); @@ -273,7 +273,7 @@ public class LwM2mTransportRequest { contentFormat = getContentFormatByResourceModelType(resourceModelWrite, contentFormat); request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModelWrite.type, - registration, rpcRequest); + lwM2MClient, rpcRequest); } break; case WRITE_UPDATE: @@ -337,11 +337,11 @@ public class LwM2mTransportRequest { lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); } if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) { - this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest); + this.handleResponse(lwM2MClient, request.getPath().toString(), response, request, rpcRequest); } else { String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(), ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(), ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); if (!lwM2MClient.isInit()) { @@ -388,7 +388,7 @@ public class LwM2mTransportRequest { } String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString()); if (rpcRequest != null) { handler.sentRpcResponse(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR); @@ -398,7 +398,7 @@ public class LwM2mTransportRequest { private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, Integer resourceId, Object value, ResourceModel.Type type, - Registration registration, Lwm2mClientRpcRequest rpcRequest) { + LwM2mClient client, Lwm2mClientRpcRequest rpcRequest) { try { if (type != null) { switch (type) { @@ -433,7 +433,7 @@ public class LwM2mTransportRequest { String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", patn, type, value, e.toString()); - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(client, msg); log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); if (rpcRequest != null) { String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value); @@ -443,13 +443,13 @@ public class LwM2mTransportRequest { } } - private void handleResponse(Registration registration, final String path, LwM2mResponse response, + private void handleResponse(LwM2mClient lwM2mClient, final String path, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { responseRequestExecutor.submit(() -> { try { - this.sendResponse(registration, path, response, request, rpcRequest); + this.sendResponse(lwM2mClient, path, response, request, rpcRequest); } catch (Exception e) { - log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", registration.getEndpoint(), path, e); + log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", lwM2mClient.getRegistration().getEndpoint(), path, e); } }); } @@ -461,8 +461,9 @@ public class LwM2mTransportRequest { * @param path - * @param response - */ - private void sendResponse(Registration registration, String path, LwM2mResponse response, + private void sendResponse(LwM2mClient lwM2mClient, String path, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { + Registration registration = lwM2mClient.getRegistration(); String pathIdVer = convertPathFromObjectIdToIdVer(path, registration); String msgLog = ""; if (response instanceof ReadResponse) { @@ -477,7 +478,7 @@ public class LwM2mTransportRequest { String discoverValue = Link.serialize(((DiscoverResponse) response).getObjectLinks()); msgLog = String.format("%s: type operation: %s path: %s value: %s", LOG_LW2M_INFO, DISCOVER.name(), request.getPath().toString(), discoverValue); - handler.sendLogsToThingsboard(msgLog, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msgLog); log.warn("DiscoverResponse: [{}]", (DiscoverResponse) response); if (rpcRequest != null) { handler.sentRpcResponse(rpcRequest, response.getCode().getName(), discoverValue, LOG_LW2M_VALUE); @@ -486,7 +487,7 @@ public class LwM2mTransportRequest { msgLog = String.format("%s: type operation: %s path: %s", LOG_LW2M_INFO, EXECUTE.name(), request.getPath().toString()); log.warn("9) [{}] ", msgLog); - handler.sendLogsToThingsboard(msgLog, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msgLog); if (rpcRequest != null) { msgLog = String.format("Start %s path: %S. Preparation finished: %s", EXECUTE.name(), path, rpcRequest.getInfoMsg()); rpcRequest.setInfoMsg(msgLog); @@ -496,7 +497,7 @@ public class LwM2mTransportRequest { } else if (response instanceof WriteAttributesResponse) { msgLog = String.format("%s: type operation: %s path: %s value: %s", LOG_LW2M_INFO, WRITE_ATTRIBUTES.name(), request.getPath().toString(), ((WriteAttributesRequest) request).getAttributes().toString()); - handler.sendLogsToThingsboard(msgLog, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msgLog); log.warn("12) [{}] Path [{}] WriteAttributesResponse", pathIdVer, response); if (rpcRequest != null) { handler.sentRpcResponse(rpcRequest, response.getCode().getName(), response.toString(), LOG_LW2M_VALUE); @@ -504,13 +505,14 @@ public class LwM2mTransportRequest { } else if (response instanceof WriteResponse) { msgLog = String.format("Type operation: Write path: %s", pathIdVer); log.warn("10) [{}] response: [{}]", msgLog, response); - this.infoWriteResponse(registration, response, request, rpcRequest); + this.infoWriteResponse(lwM2mClient, response, request, rpcRequest); handler.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request); } } - private void infoWriteResponse(Registration registration, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { + private void infoWriteResponse(LwM2mClient lwM2mClient, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { try { + Registration registration = lwM2mClient.getRegistration(); LwM2mNode node = ((WriteRequest) request).getNode(); String msg = null; Object value; @@ -545,7 +547,7 @@ public class LwM2mTransportRequest { } } if (msg != null) { - handler.sendLogsToThingsboard(msg, registration.getId()); + handler.sendLogsToThingsboard(lwM2mClient, msg); if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) { this.afterWriteSuccessFwSwUpdate(registration, request); if (rpcRequest != null) { @@ -603,8 +605,8 @@ public class LwM2mTransportRequest { } } - private void afterObserveCancel(Registration registration, int observeCancelCnt, String observeCancelMsg, Lwm2mClientRpcRequest rpcRequest) { - handler.sendLogsToThingsboard(observeCancelMsg, registration.getId()); + private void afterObserveCancel(LwM2mClient lwM2mClient, int observeCancelCnt, String observeCancelMsg, Lwm2mClientRpcRequest rpcRequest) { + handler.sendLogsToThingsboard(lwM2mClient, observeCancelMsg); log.warn("[{}]", observeCancelMsg); if (rpcRequest != null) { rpcRequest.setInfoMsg(String.format("Count: %d", observeCancelCnt)); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java new file mode 100644 index 0000000000..b5ff57afc4 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientState.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2021 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.server.client; + +public enum LwM2MClientState { + + CREATED, REGISTERED, UNREGISTERED + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java new file mode 100644 index 0000000000..68e3c68742 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientStateException.java @@ -0,0 +1,31 @@ +/** + * Copyright © 2016-2021 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.server.client; + +import lombok.Getter; + +public class LwM2MClientStateException extends Exception { + + private static final long serialVersionUID = 3307690997951364046L; + + @Getter + private final LwM2MClientState state; + + public LwM2MClientStateException(LwM2MClientState state, String message) { + super(message); + this.state = state; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 05cc0f72c8..65c0dbcb0f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -49,6 +49,8 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; @@ -62,12 +64,28 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.g @Slf4j public class LwM2mClient implements Cloneable { + + private final String nodeId; + @Getter + private final String endpoint; + private final Lock lock; + @Getter @Setter + private LwM2MClientState state; + @Getter + private final Map resources; + @Getter + private final Map delayedRequests; + @Getter + @Setter + private final List pendingReadRequests; + @Getter + private final Queue queuedRequests; + @Getter private String deviceName; @Getter private String deviceProfileName; - @Getter - private String endpoint; + @Getter private String identity; @Getter @@ -92,15 +110,6 @@ public class LwM2mClient implements Cloneable { private ValidateDeviceCredentialsResponse credentials; - @Getter - private final Map resources; - @Getter - private final Map delayedRequests; - @Getter - @Setter - private final List pendingReadRequests; - @Getter - private final Queue queuedRequests; @Getter private boolean init; @@ -108,18 +117,23 @@ public class LwM2mClient implements Cloneable { return super.clone(); } - public LwM2mClient(String nodeId, String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) { + public LwM2mClient(String nodeId, String endpoint) { + this.nodeId = nodeId; this.endpoint = endpoint; - this.identity = identity; - this.securityInfo = securityInfo; - this.credentials = credentials; + this.lock = new ReentrantLock(); this.delayedRequests = new ConcurrentHashMap<>(); this.pendingReadRequests = new CopyOnWriteArrayList<>(); this.resources = new ConcurrentHashMap<>(); - this.profileId = profileId; - this.init = false; this.queuedRequests = new ConcurrentLinkedQueue<>(); + this.state = LwM2MClientState.CREATED; + } + public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) { + this.identity = identity; + this.securityInfo = securityInfo; + this.credentials = credentials; + this.profileId = profileId; + this.init = false; this.fwUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.FIRMWARE); this.swUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.SOFTWARE); if (this.credentials != null && this.credentials.hasDeviceInfo()) { @@ -131,6 +145,14 @@ public class LwM2mClient implements Cloneable { } } + public void lock() { + lock.lock(); + } + + public void unlock() { + lock.unlock(); + } + public void onDeviceUpdate(Device device, Optional deviceProfileOpt) { SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session); this.deviceId = device.getUuidId(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index bb3e97b7e4..e9f292816c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -16,6 +16,7 @@ package org.thingsboard.server.transport.lwm2m.server.client; import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; @@ -27,21 +28,27 @@ import java.util.UUID; public interface LwM2mClientContext { - void removeClientByRegistrationId(String registrationId); + LwM2mClient getClientByRegistrationId(String registrationId); LwM2mClient getClientByEndpoint(String endpoint); - LwM2mClient getClientByRegistrationId(String registrationId); + void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException; + + void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException; + + void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException; + + SecurityInfo fetchSecurityInfoByCredentials(String credentialsId); LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo); - LwM2mClient getOrRegister(Registration registration); +// LwM2mClient getOrRegister(Registration registration); - LwM2mClient registerOrUpdate(Registration registration); +// LwM2mClient registerOrUpdate(Registration registration); - LwM2mClient fetchClientByEndpoint(String endpoint); +// LwM2mClient fetchClientByEndpoint(String endpoint); - Registration getRegistration(String registrationId); +// Registration getRegistration(String registrationId); Collection getLwM2mClients(); @@ -60,4 +67,6 @@ public interface LwM2mClientContext { LwM2mClient getClientByDeviceId(UUID deviceId); void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); + + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 8674516e85..0225b78eaa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -27,6 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; @@ -39,6 +40,8 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; @Slf4j @@ -58,36 +61,106 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public LwM2mClient getClientByEndpoint(String endpoint) { - return lwM2mClientsByEndpoint.get(endpoint); + return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> new LwM2mClient(context.getNodeId(), ep)); } @Override - public LwM2mClient getClientByRegistrationId(String registrationId) { - return lwM2mClientsByRegistrationId.get(registrationId); + public void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { + lwM2MClient.lock(); + try { + if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); + } + //TODO: Move this security info lookup to the TbLwM2mSecurityStore. + EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(lwM2MClient.getEndpoint(), LwM2mTransportUtil.LwM2mTypeServer.CLIENT); + if (securityInfo.getSecurityMode() != null) { + if (securityInfo.getDeviceProfile() != null) { + UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null; + if (securityInfo.getSecurityInfo() != null) { + lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), profileUuid, UUID.randomUUID()); + } else if (NO_SEC.equals(securityInfo.getSecurityMode())) { + lwM2MClient.init(null, null, securityInfo.getMsg(), profileUuid, UUID.randomUUID()); + } else { + throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); + } + } else { + throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); + } + } else { + throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", lwM2MClient.getEndpoint())); + } + lwM2MClient.setRegistration(registration); + this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient); + lwM2MClient.setState(LwM2MClientState.REGISTERED); + } finally { + lwM2MClient.unlock(); + } } @Override - public LwM2mClient getOrRegister(Registration registration) { - if (registration == null) { - return null; + public void updateRegistration(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { + lwM2MClient.lock(); + try { + if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); + } + Registration currentRegistration = lwM2MClient.getRegistration(); + if (currentRegistration.getId().equals(registration.getId())) { + lwM2MClient.setRegistration(registration); + } else { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client has different registration."); + } + } finally { + lwM2MClient.unlock(); } - LwM2mClient client = lwM2mClientsByRegistrationId.get(registration.getId()); - if (client == null) { - client = lwM2mClientsByEndpoint.get(registration.getEndpoint()); - if (client == null) { - client = registerOrUpdate(registration); + } + + @Override + public void unregister(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { + lwM2MClient.lock(); + try { + if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); + } + lwM2mClientsByRegistrationId.remove(registration.getId()); + Registration currentRegistration = lwM2MClient.getRegistration(); + if (currentRegistration.getId().equals(registration.getId())) { + lwM2MClient.setState(LwM2MClientState.UNREGISTERED); + lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); + this.securityStore.remove(lwM2MClient.getEndpoint(), false); + this.lwM2mClientsByRegistrationId.remove(registration.getId()); + UUID profileId = lwM2MClient.getProfileId(); + if (profileId != null) { + Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); + if (otherClients.isEmpty()) { + profiles.remove(profileId); + } + } + } else { + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client has different registration."); } + } finally { + lwM2MClient.unlock(); } - return client; + } + + @Override + public LwM2mClient fetchSecurityInfoByCredentials(String credentialsId) { + return null; + } + + @Override + public LwM2mClient getClientByRegistrationId(String registrationId) { + return lwM2mClientsByRegistrationId.get(registrationId); } @Override public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c -> + LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c -> (new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())) .equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))) - ).findAny().get(); + ).findAny().orElse(null); if (lwM2mClient == null) { log.warn("Device TimeOut? lwM2mClient is null."); log.warn("SessionInfo input [{}], lwM2mClientsByEndpoint size: [{}]", sessionInfo, lwM2mClientsByEndpoint.values().size()); @@ -96,60 +169,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { return lwM2mClient; } - @Override - public LwM2mClient registerOrUpdate(Registration registration) { - LwM2mClient lwM2MClient = lwM2mClientsByEndpoint.get(registration.getEndpoint()); - if (lwM2MClient == null) { - lwM2MClient = this.fetchClientByEndpoint(registration.getEndpoint()); - } - lwM2MClient.setRegistration(registration); -// TODO: this remove is probably redundant. We should remove it. -// this.lwM2mClientsByEndpoint.remove(registration.getEndpoint()); - this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient); - return lwM2MClient; - } - public Registration getRegistration(String registrationId) { return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration(); } - @Override - public LwM2mClient fetchClientByEndpoint(String endpoint) { - EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); - if (securityInfo.getSecurityMode() != null) { - if (securityInfo.getDeviceProfile() != null) { - UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile())!= null ? - securityInfo.getDeviceProfile().getUuidId() : null; - // TODO: for tests bug. - if (profileUuid== null) { - log.trace("input parameters toClientProfile if the result is null: [{}]", securityInfo.getDeviceProfile()); - } - LwM2mClient client; - if (securityInfo.getSecurityInfo() != null) { - client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(), - securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), - securityInfo.getMsg(), profileUuid, UUID.randomUUID()); - } else if (NO_SEC.equals(securityInfo.getSecurityMode())) { - client = new LwM2mClient(context.getNodeId(), endpoint, - null, null, - securityInfo.getMsg(), profileUuid, UUID.randomUUID()); - } else { - throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint)); - } - lwM2mClientsByEndpoint.put(client.getEndpoint(), client); - return client; - } else { - throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint)); - } - } else { - throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", endpoint)); - } - } - @Override public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) { - LwM2mClient client = new LwM2mClient(context.getNodeId(), registration.getEndpoint(), null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID()); - lwM2mClientsByEndpoint.put(registration.getEndpoint(), client); + LwM2mClient client = getClientByEndpoint(registration.getEndpoint()); + client.init(null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID()); lwM2mClientsByRegistrationId.put(registration.getId(), client); profileUpdate(credentials.getDeviceProfile()); } @@ -171,7 +198,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @Override public LwM2mClientProfile getProfile(Registration registration) { - return this.getProfiles().get(getOrRegister(registration).getProfileId()); + return this.getProfiles().get(getClientByEndpoint(registration.getEndpoint()).getProfileId()); } @Override @@ -186,8 +213,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (lwM2MClientProfile != null) { profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile); return lwM2MClientProfile; - } - else { + } else { return null; } } @@ -215,20 +241,4 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null); } - @Override - public void removeClientByRegistrationId(String registrationId) { - LwM2mClient lwM2MClient = this.lwM2mClientsByRegistrationId.get(registrationId); - if (lwM2MClient != null) { - this.securityStore.remove(lwM2MClient.getEndpoint(), false); - this.lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); - this.lwM2mClientsByRegistrationId.remove(registrationId); - UUID profileId = lwM2MClient.getProfileId(); - if (profileId != null) { - Optional otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); - if (otherClients.isEmpty()) { - profiles.remove(profileId); - } - } - } - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java index e940061c66..7a93d15988 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java @@ -167,7 +167,7 @@ public class LwM2mFwSwUpdate { String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration()); String fwMsg = String.format("%s: Start type operation %s paths: %s", LOG_LW2M_INFO, LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE.name(), FW_PACKAGE_ID); - handler.sendLogsToThingsboard(fwMsg, lwM2MClient.getRegistration().getId()); + handler.sendLogsToThingsboard(lwM2MClient, fwMsg); log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer); request.sendAllRequest(this.lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(), firmwareChunk, handler.config.getTimeout(), this.rpcRequest); @@ -190,7 +190,7 @@ public class LwM2mFwSwUpdate { if (LOG_LW2M_ERROR.equals(typeInfo)) { msg = String.format("%s Error: %s", msg, msgError); } - handler.sendLogsToThingsboard(msg, lwM2MClient.getRegistration().getId()); + handler.sendLogsToThingsboard(lwM2MClient, msg); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index 701d629154..c2d5d542f1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -68,7 +68,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { if (lwM2mClient != null && lwM2mClient.getRegistration() != null && !lwM2mClient.getRegistration().getIdentity().isSecure()) { return null; } - securityInfo = clientContext.fetchClientByEndpoint(endpoint).getSecurityInfo(); + securityInfo = clientContext.fetchSecurityInfoByCredentials(endpoint); try { if (securityInfo != null) { add(securityInfo); @@ -84,7 +84,7 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { public SecurityInfo getByIdentity(String pskIdentity) { SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity); if (securityInfo == null) { - securityInfo = clientContext.fetchClientByEndpoint(pskIdentity).getSecurityInfo(); + securityInfo = clientContext.fetchSecurityInfoByCredentials(pskIdentity); try { if (securityInfo != null) { add(securityInfo); From 74dc1c9df19075b3ba176e0a5a32c797f4811b08 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 7 Jun 2021 19:24:25 +0300 Subject: [PATCH 3/9] Fix initialization order --- .../secure/LwM2MBootstrapSecurityStore.java | 10 +- ...LwM2mCredentialsSecurityInfoValidator.java | 27 ++-- .../lwm2m/secure/TbLwM2MAuthorizer.java | 3 +- ...rityInfo.java => TbLwM2MSecurityInfo.java} | 2 +- .../DefaultLwM2MTransportMsgHandler.java | 14 +- .../server/DefaultLwM2mTransportService.java | 4 +- .../lwm2m/server/client/LwM2mClient.java | 1 - .../server/client/LwM2mClientContext.java | 5 +- .../server/client/LwM2mClientContextImpl.java | 25 +--- .../server/client/Lwm2mClientRpcRequest.java | 2 +- .../server/store/TbEditableSecurityStore.java | 27 ++++ .../server/store/TbInMemorySecurityStore.java | 130 ++++++++++++++++ .../store/TbLwM2mRedisSecurityStore.java | 141 ++++++++++-------- .../server/store/TbLwM2mSecurityStore.java | 81 +++++----- .../server/store/TbLwM2mStoreFactory.java | 11 +- .../lwm2m/server/store/TbSecurityStore.java | 25 ++++ 16 files changed, 344 insertions(+), 164 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/{EndpointSecurityInfo.java => TbLwM2MSecurityInfo.java} (97%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 584b0542b6..197c3ba842 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -30,7 +30,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; @@ -72,7 +72,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public Iterator getAllByEndpoint(String endPoint) { - EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); @@ -96,7 +96,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { @Override public SecurityInfo getByIdentity(String identity) { - EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ this.setBootstrapConfigScurityInfo(store); @@ -113,7 +113,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { return null; } - private void setBootstrapConfigScurityInfo(EndpointSecurityInfo store) { + private void setBootstrapConfigScurityInfo(TbLwM2MSecurityInfo store) { /* BootstrapConfig */ LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { @@ -150,7 +150,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } } - private LwM2MBootstrapConfig getParametersBootstrap(EndpointSecurityInfo store) { + private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { try { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 8d90b2a86b..c57c2295c6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -55,15 +55,15 @@ public class LwM2mCredentialsSecurityInfoValidator { private final LwM2mTransportContext context; private final LwM2MTransportServerConfig config; - public EndpointSecurityInfo getEndpointSecurityInfo(String endpoint, LwM2mTransportUtil.LwM2mTypeServer keyValue) { + public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTransportUtil.LwM2mTypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); - final EndpointSecurityInfo[] resultSecurityStore = new EndpointSecurityInfo[1]; - context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(), + final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1]; + context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(credentialsId).build(), new TransportServiceCallback<>() { @Override public void onSuccess(ValidateDeviceCredentialsResponse msg) { String credentialsBody = msg.getCredentials(); - resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue); + resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue); resultSecurityStore[0].setMsg(msg); resultSecurityStore[0].setDeviceProfile(msg.getDeviceProfile()); latch.countDown(); @@ -71,8 +71,8 @@ public class LwM2mCredentialsSecurityInfoValidator { @Override public void onError(Throwable e) { - log.trace("[{}] [{}] Failed to process credentials ", endpoint, e); - resultSecurityStore[0] = createSecurityInfo(endpoint, null, null); + log.trace("[{}] [{}] Failed to process credentials ", credentialsId, e); + resultSecurityStore[0] = createSecurityInfo(credentialsId, null, null); latch.countDown(); } }); @@ -91,8 +91,8 @@ public class LwM2mCredentialsSecurityInfoValidator { * @param keyValue - * @return SecurityInfo */ - private EndpointSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) { - EndpointSecurityInfo result = new EndpointSecurityInfo(); + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) { + TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo(); LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class); if (credentials != null) { if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) { @@ -106,7 +106,7 @@ public class LwM2mCredentialsSecurityInfoValidator { } else { switch (credentials.getClient().getSecurityConfigClientMode()) { case NO_SEC: - createClientSecurityInfoNoSec(result); + createClientSecurityInfoNoSec(result, endpoint); break; case PSK: createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); @@ -125,12 +125,13 @@ public class LwM2mCredentialsSecurityInfoValidator { return result; } - private void createClientSecurityInfoNoSec(EndpointSecurityInfo result) { + private void createClientSecurityInfoNoSec(TbLwM2MSecurityInfo result, String endpoint) { + result.setEndpoint(endpoint); result.setSecurityInfo(null); result.setSecurityMode(NO_SEC); } - private void createClientSecurityInfoPSK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { + private void createClientSecurityInfoPSK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { PSKClientCredentials pskConfig = (PSKClientCredentials) clientCredentialsConfig; if (StringUtils.isNotEmpty(pskConfig.getIdentity())) { try { @@ -149,7 +150,7 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoRPK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { + private void createClientSecurityInfoRPK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { RPKClientCredentials rpkConfig = (RPKClientCredentials) clientCredentialsConfig; try { if (rpkConfig.getKey() != null) { @@ -164,7 +165,7 @@ public class LwM2mCredentialsSecurityInfoValidator { } } - private void createClientSecurityInfoX509(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { + private void createClientSecurityInfoX509(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) { result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint)); result.setSecurityMode(X509); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java index 7269e78b5e..cd7f1f3072 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MAuthorizer.java @@ -27,6 +27,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; @Component @RequiredArgsConstructor @@ -34,7 +35,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore; public class TbLwM2MAuthorizer implements Authorizer { private final TbLwM2MDtlsSessionStore sessionStorage; - private final TbLwM2mSecurityStore securityStore; + private final TbSecurityStore securityStore; private final SecurityChecker securityChecker = new SecurityChecker(); private final LwM2mClientContext clientContext; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java index e8d3ae3c2b..9b9147c44f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig; @Data -public class EndpointSecurityInfo { +public class TbLwM2MSecurityInfo { private ValidateDeviceCredentialsResponse msg; private SecurityInfo securityInfo; private SecurityMode securityMode; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index 41fcb1c9cb..6c5bbb5970 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -357,7 +357,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ @Override public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo); + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) { log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList()); msg.getSharedUpdatedList().forEach(tsKvProto -> { @@ -459,7 +459,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler this.rpcSubscriptions.put(requestUUID, toDeviceRpcRequestMsg.getExpirationTime()); Lwm2mClientRpcRequest lwm2mClientRpcRequest = null; try { - Registration registration = clientContext.getClient(sessionInfo).getRegistration(); + Registration registration = clientContext.getClientBySessionInfo(sessionInfo).getRegistration(); lwm2mClientRpcRequest = new Lwm2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this); if (lwm2mClientRpcRequest.getErrorMsg() != null) { lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name()); @@ -789,7 +789,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler lwM2MClient.getPendingReadRequests().addAll(pathSend); ConcurrentHashMap finalParams = params; pathSend.forEach(target -> { - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(), + lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TEXT.getName(), finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null); }); if (OBSERVE.equals(typeOper)) { @@ -1159,7 +1159,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler .collect(Collectors.toUnmodifiableSet()); if (!pathSend.isEmpty()) { ConcurrentHashMap finalParams = lwm2mAttributesNew; - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(), + pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TEXT.getName(), finalParams.get(target), this.config.getTimeout(), null)); } }); @@ -1176,7 +1176,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler Map params = (Map) lwm2mAttributesOld.get(target); params.clear(); params.put(OBJECT_VERSION, ""); - lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(), + lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TEXT.getName(), params, this.config.getTimeout(), null); }); } @@ -1227,7 +1227,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - LwM2mClient lwM2mClient = clientContext.getClient(sessionInfo); + LwM2mClient lwM2mClient = clientContext.getClientBySessionInfo(sessionInfo); return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey) .orElse(null); @@ -1262,7 +1262,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param sessionInfo */ public void updateAttributeFromThingsboard(List tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo); + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo); if (lwM2MClient != null) { log.warn("1) UpdateAttributeFromThingsboard, tsKvProtos [{}]", tsKvProtos); tsKvProtos.forEach(tsKvProto -> { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 90e3e13033..865168aed6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -36,6 +36,8 @@ import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -83,7 +85,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { private final LwM2mTransportServerHelper helper; private final LwM2mTransportMsgHandler handler; private final CaliforniumRegistrationStore registrationStore; - private final EditableSecurityStore securityStore; + private final TbSecurityStore securityStore; private final LwM2mClientContext lwM2mClientContext; private final TbLwM2MDtlsCertificateVerifier certificateVerifier; private final TbLwM2MAuthorizer authorizer; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 65c0dbcb0f..1fc876cc45 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -76,7 +76,6 @@ public class LwM2mClient implements Cloneable { @Getter private final Map delayedRequests; @Getter - @Setter private final List pendingReadRequests; @Getter private final Queue queuedRequests; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index e9f292816c..e2e24ad1ff 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -32,15 +32,14 @@ public interface LwM2mClientContext { LwM2mClient getClientByEndpoint(String endpoint); + LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo); + void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException; void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException; void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException; - SecurityInfo fetchSecurityInfoByCredentials(String credentialsId); - - LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo); // LwM2mClient getOrRegister(Registration registration); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 0225b78eaa..ac57040d7b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -25,11 +25,11 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; -import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import java.util.Arrays; import java.util.Collection; @@ -40,8 +40,6 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; @Slf4j @@ -51,14 +49,11 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c public class LwM2mClientContextImpl implements LwM2mClientContext { private final LwM2mTransportContext context; + private final TbEditableSecurityStore securityStore; private final Map lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private Map profiles = new ConcurrentHashMap<>(); - private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; - - private final EditableSecurityStore securityStore; - @Override public LwM2mClient getClientByEndpoint(String endpoint) { return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> new LwM2mClient(context.getNodeId(), ep)); @@ -71,8 +66,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) { throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); } - //TODO: Move this security info lookup to the TbLwM2mSecurityStore. - EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(lwM2MClient.getEndpoint(), LwM2mTransportUtil.LwM2mTypeServer.CLIENT); + TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint()); if (securityInfo.getSecurityMode() != null) { if (securityInfo.getDeviceProfile() != null) { UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null; @@ -127,7 +121,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { if (currentRegistration.getId().equals(registration.getId())) { lwM2MClient.setState(LwM2MClientState.UNREGISTERED); lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); - this.securityStore.remove(lwM2MClient.getEndpoint(), false); + this.securityStore.remove(lwM2MClient.getEndpoint()); this.lwM2mClientsByRegistrationId.remove(registration.getId()); UUID profileId = lwM2MClient.getProfileId(); if (profileId != null) { @@ -144,18 +138,13 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } } - @Override - public LwM2mClient fetchSecurityInfoByCredentials(String credentialsId) { - return null; - } - @Override public LwM2mClient getClientByRegistrationId(String registrationId) { return lwM2mClientsByRegistrationId.get(registrationId); } @Override - public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) { + public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c -> (new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())) .equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java index d71c6b27f6..40dace0b5e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java @@ -273,7 +273,7 @@ public class Lwm2mClientRpcRequest { } private String getRezIdByResourceNameAndObjectInstanceId(String resourceName, DefaultLwM2MTransportMsgHandler handler) { - LwM2mClient lwM2mClient = handler.clientContext.getClient(this.sessionInfo); + LwM2mClient lwM2mClient = handler.clientContext.getClientBySessionInfo(this.sessionInfo); return lwM2mClient != null ? lwM2mClient.getRezIdByResourceNameAndObjectInstanceId(resourceName, this.targetIdVer, handler.config.getModelProvider()) : null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java new file mode 100644 index 0000000000..9efd07dde0 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbEditableSecurityStore.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2021 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.server.store; + +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; + +public interface TbEditableSecurityStore extends TbSecurityStore { + + void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException; + + void remove(String endpoint); + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java new file mode 100644 index 0000000000..9c0b109082 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbInMemorySecurityStore.java @@ -0,0 +1,130 @@ +/** + * Copyright © 2016-2021 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.server.store; + +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class TbInMemorySecurityStore implements TbEditableSecurityStore { + // lock for the two maps + protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + protected final Lock readLock = readWriteLock.readLock(); + protected final Lock writeLock = readWriteLock.writeLock(); + + // by client end-point + protected Map securityByEp = new HashMap<>(); + + // by PSK identity + protected Map securityByIdentity = new HashMap<>(); + + public TbInMemorySecurityStore() { + } + + /** + * {@inheritDoc} + */ + @Override + public SecurityInfo getByEndpoint(String endpoint) { + readLock.lock(); + try { + TbLwM2MSecurityInfo securityInfo = securityByEp.get(endpoint); + if (securityInfo != null) { + return securityInfo.getSecurityInfo(); + } else { + return null; + } + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public SecurityInfo getByIdentity(String identity) { + readLock.lock(); + try { + TbLwM2MSecurityInfo securityInfo = securityByIdentity.get(identity); + if (securityInfo != null) { + return securityInfo.getSecurityInfo(); + } else { + return null; + } + } finally { + readLock.unlock(); + } + } + + @Override + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException { + writeLock.lock(); + try { + String identity = null; + if (tbSecurityInfo.getSecurityInfo() != null) { + identity = tbSecurityInfo.getSecurityInfo().getIdentity(); + if (identity != null) { + TbLwM2MSecurityInfo infoByIdentity = securityByIdentity.get(identity); + if (infoByIdentity != null && !tbSecurityInfo.getSecurityInfo().getEndpoint().equals(infoByIdentity.getEndpoint())) { + throw new NonUniqueSecurityInfoException("PSK Identity " + identity + " is already used"); + } + securityByIdentity.put(tbSecurityInfo.getSecurityInfo().getIdentity(), tbSecurityInfo); + } + } + + TbLwM2MSecurityInfo previous = securityByEp.put(tbSecurityInfo.getEndpoint(), tbSecurityInfo); + if (previous != null && previous.getSecurityInfo() != null) { + String previousIdentity = previous.getSecurityInfo().getIdentity(); + if (previousIdentity != null && !previousIdentity.equals(identity)) { + securityByIdentity.remove(previousIdentity); + } + } + } finally { + writeLock.unlock(); + } + } + + @Override + public void remove(String endpoint) { + writeLock.lock(); + try { + TbLwM2MSecurityInfo securityInfo = securityByEp.remove(endpoint); + if (securityInfo != null && securityInfo.getSecurityInfo() != null && securityInfo.getSecurityInfo().getIdentity() != null) { + securityByIdentity.remove(securityInfo.getSecurityInfo().getIdentity()); + } + } finally { + writeLock.unlock(); + } + } + + @Override + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) { + readLock.lock(); + try { + return securityByEp.get(endpoint); + } finally { + readLock.unlock(); + } + } + +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java index 4cfe2a6829..9e3fe5625d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java @@ -24,13 +24,14 @@ import org.springframework.data.redis.connection.RedisClusterConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; -public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { +public class TbLwM2mRedisSecurityStore implements TbEditableSecurityStore { private static final String SEC_EP = "SEC#EP#"; private static final String PSKID_SEC = "PSKID#SEC"; @@ -72,73 +73,89 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { } @Override - public Collection getAll() { - try (var connection = connectionFactory.getConnection()) { - Collection list = new LinkedList<>(); - ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(SEC_EP + "*").build(); - List> scans = new ArrayList<>(); - if (connection instanceof RedisClusterConnection) { - ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> { - scans.add(((RedisClusterConnection) connection).scan(node, scanOptions)); - }); - } else { - scans.add(connection.scan(scanOptions)); - } - - scans.forEach(scan -> { - scan.forEachRemaining(key -> { - byte[] element = connection.get(key); - list.add(deserialize(element)); - }); - }); - return list; - } + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException { + //TODO: implement } @Override - public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { - byte[] data = serialize(info); - try (var connection = connectionFactory.getConnection()) { - if (info.getIdentity() != null) { - // populate the secondary index (security info by PSK id) - String oldEndpoint = new String(connection.hGet(PSKID_SEC.getBytes(), info.getIdentity().getBytes())); - if (!oldEndpoint.equals(info.getEndpoint())) { - throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used"); - } - connection.hSet(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes()); - } - - byte[] previousData = connection.getSet((SEC_EP + info.getEndpoint()).getBytes(), data); - SecurityInfo previous = previousData == null ? null : deserialize(previousData); - String previousIdentity = previous == null ? null : previous.getIdentity(); - if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) { - connection.hDel(PSKID_SEC.getBytes(), previousIdentity.getBytes()); - } - - return previous; - } + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) { + //TODO: implement + return null; } @Override - public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { - try (var connection = connectionFactory.getConnection()) { - byte[] data = connection.get((SEC_EP + endpoint).getBytes()); - - if (data != null) { - SecurityInfo info = deserialize(data); - if (info.getIdentity() != null) { - connection.hDel(PSKID_SEC.getBytes(), info.getIdentity().getBytes()); - } - connection.del((SEC_EP + endpoint).getBytes()); - if (listener != null) { - listener.securityInfoRemoved(infosAreCompromised, info); - } - return info; - } - } - return null; + public void remove(String endpoint) { + //TODO: implement } + // @Override +// public Collection getAll() { +// try (var connection = connectionFactory.getConnection()) { +// Collection list = new LinkedList<>(); +// ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(SEC_EP + "*").build(); +// List> scans = new ArrayList<>(); +// if (connection instanceof RedisClusterConnection) { +// ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> { +// scans.add(((RedisClusterConnection) connection).scan(node, scanOptions)); +// }); +// } else { +// scans.add(connection.scan(scanOptions)); +// } +// +// scans.forEach(scan -> { +// scan.forEachRemaining(key -> { +// byte[] element = connection.get(key); +// list.add(deserialize(element)); +// }); +// }); +// return list; +// } +// } +// +// @Override +// public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { +// byte[] data = serialize(info); +// try (var connection = connectionFactory.getConnection()) { +// if (info.getIdentity() != null) { +// // populate the secondary index (security info by PSK id) +// String oldEndpoint = new String(connection.hGet(PSKID_SEC.getBytes(), info.getIdentity().getBytes())); +// if (!oldEndpoint.equals(info.getEndpoint())) { +// throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used"); +// } +// connection.hSet(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes()); +// } +// +// byte[] previousData = connection.getSet((SEC_EP + info.getEndpoint()).getBytes(), data); +// SecurityInfo previous = previousData == null ? null : deserialize(previousData); +// String previousIdentity = previous == null ? null : previous.getIdentity(); +// if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) { +// connection.hDel(PSKID_SEC.getBytes(), previousIdentity.getBytes()); +// } +// +// return previous; +// } +// } +// +// @Override +// public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { +// try (var connection = connectionFactory.getConnection()) { +// byte[] data = connection.get((SEC_EP + endpoint).getBytes()); +// +// if (data != null) { +// SecurityInfo info = deserialize(data); +// if (info.getIdentity() != null) { +// connection.hDel(PSKID_SEC.getBytes(), info.getIdentity().getBytes()); +// } +// connection.del((SEC_EP + endpoint).getBytes()); +// if (listener != null) { +// listener.securityInfoRemoved(infosAreCompromised, info); +// } +// return info; +// } +// } +// return null; +// } + private byte[] serialize(SecurityInfo secInfo) { return SecurityInfoSerDes.serialize(secInfo); } @@ -147,8 +164,4 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { return SecurityInfoSerDes.deserialize(data); } - @Override - public void setListener(SecurityStoreListener listener) { - this.listener = listener; - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index c2d5d542f1..8302af64fa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -19,63 +19,40 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.security.EditableSecurityStore; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.eclipse.leshan.server.security.SecurityInfo; +import org.eclipse.leshan.server.security.SecurityStore; import org.eclipse.leshan.server.security.SecurityStoreListener; +import org.jetbrains.annotations.Nullable; import org.springframework.stereotype.Component; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.Collection; @Slf4j -@Component @TbLwM2mTransportComponent -public class TbLwM2mSecurityStore implements EditableSecurityStore { +public class TbLwM2mSecurityStore implements TbEditableSecurityStore { - private final LwM2mClientContext clientContext; - private final EditableSecurityStore securityStore; + private final TbEditableSecurityStore securityStore; + private final LwM2mCredentialsSecurityInfoValidator validator; - public TbLwM2mSecurityStore(LwM2mClientContext clientContext, EditableSecurityStore securityStore) { - this.clientContext = clientContext; + public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2mCredentialsSecurityInfoValidator validator) { this.securityStore = securityStore; + this.validator = validator; } @Override - public Collection getAll() { - return securityStore.getAll(); - } - - @Override - public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { - return securityStore.add(info); - } - - @Override - public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { - return securityStore.remove(endpoint, infosAreCompromised); - } - - @Override - public void setListener(SecurityStoreListener listener) { - securityStore.setListener(listener); + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) { + return securityStore.getTbLwM2MSecurityInfoByEndpoint(endpoint); } @Override public SecurityInfo getByEndpoint(String endpoint) { SecurityInfo securityInfo = securityStore.getByEndpoint(endpoint); if (securityInfo == null) { - LwM2mClient lwM2mClient = clientContext.getClientByEndpoint(endpoint); - if (lwM2mClient != null && lwM2mClient.getRegistration() != null && !lwM2mClient.getRegistration().getIdentity().isSecure()) { - return null; - } - securityInfo = clientContext.fetchSecurityInfoByCredentials(endpoint); - try { - if (securityInfo != null) { - add(securityInfo); - } - } catch (NonUniqueSecurityInfoException e) { - log.trace("Failed to add security info: {}", securityInfo, e); - } + securityInfo = fetchAndPutSecurityInfo(endpoint); } return securityInfo; } @@ -84,15 +61,31 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore { public SecurityInfo getByIdentity(String pskIdentity) { SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity); if (securityInfo == null) { - securityInfo = clientContext.fetchSecurityInfoByCredentials(pskIdentity); - try { - if (securityInfo != null) { - add(securityInfo); - } - } catch (NonUniqueSecurityInfoException e) { - log.trace("Failed to add security info: {}", securityInfo, e); - } + securityInfo = fetchAndPutSecurityInfo(pskIdentity); } return securityInfo; } + + @Nullable + public SecurityInfo fetchAndPutSecurityInfo(String credentialsId) { + TbLwM2MSecurityInfo securityInfo = validator.getEndpointSecurityInfoByCredentialsId(credentialsId, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); + try { + if (securityInfo != null) { + securityStore.put(securityInfo); + } + } catch (NonUniqueSecurityInfoException e) { + log.trace("Failed to add security info: {}", securityInfo, e); + } + return securityInfo != null ? securityInfo.getSecurityInfo() : null; + } + + @Override + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException { + securityStore.put(tbSecurityInfo); + } + + @Override + public void remove(String endpoint) { + securityStore.remove(endpoint); + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java index 2c0c96212f..3dd9ebd3ed 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java @@ -19,6 +19,7 @@ import org.eclipse.leshan.server.californium.registration.CaliforniumRegistratio import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore; import org.eclipse.leshan.server.security.EditableSecurityStore; import org.eclipse.leshan.server.security.InMemorySecurityStore; +import org.eclipse.leshan.server.security.SecurityStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -27,6 +28,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.Optional; @@ -42,8 +44,7 @@ public class TbLwM2mStoreFactory { private LwM2MTransportServerConfig config; @Autowired - @Lazy - private LwM2mClientContext clientContext; + private LwM2mCredentialsSecurityInfoValidator validator; @Value("${transport.lwm2m.redis.enabled:false}") private boolean useRedis; @@ -55,9 +56,9 @@ public class TbLwM2mStoreFactory { } @Bean - private EditableSecurityStore securityStore() { - return new TbLwM2mSecurityStore(clientContext, redisConfiguration.isPresent() && useRedis ? - new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new InMemorySecurityStore()); + private TbSecurityStore securityStore() { + return new TbLwM2mSecurityStore(redisConfiguration.isPresent() && useRedis ? + new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new TbInMemorySecurityStore(), validator); } @Bean diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java new file mode 100644 index 0000000000..a1aa394fb5 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbSecurityStore.java @@ -0,0 +1,25 @@ +/** + * Copyright © 2016-2021 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.server.store; + +import org.eclipse.leshan.server.security.SecurityStore; +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; + +public interface TbSecurityStore extends SecurityStore { + + TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint); + +} From be4d3f608d2cb6a369b47771d9ae187e5ff5ff93 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 7 Jun 2021 19:26:10 +0300 Subject: [PATCH 4/9] fixed lwm2m tests --- .../lwm2m/AbstractLwM2MIntegrationTest.java | 47 ++++++++ .../lwm2m/NoSecLwM2MIntegrationTest.java | 71 ++---------- .../lwm2m/X509LwM2MIntegrationTest.java | 48 -------- .../lwm2m/client/LwM2MTestClient.java | 107 ++++++------------ .../lwm2m/credentials/clientKeyStore.jks | Bin 3180 -> 4810 bytes .../lwm2m/credentials/serverKeyStore.jks | Bin 3120 -> 3806 bytes 6 files changed, 93 insertions(+), 180 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 90b926e78a..6db6e24f91 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -60,6 +60,53 @@ import java.util.concurrent.ScheduledExecutorService; @DaoSqlTest public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { + protected final String TRANSPORT_CONFIGURATION = "{\n" + + " \"type\": \"LWM2M\",\n" + + " \"observeAttr\": {\n" + + " \"keyName\": {\n" + + " \"/3_1.0/0/9\": \"batteryLevel\"\n" + + " },\n" + + " \"observe\": [],\n" + + " \"attribute\": [\n" + + " ],\n" + + " \"telemetry\": [\n" + + " \"/3_1.0/0/9\"\n" + + " ],\n" + + " \"attributeLwm2m\": {}\n" + + " },\n" + + " \"bootstrap\": {\n" + + " \"servers\": {\n" + + " \"binding\": \"U\",\n" + + " \"shortId\": 123,\n" + + " \"lifetime\": 300,\n" + + " \"notifIfDisabled\": true,\n" + + " \"defaultMinPeriod\": 1\n" + + " },\n" + + " \"lwm2mServer\": {\n" + + " \"host\": \"localhost\",\n" + + " \"port\": 5686,\n" + + " \"serverId\": 123,\n" + + " \"serverPublicKey\": \"\",\n" + + " \"bootstrapServerIs\": false,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " },\n" + + " \"bootstrapServer\": {\n" + + " \"host\": \"localhost\",\n" + + " \"port\": 5687,\n" + + " \"serverId\": 111,\n" + + " \"securityMode\": \"NO_SEC\",\n" + + " \"serverPublicKey\": \"\",\n" + + " \"bootstrapServerIs\": true,\n" + + " \"clientHoldOffTime\": 1,\n" + + " \"bootstrapServerAccountTimeout\": 0\n" + + " }\n" + + " },\n" + + " \"clientLwM2mSettings\": {\n" + + " \"clientOnlyObserveAfterConnect\": 1\n" + + " }\n" + + "}"; + protected DeviceProfile deviceProfile; protected ScheduledExecutorService executor; protected TbTestWebSocketClient wsClient; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java index 2021dd839c..7d173e61d9 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/NoSecLwM2MIntegrationTest.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; @@ -36,7 +37,6 @@ import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; import java.util.Collections; import java.util.List; @@ -46,60 +46,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { - protected final String TRANSPORT_CONFIGURATION = "{\n" + - " \"type\": \"LWM2M\",\n" + - " \"observeAttr\": {\n" + - " \"keyName\": {\n" + - " \"/3_1.0/0/9\": \"batteryLevel\"\n" + - " },\n" + - " \"observe\": [],\n" + - " \"attribute\": [\n" + - " ],\n" + - " \"telemetry\": [\n" + - " \"/3_1.0/0/9\"\n" + - " ],\n" + - " \"attributeLwm2m\": {}\n" + - " },\n" + - " \"bootstrap\": {\n" + - " \"servers\": {\n" + - " \"binding\": \"UQ\",\n" + - " \"shortId\": 123,\n" + - " \"lifetime\": 300,\n" + - " \"notifIfDisabled\": true,\n" + - " \"defaultMinPeriod\": 1\n" + - " },\n" + - " \"lwm2mServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5685,\n" + - " \"serverId\": 123,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": false,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " \"bootstrapServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5687,\n" + - " \"serverId\": 111,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": true,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " }\n" + - " },\n" + - " \"clientLwM2mSettings\": {\n" + - " \"clientOnlyObserveAfterConnect\": 1\n" + - " }\n" + - "}"; - - private final int port = 5685; - private final Security security = noSec("coap://localhost:" + port, 123); - private final NetworkConfig coapConfig = new NetworkConfig().setString("COAP_PORT", Integer.toString(port)); + private final int PORT = 5685; + private final Security SECURITY = noSec("coap://localhost:" + PORT, 123); + private final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); + private final String ENDPOINT = "deviceAEndpoint"; @NotNull - private Device createDevice(String deviceAEndpoint) throws Exception { + private Device createDevice() throws Exception { Device device = new Device(); device.setName("Device A"); device.setDeviceProfileId(deviceProfile.getId()); @@ -114,20 +67,18 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { LwM2MCredentials noSecCredentials = new LwM2MCredentials(); NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); - clientCredentials.setEndpoint(deviceAEndpoint); + clientCredentials.setEndpoint(ENDPOINT); noSecCredentials.setClient(clientCredentials); deviceCredentials.setCredentialsValue(JacksonUtil.toString(noSecCredentials)); doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk()); return device; } -// @Test + @Test public void testConnectAndObserveTelemetry() throws Exception { createDeviceProfile(TRANSPORT_CONFIGURATION); - String deviceAEndpoint = "deviceAEndpoint"; - - Device device = createDevice(deviceAEndpoint); + Device device = createDevice(); SingleEntityFilter sef = new SingleEntityFilter(); sef.setSingleEntity(device.getId()); @@ -144,8 +95,8 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { wsClient.waitForReply(); wsClient.registerWaitForUpdate(); - LwM2MTestClient client = new LwM2MTestClient(executor, deviceAEndpoint); - client.init(security, coapConfig); + LwM2MTestClient client = new LwM2MTestClient(executor, ENDPOINT); + client.init(SECURITY, COAP_CONFIG); String msg = wsClient.waitForUpdate(); EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/X509LwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/X509LwM2MIntegrationTest.java index 18749cfee5..0c13c57441 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/X509LwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/X509LwM2MIntegrationTest.java @@ -47,54 +47,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { - protected final String TRANSPORT_CONFIGURATION = "{\n" + - " \"type\": \"LWM2M\",\n" + - " \"observeAttr\": {\n" + - " \"keyName\": {\n" + - " \"/3_1.0/0/9\": \"batteryLevel\"\n" + - " },\n" + - " \"observe\": [],\n" + - " \"attribute\": [\n" + - " ],\n" + - " \"telemetry\": [\n" + - " \"/3_1.0/0/9\"\n" + - " ],\n" + - " \"attributeLwm2m\": {}\n" + - " },\n" + - " \"bootstrap\": {\n" + - " \"servers\": {\n" + - " \"binding\": \"UQ\",\n" + - " \"shortId\": 123,\n" + - " \"lifetime\": 300,\n" + - " \"notifIfDisabled\": true,\n" + - " \"defaultMinPeriod\": 1\n" + - " },\n" + - " \"lwm2mServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5686,\n" + - " \"serverId\": 123,\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": false,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " },\n" + - " \"bootstrapServer\": {\n" + - " \"host\": \"localhost\",\n" + - " \"port\": 5687,\n" + - " \"serverId\": 111,\n" + - " \"securityMode\": \"NO_SEC\",\n" + - " \"serverPublicKey\": \"\",\n" + - " \"bootstrapServerIs\": true,\n" + - " \"clientHoldOffTime\": 1,\n" + - " \"bootstrapServerAccountTimeout\": 0\n" + - " }\n" + - " },\n" + - " \"clientLwM2mSettings\": {\n" + - " \"clientOnlyObserveAfterConnect\": 1\n" + - " }\n" + - "}"; - - private final int port = 5686; private final NetworkConfig coapConfig = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(port)); private final String endpoint = "deviceAEndpoint"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 9f7c232203..4ab03fa6c0 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -17,18 +17,11 @@ 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.elements.Connector; +import org.eclipse.californium.core.observe.ObservationStore; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; -import org.eclipse.californium.scandium.dtls.ClientHandshaker; -import org.eclipse.californium.scandium.dtls.DTLSSession; -import org.eclipse.californium.scandium.dtls.HandshakeException; -import org.eclipse.californium.scandium.dtls.Handshaker; -import org.eclipse.californium.scandium.dtls.ResumingClientHandshaker; -import org.eclipse.californium.scandium.dtls.ResumingServerHandshaker; -import org.eclipse.californium.scandium.dtls.ServerHandshaker; -import org.eclipse.californium.scandium.dtls.SessionAdapter; import org.eclipse.leshan.client.californium.LeshanClient; import org.eclipse.leshan.client.californium.LeshanClientBuilder; import org.eclipse.leshan.client.engine.DefaultRegistrationEngineFactory; @@ -40,7 +33,7 @@ import org.eclipse.leshan.client.resource.ObjectsInitializer; import org.eclipse.leshan.client.servers.ServerIdentity; import org.eclipse.leshan.core.LwM2mId; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.californium.DefaultEndpointFactory; +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; @@ -54,6 +47,7 @@ import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; import java.io.IOException; +import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; @@ -81,80 +75,49 @@ public class LwM2MTestClient { initializer.setInstancesForObject(SECURITY, security); initializer.setInstancesForObject(SERVER, new Server(123, 300)); initializer.setInstancesForObject(DEVICE, new SimpleLwM2MDevice()); + initializer.setClassForObject(LwM2mId.ACCESS_CONTROL, DummyInstanceEnabler.class); DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); dtlsConfig.setRecommendedCipherSuitesOnly(true); + dtlsConfig.setClientOnly(); DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory(); engineFactory.setReconnectOnUpdate(false); engineFactory.setResumeOnConnect(true); - DefaultEndpointFactory endpointFactory = new DefaultEndpointFactory(endpoint) { + 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 - protected Connector createSecuredConnector(DtlsConnectorConfig dtlsConfig) { - - return new DTLSConnector(dtlsConfig) { - @Override - protected void onInitializeHandshaker(Handshaker handshaker) { - handshaker.addSessionListener(new SessionAdapter() { - - @Override - public void handshakeStarted(Handshaker handshaker) throws HandshakeException { - if (handshaker instanceof ServerHandshaker) { - log.info("DTLS Full Handshake initiated by server : STARTED ..."); - } else if (handshaker instanceof ResumingServerHandshaker) { - log.info("DTLS abbreviated Handshake initiated by server : STARTED ..."); - } else if (handshaker instanceof ClientHandshaker) { - log.info("DTLS Full Handshake initiated by client : STARTED ..."); - } else if (handshaker instanceof ResumingClientHandshaker) { - log.info("DTLS abbreviated Handshake initiated by client : STARTED ..."); - } - } - - @Override - public void sessionEstablished(Handshaker handshaker, DTLSSession establishedSession) - throws HandshakeException { - if (handshaker instanceof ServerHandshaker) { - log.info("DTLS Full Handshake initiated by server : SUCCEED, handshaker {}", handshaker); - } else if (handshaker instanceof ResumingServerHandshaker) { - log.info("DTLS abbreviated Handshake initiated by server : SUCCEED, handshaker {}", handshaker); - } else if (handshaker instanceof ClientHandshaker) { - log.info("DTLS Full Handshake initiated by client : SUCCEED, handshaker {}", handshaker); - } else if (handshaker instanceof ResumingClientHandshaker) { - log.info("DTLS abbreviated Handshake initiated by client : SUCCEED, handshaker {}", handshaker); - } - } - - @Override - public void handshakeFailed(Handshaker handshaker, Throwable error) { - /** get cause */ - String cause; - if (error != null) { - if (error.getMessage() != null) { - cause = error.getMessage(); - } else { - cause = error.getClass().getName(); - } - } else { - cause = "unknown cause"; - } - - if (handshaker instanceof ServerHandshaker) { - log.info("DTLS Full Handshake initiated by server : FAILED [{}]", cause); - } else if (handshaker instanceof ResumingServerHandshaker) { - log.info("DTLS abbreviated Handshake initiated by server : FAILED [{}]", cause); - } else if (handshaker instanceof ClientHandshaker) { - log.info("DTLS Full Handshake initiated by client : FAILED [{}]", cause); - } else if (handshaker instanceof ResumingClientHandshaker) { - log.info("DTLS abbreviated Handshake initiated by client : FAILED [{}]", cause); - } - } - }); - } - }; + public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, + ObservationStore store) { + CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); + DtlsConnectorConfig.Builder dtlsConfigBuilder = new DtlsConnectorConfig.Builder(dtlsConfig); + + // tricks to be able to change psk information on the fly +// AdvancedPskStore pskStore = dtlsConfig.getAdvancedPskStore(); +// if (pskStore != null) { +// PskPublicInformation identity = pskStore.getIdentity(null, null); +// SecretKey key = pskStore +// .requestPskSecretResult(ConnectionId.EMPTY, null, identity, null, null, null).getSecret(); +// singlePSKStore = new SinglePSKStore(identity, key); +// dtlsConfigBuilder.setAdvancedPskStore(singlePSKStore); +// } + builder.setConnector(new DTLSConnector(dtlsConfigBuilder.build())); + builder.setNetworkConfig(coapConfig); + return builder.build(); } }; + LeshanClientBuilder builder = new LeshanClientBuilder(endpoint); builder.setLocalAddress("0.0.0.0", 11000); builder.setObjects(initializer.createAll()); diff --git a/application/src/test/resources/lwm2m/credentials/clientKeyStore.jks b/application/src/test/resources/lwm2m/credentials/clientKeyStore.jks index 7cc58589b72517c57a1086144275218ad04b75de..a6c9ae7faed05c48ec1218e23a42c3025ae852d2 100644 GIT binary patch literal 4810 zcmeHKdpwls9)IVZ8?$1V+`8z^r7faoTyo7Kw~~aYeB{y?OqdySK}BLOgxw-rlBDFa z(TZxxaVZgsq;!#Oed=sfBHG$cn>de|>D0_gr#|2u2XxmVxY?(+F|Bkr}Xrw_K2ni-bWfz@s=6CB*GFPk0g!dufX^N|u{P18lHZ>cz+#X=+GmPnADKMv-z)w>@4JBhb z95ADsN(Mgk=M8{HB8%2Ragqh`I5OS=A$$_)db__`Kf&{*+vqJu#2QlLoO2`e+65gI z-$gJeM>`{JIjxqb>8Ge_!lDMXA86YTCXKbnuGg^n=F+^#I@_T_2Ve*0!Y$8LB&ZQ) z8fIy2sm?Jp&$_ZJ{#<&$?-nG%2PjVctc1f&65w0nNI+@oo;Gz)1bBFnJ_Nig0-VtK z$i+`9(rT0kqX*_j_w@*Fd+BSSSe=pDsrHJU_wP4v8bC4krd)?AT1kHN7-kN~$tF(BaxIDJ$Zha)0{i0J#> zovXR|mu?hxEl}b7x^;3Dt#7!s^lHm~yIG-8)Li9+;k)X(YBi1vEBDnnA>Ez!mT$3`Q4`n9W+^X!+{4QYO-S3QT6X}EDl&Ek_+k0!5+ zYpLBXV#z;PQ2-f{2g6>%3gV9>L+Jzg5U|p$u#jbig&&wj*8pl_N-2dfV^|EPy%Rfx z%VDtvV0v2U9!Lqw-7z#C_5+1q>%r{Zrb<@rA-bN~cDcLZR##D3?^iAxJ|7PzzqBvV z*yMKZMJcE6p^Zs|bIl@!0%}5XejyKV-=T%)i-5C@=hRPSl+Ag>Zzi$gZEP1x(*mCg z~3 zcUGX)I%_?*E_{3-ZJa+cD?i<-R#=W=gwmu2hr~i!y5^m%St(XSs=P&_3t+#~|>9H!PwQ{m$UWGO2k zOFy7X*9MqKKnj|XB2NyK>?oEc2$yW@k1ZvUBV)Y!3qJ=m9_lR#FWA#Q!FtBRKlEK@R$tJlo_n3b=vB)WQS;b+(7BZC~gcdc{5>TRX>Hkx@c6+Pa||hi){oR?wITG zsg(^leJ5-T^ZT;2SlX2DLO$JrktE@ie zV(3OUHZe6@YW@KxHl`D?&h_4cZl}NScqNqV38S?a8?N=awxM`xRG?1AJYVaiudOGe zpVML!quB?GvXVcrfBp2AXyKVh6d6+wN(pE9O zsn;F7ks3QNc{q&6s497^$v>WtV0af}+7+|4Ma=vf{-UO`3IbZ2(e6)Sd+W8OGKhnve&F{pX!=}TYj4pS)bm=q zHg>r3!Tw%uPva9JIo&dQB!vMD}d)xMoZa~hgv(AwfIo@}ty=^|8i z?n)v@R27DTkau$Rd!dmn;Z)#ji%U2;K!PP4ijz*-ZqJH)6dp%CKfEigBQr|i7~(ZE zSNc%JWgeC&#P;~!=vb~|O|B&94a$Fi-o|$Jf-!&9>IK^k`kO|fskCT;0hJLwRNGo% zCZ`=e)~M|P>N&lva`&9jLkU_gBIznXQxTUp{5Q4tLBl^m{$qix3_<2fg!XQil~?o@ z=_63e`7j(La*k_O?v!R8_|N5RCM#z%zkh4i=|vq~di=F*tao-9r*Ip2(xUaGp`_g-CJ{w$T`QZdmIwKlWK4#oVF!}tB|TGZ8X?OTd* z)Y^xIg29viIhbnLsgyi}V&_7UU{xeV6q_Rm6!3(60W(Bg+a1{O7R+)8WGRd{wH@(s zK${GhI`sLXb^*4`8j_Y-$d*hvP4oP|D)0ZkP5Rn*Om0!NWp4tgDGpG|L5z=m>HIMn zbp-;Pp~*g28Bx;KSa>euVO`z+-kczeW;a<=?+S=f1MQ;`&`d}d^5AfFY+egkWc!CP39AfyQ}=1VlHt()E_ z1M7$I_@8ZhJ%PtNiS+k2y&uujiVJc5Gsor4Iq{=&2E7sHiH7dql=}VmE~1%wAjS=W z-US%MD#xzn+KIdbuX4}O1#U6Evu~aWyJvEnGFWtBU;QUP+JGyKj%mKTb$|Y4AvgC` M^f%}Gep;{ccMhiIP5=M^ literal 3180 zcmY+EcQhLgyT>I~#h#@`&C&{j+M^=W-m|s$Dlyu|jM=CdX-UmeTS=(BDJ7^?tEm3$ z-D;v$6|}s)_uTuw_x|;q^ZB0Vd!Elf4E~`y z_c5=z7aiXiMP0SIp3X%Zap%Z$u5o#n@rt3Ni{ZVz8sNQ!BJU_!EeP+w52WLeWfEYZ z@Su1=;YZ;`5k&D2@*gicPFW5rHfz5?FF{#FIf#;+qO6jVoPshWfnN0A4YV}H3G|$Q z5i1Zt@ppj!lK}poAI*RH1%Rg>D$|YFIKb2gpEW5N9}71w{I_3R0%+=L4gR(-Ux$}= zrm0RO$19#zUzA_G3G8i7vuD>K*KK(PwRHrBK`AvmJJmkd!pe&uC*)(P;5ld71zZ3nuS1haTTmybS^XcAe)So$acDI| zmC*^Gf!EzPXY8x~_>;H9?m{U=9jZWPu%xf2q14AY93aolJz4Lu0+{AFNooT?9dtWz`(x=LG7zcaw5@tiW6 zmN7Em+7$q-do3HSnjr~K7i$OMF~&oJ-78kIbuYA|-W$8}+aB?CWmX~#($Ss!|I7&8 zfzpcY|8#*-X9$@bd@~1Kxj!&SvaHrl<<~TWt0F&f=gH`1dGss};YfXU%L1>@5(5?8 zo|Yz-=nPBV4!`{UW?-x&DSt)i`o@H4&UT_N$3Al?kw~xEz@uIOX>_CvZqsY7E>`~< z)u*Ig9OBuoh^RM|RpcGI}(s>QSJNWeWpNW|N4DYAP|kGi@> z0_}UVlN$JJX%%~{e?gb|ER3<*#P5>xqxchlz0x zdf-!mQz6b>!Ofl~woyu43-;@;oczXcNkA>gnT4T8349H4O)Nz&(3#G2!9F=|f%zMi z;B;)}v&n`X#el-~waY$)-IZ8RPQ|dIyR)_(Xg8IaeF2p=NivE{WrI6#_Kk0qdC83) zt8Kw1lF=*v%8?z=+X<|ezsSc*XZx2~c{srB~%&tf5yj*pxL10uj$iFwb_=xkXmfAQVWy$)OTCIO2^!(%q zxwYh2rLAb*+ZHn{l6_)MkB&qfn!mdBU^9A&<25(d37M%`4oO9I?`tX-Kv?q&8RveWJfTj|C*(~?a#XX* zHc(Kk*0x$06q2$&-h*yOv-F2@<*;(v=PEq<>?(zw>`knBgne}3G$IN&q>UzqPAomA z9%$1-D5=Hok(GkAn+y0IKFm#1<*%U2ZvFBl*);k|4D|2lUJQ>MmxEpV`gh;ld1rEv zflhw7)RFQ@=6A4DN0QHvgW~bihUx8!_HXhwlU#K>8k06ja}hpatemUXh5rQ9swEiGJ1d><-1Yn+7nJy9>Sx7w z;=~!rnUdx1%RGUqAEL*(bui)Z!Hac=&(Y4ZX^#p$BrXT=!v^E!aA0no{1@99M z@y$C;m9h3otJ2vBDLjtAJ&*`3n+x`5Hr@!H72_`-KU`^z$Wr9V?F!ZXesRi~(m5uQ zrmL29!G383?}8oj3MWbIfioD)ui2eS1+{gO^4K;^_WBh@)M#hmK4#>>E&iT~IKQ0G zd%9t~Td|-nRlbA$XuS5cHYnQcIqBVru2A2 zz@*?0t6R8i+L=2C$of411@kr ziwo=QI@w;(No~GjiNPc%ecPX{8As|KFW$P%K4ssybl4l$x=H19epGEbbN?VozQPWZ zHRRz|Lz62iPT6j2wv2CWiYn)pVgetR(62!%nlN^8-#O+@W6xAVK51xO=MQ=% zM%#nP*jvSr*%2y1%2dydZL}mRwgaE_Dj3n-ym8Uj&W-)7{l+dkAo2tp81>JS(9L7Q z#TWlFvY_oJ4F54dCarark`7_Xp!ebjl3e{|tNov$sp&b)=MwaNAhs?zf*AMPWQ?E~ zKCiO$_k~+-F2Oamgl}kIs>nVceYQNeiwL8#Y>HCiTZQ7=<7xT7)9oXtoDcy;`^Lsd zMjLBJhOqg$oE>PMEx1(<|O)1HA9sm+Nu(eMq@G_by%kOo}7V{ryp4 z@T<~pv9?Z^(H7Rrr5_enmuER~)Y$8;a%>PWsXloG)WNPvuDS!;2wg{nK>bMV3V4{6eZAHBpRy z1nc~^$CBLtM4#X5r9>|`8y+fhF%rd*24!pd$azQaxq3e7rN$q}80e9h1U;hMNWJ4G zZ7TBeD>JH2%L@W5ZWuP4Zma~P+mc^9=lNx-1L?zEJ}Mp9%=v8kH_@a=S|n#(U7lj) zU=^aS+<`VRu{|vtOq4KOZMdVb?1`G0?OJf}_;DrHU4C(UqO!%RYzBoQ7ENywB1Pr7 zv(vcn<7sU!l>>UP%5OhboL<#IVF&FLuf;ofQkXbndq)P`62!6=Sh5L5N{?G=KLu7T z#Zw}ME)jjpF|E zmXHTaZWr$LoRLcT8<(k`=(C~#DS~R+23BZE0Ag+YU2(9KjC*qWk>3u;C05Q8of!d- zUFw!jFxDi!>2s$)cAcYs-Y{T!emm@^e}VWkxA;5tRrvWyvm^qzONEI}46wyN>B MoMV8L095h60D(LA`2YX_ diff --git a/application/src/test/resources/lwm2m/credentials/serverKeyStore.jks b/application/src/test/resources/lwm2m/credentials/serverKeyStore.jks index f1f03005e129985fd17b09e8dd6e0e2caa2d366f..fc541a3b18111312545da774be682ddb893d72c2 100644 GIT binary patch literal 3806 zcmezO_TO6u1_mY|W&_iFnRz9tMY*XdnTaK-$%zaMjFr!(OnJ+|8lh)uUJkHs&Ff*|-7)Tn58;G(ohq5pW^ZBF}XC&q+6y@ia zC^$PBD2VeK85)=wm>U`cNz*6^ej`JmfT^JgRKP&dP~JcmqFD^88QDo7Lm~}?+1SDM zF)>0dW@cn(c4A;T@VS|9lH1dLZ_jKt-`U6Fea+QH`BYo9IL#mhY`ZKUix`Ut^Mt&kdKuN{mQQtB zUi5*fk(H(TpaCDyakBi3jQ?4HzGY-H5CZXqL3|DaHXy~s$Y3B35>sZ8Fc51H(VZk$ zxqXJN`J@Z|H3z%zhgCAvhN1=-vnPXr8zz+tX`Lo>Xmwt;`4ciQ-RUJ$iP{g zT2z)=1Wd({+%)YhP`KWp7MPN_wAmP07`2!L85vm_Sh9C4soL}0b=E$Mg=v$soQ%&E ze-UkGh(7!8*z23GK6Ux3JW7}-CdGRxUb*$s#*H}>yS#3hWc=9SwbZeCr>?;9ccr&_ zYgxQJ(!V{(HT$V`QR>5%H$^P@+qt&id0fzvyI|3@t`COBEccC7VLd&rY7L^CxjgF5%vL_s_{?G7bKy zS)IAVKm?R*1X*|uxSKe0@{<#DGV+T{3^>7wiG|4kHQ!?`JcL1NRatlpxY#&=anH)i z&di7!(9G@(1};nrn!6{v?BTePd(kMjNR;uU^|$ugrFS$Q9umsi${YQ5&H^TdsFeM= z90yik-kWEXGgr=O`{J&$y|KM7LUoxI7hXH8CBN4cMod%AvKSoW?FOfOlv-vGHtp+D%Gs zJc(4Dp!3?mQ2w@XY2U+&4qJBf-UtR0M-HvV>(w&A3ge>joNbbJ!JgUYuAZ6QqPAQv zQ)->$ngpAsU+XTp#rL^@s{=MjR72u+>TO(gfe)|D(-6Qb2h|ya67LSJ{;U~ z=j!t7JN^Y!?~YK;neEaj@$>WA(44J%&My4R*S)D{)LMO8UGTuGsl5-*N3oSb>J z)Lvu@%h8K!V%cK1e3=wtzAp%{I$kwDp0DD0XHV~}Lt>(a&rX)h7S2h_+IP<}98nI8 zw&b9#Z#uT*m>7g0Sr@a2o|KM=nlfPCDFR|qSR>n^QvogiV9x@mC9xTLNo*EnfL$LA zvreFaKLuHbh@1iK`FxVtS7y-vtNrrlO-x^(POD+NzGweDCVTEHScmMzZ literal 3120 zcmb7?2{aUH8^>pc!7vD8SJuc-1`|edMaB}L#3hEIn2uW2`P}c^@7{CI`Of+7ciwZ}=bZolyzhB_&;LOXp|T(#9fHWR%m9ItbV+-x zKt^B&k!6&g$TD;y_aTU&h`(7NJUtQQdm?)wf;$;l{&)ms27)qt5f2d349x$LPW~07 zhj9?PR?blS-^PeIRe7>qzlKfC76Q=$T8-&-wd!1sA1ALX%mpGE>qRQyYQ@=L@jGH9 zwlzgWqguGkP2JL?Z!!ypYphpOvh!i;{et~-hS;E6h914$VaZ5!8ONS3_b=Wn@)`)i zKYN70Z;pqc=Ef9=BZ6&-7Mc9C||ERjTud|b7$z(dsId?92!yS5B)mT1E>WH));h6 zscGKlO-5>NW;KK!m=^Sm-{@5b=e{u4cc}hG#Aiyp_Pl1WDF(ielD~mC|5vv#d66?` z01p7JCm^0D)$63*1>E^R;1m^6Cvg8HCvV$h9O&?oB+R10Azjn)&E@fSqd(w4>ZEr+ z1IBT6>@K7U4KZq-^O9MPREcl;nx!Y#$n(X0Okj3TnT~m@3x}r@y^@w;WXzyC*0NR;wL1QDY4=Xe+yGKi4#Cz3P>2skNX ze>uRv?IFYOdzd0DuJ8H^e7LqzBSE~Fx3Lne^5oxq1R~R_e=}h*Tk!b@kZ_RAR;?l{ z{J^+uvHZ+;TWQu)0!|P65R+2I)-KBL-AhLu#Xs`-`u|F;9yeY!&*3cccvly^p1PMz zyMxEHw66MVhv)98S|B(H3j0?YI?D!(*#8}zC+ zG!ze)K6)xg$;W8hbE$7LnbCFK&4hh4T?=Oj>{}3gaUEkwOO-HSjF-hh`M-9KCL8FF zx<$&+g{3}q7=uCkTa@F3W*C}%9J9mCa;8t2WU)uFSJSD6*5hIUr8=*2SN3rCas z4x)TN?m?Z64X|Cv-H3++S5Lpfc5%k>H$WHo%^59yadG?RoBQ?m1>f54-AXh~P~(>R zqC^XOZtLnW@yWvVC5KaGa}jx%^;6F_Tbei~JJCLQt8O5_;aq_c)E@Z>B>!!;R3Yv>a7DsSefN9@{g5~bOq&uvm=C&ZGW_PJWzVL!{m z+V&Zd1lb$Qfpai(d|L0C+~?aPCZ)UTIF-jM*`9d; zHzS?%D(y)s)GGbj?UZa>K!DWq$lJ3hbzjmjaYRrACpu5@Q((*X;X}J{luqW90{G+` zNkJfC{dMjy7Ji1Z0Xev!&0(^?WR&fr2NF5|K(g|;@8;NN zWAdCdufb47p$JuDWwi*on_}Bq@mpN|QR_p>@WPUe>Drved6RL>seLL2RZ+kO1YeUt zE_J!GdFQ&wF-wPr{*tvR31(b5<_l`37f+1783!MaTI!mb?tgCBFm zCj}NS3Sk*Cp(aRaP=;DWk(+*7r_DRKZ%gEDal=g)_P@%?Vje2?bxqH2gztp=6a0;) zhDKc%Jb7KJI0u9&AAdD=<*Pr$H}{f@s4u-BJK@B-8a%qCKhoe@SR6NY(oYFlR+}$w zct3j0iKKxnC14)p1YgW~FRs5oI*4=Jl)r>rvQ;cAf>)V6P^Gqq;7Cw&4nkKQgIXq__R(T-&~r`Kr=kc<#4!o>-H%`Wuz8 zs(}?jTs-g9LG>B(ykbMLQ+Tq%Y@fH>nu(5&RR-o;;LVZ7h?S+xzE_EMFEqkOD(^XX zIqlf;=YQF6cyrW;E>D*?!>`YjIKVqLLU?Zv3b&hhwU&32v;;PQEvoAsri#F*ka7<& zc_;1q*ZPT~(BhZH&hB#GQ*AW>8{4i9?_$d|N*y2HJx406k(b?Ar1<1#_v&1#e#Li&t1P`~}OT}+!`r>=7 z*a}U}ha~P$MZMkXmV4JjtQFTM9bOZPvMB?7OYx`1ta`;SlF{WXrlC?AfeH)lvRjui z!?dnCtlmcR6=7OhyTshguRD@~R`Zujn6Pptx;s9x{NlNJc2j%y9~r1JT97t(|4o9j zYf0H_wHE$+qo3>w%ZGV+EL|(KIY352RtdVzbDY$h3h7)~g0z0ygEt5F{qj;EmjY(d z0T~&WsKR97y(@-B#Wn0Ttx2W|BV%)9OE7-U^8VGpv)<63&H9;y>(BR2@h+afz{{_8 zgGUCE@+m8`NLv5wo%ve^47(q2^;JKD8@!R7?K6(Ak;g%mRRH@hV~)=snhOUarRy75 zx)iA%8O4MjRgDYs$*MMBNqol1JF>CL5SoaFr zI4I$}{w)@M=v7w=C@)e^yFuvI^p?z50d1`xeBHOqcPT}v!Ii;XXUAdD6y?tA-2TUA zdc-adXpE1Ydo61DYOsyXi&+R}eb)WfJ#jPIf~UP8YIXDv1e!M%$dLm{eSY*_FJb%ZDa!T^?GqXP+m0raq|ZrxS|MbSSj qL;D3%%-d?jak~%bVSeI3r^Om(r)};qh1!z#p-K Date: Tue, 8 Jun 2021 10:50:36 +0300 Subject: [PATCH 5/9] fixed lwm2m x509 with cert security --- ...LwM2mCredentialsSecurityInfoValidator.java | 12 +-- .../TbLwM2MDtlsCertificateVerifier.java | 75 +++++++------------ .../server/client/LwM2mClientContextImpl.java | 2 - 3 files changed, 35 insertions(+), 54 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index c57c2295c6..13d6fd6568 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -22,16 +22,16 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.springframework.stereotype.Component; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; @@ -104,9 +104,10 @@ public class LwM2mCredentialsSecurityInfoValidator { result.setEndpoint(endpoint); result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode()); } else { + result.setEndpoint(credentials.getClient().getEndpoint()); switch (credentials.getClient().getSecurityConfigClientMode()) { case NO_SEC: - createClientSecurityInfoNoSec(result, endpoint); + createClientSecurityInfoNoSec(result); break; case PSK: createClientSecurityInfoPSK(result, endpoint, credentials.getClient()); @@ -125,8 +126,7 @@ public class LwM2mCredentialsSecurityInfoValidator { return result; } - private void createClientSecurityInfoNoSec(TbLwM2MSecurityInfo result, String endpoint) { - result.setEndpoint(endpoint); + private void createClientSecurityInfoNoSec(TbLwM2MSecurityInfo result) { result.setSecurityInfo(null); result.setSecurityMode(NO_SEC); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 7b81e733bc..dcd7fa89bb 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -29,22 +29,21 @@ 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.util.ServerNames; +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; 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.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.util.SslUtil; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; -import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; +import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import javax.annotation.PostConstruct; @@ -57,8 +56,6 @@ import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @Slf4j @Component @@ -66,9 +63,10 @@ import java.util.concurrent.TimeUnit; @RequiredArgsConstructor public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier { - private final TransportService transportService; private final TbLwM2MDtlsSessionStore sessionStorage; private final LwM2MTransportServerConfig config; + private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; + private final TbEditableSecurityStore securityStore; @SuppressWarnings("deprecation") private StaticCertificateVerifier staticCertificateVerifier; @@ -119,48 +117,33 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer String strCert = SslUtil.getCertificateString(cert); String sha3Hash = EncryptionUtil.getSha3Hash(strCert); - final ValidateDeviceCredentialsResponse[] deviceCredentialsResponse = new ValidateDeviceCredentialsResponse[1]; - CountDownLatch latch = new CountDownLatch(1); - transportService.process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(sha3Hash).build(), - new TransportServiceCallback<>() { - @Override - public void onSuccess(ValidateDeviceCredentialsResponse msg) { - if (!StringUtils.isEmpty(msg.getCredentials())) { - deviceCredentialsResponse[0] = msg; - } - latch.countDown(); - } - - @Override - public void onError(Throwable e) { - log.error(e.getMessage(), e); - latch.countDown(); - } - }); - if (latch.await(10, TimeUnit.SECONDS)) { - ValidateDeviceCredentialsResponse msg = deviceCredentialsResponse[0]; - if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { - LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class); - if(!credentials.getClient().getSecurityConfigClientMode().equals(LwM2MSecurityMode.X509)){ - continue; - } - X509ClientCredentials config = (X509ClientCredentials) credentials.getClient(); - String certBody = config.getCert(); - String endpoint = config.getEndpoint(); - if (strCert.equals(certBody)) { - x509CredentialsFound = true; - DeviceProfile deviceProfile = msg.getDeviceProfile(); - if (msg.hasDeviceInfo() && deviceProfile != null) { - sessionStorage.put(endpoint, new TbX509DtlsSessionInfo(cert.getSubjectX500Principal().getName(), msg)); - break; + TbLwM2MSecurityInfo securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, LwM2mTransportUtil.LwM2mTypeServer.CLIENT); + ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null; + if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) { + LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class); + if (!credentials.getClient().getSecurityConfigClientMode().equals(LwM2MSecurityMode.X509)) { + continue; + } + X509ClientCredentials config = (X509ClientCredentials) credentials.getClient(); + String certBody = config.getCert(); + String endpoint = config.getEndpoint(); + if (strCert.equals(certBody)) { + x509CredentialsFound = true; + DeviceProfile deviceProfile = msg.getDeviceProfile(); + if (msg.hasDeviceInfo() && deviceProfile != null) { + sessionStorage.put(endpoint, new TbX509DtlsSessionInfo(cert.getSubjectX500Principal().getName(), msg)); + try { + securityStore.put(securityInfo); + } catch (NonUniqueSecurityInfoException e) { + log.trace("Failed to add security info: {}", securityInfo, e); } - } else { - log.trace("[{}][{}] Certificate mismatch. Expected: {}, Actual: {}", endpoint, sha3Hash, strCert, certBody); + break; } + } else { + log.trace("[{}][{}] Certificate mismatch. Expected: {}, Actual: {}", endpoint, sha3Hash, strCert, certBody); } } - } catch (InterruptedException | - CertificateEncodingException | + } catch (CertificateEncodingException | CertificateExpiredException | CertificateNotYetValidException e) { log.error(e.getMessage(), e); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index ac57040d7b..aa204ae868 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.server.registration.Registration; -import org.eclipse.leshan.server.security.EditableSecurityStore; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; @@ -29,7 +28,6 @@ import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore; -import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import java.util.Arrays; import java.util.Collection; From 7dc6ee10d889add002eba31eb4355ed93e398d33 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 8 Jun 2021 11:57:41 +0300 Subject: [PATCH 6/9] refactored --- .../server/transport/TransportSqlTestSuite.java | 14 +++++++------- .../lwm2m/server/store/TbLwM2mStoreFactory.java | 7 +------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java index d059ea1449..25df3bee00 100644 --- a/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java @@ -26,13 +26,13 @@ import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ -// "org.thingsboard.server.transport.*.rpc.sql.*Test", -// "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", -// "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", -// "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", -// "org.thingsboard.server.transport.*.attributes.request.sql.*Test", -// "org.thingsboard.server.transport.*.claim.sql.*Test", -// "org.thingsboard.server.transport.*.provision.sql.*Test", + "org.thingsboard.server.transport.*.rpc.sql.*Test", + "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", + "org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", + "org.thingsboard.server.transport.*.attributes.updates.sql.*Test", + "org.thingsboard.server.transport.*.attributes.request.sql.*Test", + "org.thingsboard.server.transport.*.claim.sql.*Test", + "org.thingsboard.server.transport.*.provision.sql.*Test", "org.thingsboard.server.transport.lwm2m.*Test" }) public class TransportSqlTestSuite { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java index 3dd9ebd3ed..154de636de 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java @@ -17,19 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.store; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore; -import org.eclipse.leshan.server.security.EditableSecurityStore; -import org.eclipse.leshan.server.security.InMemorySecurityStore; -import org.eclipse.leshan.server.security.SecurityStore; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.Optional; @@ -56,7 +51,7 @@ public class TbLwM2mStoreFactory { } @Bean - private TbSecurityStore securityStore() { + private TbEditableSecurityStore securityStore() { return new TbLwM2mSecurityStore(redisConfiguration.isPresent() && useRedis ? new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new TbInMemorySecurityStore(), validator); } From c61c52bb8bb92f969f3167ba050bc083f685efdf Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 8 Jun 2021 12:18:05 +0300 Subject: [PATCH 7/9] removed redundant annotation --- .../transport/lwm2m/server/store/TbLwM2mSecurityStore.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java index 8302af64fa..cbdb9faf07 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java @@ -32,7 +32,6 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.Collection; @Slf4j -@TbLwM2mTransportComponent public class TbLwM2mSecurityStore implements TbEditableSecurityStore { private final TbEditableSecurityStore securityStore; From ef54e5580ec55ffcc521bebd47e5d43324ffe5bc Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 8 Jun 2021 14:44:16 +0300 Subject: [PATCH 8/9] Slect default LwM2M content type based on the version of the client --- .../DefaultLwM2MTransportMsgHandler.java | 136 ++++++++---------- .../lwm2m/server/LwM2mServerListener.java | 4 +- .../server/LwM2mTransportMsgHandler.java | 4 +- .../lwm2m/server/LwM2mTransportRequest.java | 22 ++- .../lwm2m/server/client/LwM2mClient.java | 13 +- .../server/client/LwM2mClientContext.java | 11 +- .../server/client/LwM2mClientContextImpl.java | 14 +- .../lwm2m/server/client/LwM2mFwSwUpdate.java | 12 +- 8 files changed, 92 insertions(+), 124 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index 6c5bbb5970..3f8901b028 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -31,7 +31,6 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.observation.Observation; -import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.WriteRequest; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.server.registration.Registration; @@ -100,6 +99,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_WARN; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE; @@ -183,39 +183,38 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler */ public void onRegistered(Registration registration, Collection previousObservations) { registrationExecutor.submit(() -> { + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); try { log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); - LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); if (lwM2MClient != null) { this.clientContext.register(lwM2MClient, registration); + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_INFO + ": Client registered with registration id: " + registration.getId()); SessionInfoProto sessionInfo = lwM2MClient.getSession(); - if (sessionInfo != null) { - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); - TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() - .setSessionInfo(sessionInfo) - .setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN)) - .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build()) - .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().build()) - .build(); - transportService.process(msg, null); - this.getInfoFirmwareUpdate(lwM2MClient, null); - this.getInfoSoftwareUpdate(lwM2MClient, null); - this.initLwM2mFromClientValue(registration, lwM2MClient); - this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_INFO + ": Client create after Registration"); - } else { - log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); - } + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); + TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() + .setSessionInfo(sessionInfo) + .setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN)) + .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build()) + .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().build()) + .build(); + transportService.process(msg, null); + this.getInfoFirmwareUpdate(lwM2MClient, null); + this.getInfoSoftwareUpdate(lwM2MClient, null); + this.initClientTelemetry(lwM2MClient); } else { - log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); + log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null); } } catch (LwM2MClientStateException stateException) { if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) { log.info("[{}] retry registration due to race condition: [{}].", registration.getEndpoint(), stateException.getState()); // Race condition detected and the client was in progress of unregistration while new registration arrived. Let's try again. onRegistered(registration, previousObservations); + } else { + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_WARN + ": Client registration failed due to invalid state: " + stateException.getState()); } } catch (Throwable t) { log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t); + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_WARN + ": Client registration failed due to: " + t.getMessage()); } }); } @@ -232,7 +231,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler clientContext.updateRegistration(lwM2MClient, registration); TransportProtos.SessionInfoProto sessionInfo = lwM2MClient.getSession(); this.reportActivityAndRegister(sessionInfo); - if (registration.getQueueMode()) { + if (registration.usesQueueMode()) { LwM2mQueuedRequest request; while ((request = lwM2MClient.getQueuedRequests().poll()) != null) { request.send(); @@ -292,8 +291,11 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @Override public void setCancelObservationsAll(Registration registration) { if (registration != null) { - this.lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL_ALL, - null, null, this.config.getTimeout(), null); + LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); + if (client != null && client.getRegistration() != null && client.getRegistration().getId().equals(registration.getId())) { + this.lwM2mTransportRequest.sendAllRequest(client, null, OBSERVE_CANCEL_ALL, + null, null, this.config.getTimeout(), null); + } } } @@ -459,13 +461,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler this.rpcSubscriptions.put(requestUUID, toDeviceRpcRequestMsg.getExpirationTime()); Lwm2mClientRpcRequest lwm2mClientRpcRequest = null; try { - Registration registration = clientContext.getClientBySessionInfo(sessionInfo).getRegistration(); + LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); + Registration registration = client.getRegistration(); lwm2mClientRpcRequest = new Lwm2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this); if (lwm2mClientRpcRequest.getErrorMsg() != null) { lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name()); this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo); } else { - lwM2mTransportRequest.sendAllRequest(registration, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(), + lwM2mTransportRequest.sendAllRequest(client, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(), null, lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(), this.config.getTimeout(), lwm2mClientRpcRequest); @@ -519,17 +522,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler log.info("[{}] toServerRpcResponse", toServerResponse); } - /** - * Trigger Server path = "/1/0/8" - *

- * Trigger bootStrap path = "/1/0/9" - have to implemented on client - */ - @Override - public void doTrigger(Registration registration, String path) { - lwM2mTransportRequest.sendAllRequest(registration, path, EXECUTE, - ContentFormat.TLV.getName(), null, this.config.getTimeout(), null); - } - /** * Deregister session in transport * @@ -572,7 +564,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * @param registrationId - Id of Registration LwM2M Client */ @Override - public void sendLogsToThingsboard2(String registrationId, String logMsg) { + public void sendLogsToThingsboard(String registrationId, String logMsg) { sendLogsToThingsboard(clientContext.getClientByRegistrationId(registrationId), logMsg); } @@ -595,24 +587,23 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * - Read Request to the client after registration to read all resource values for all objects * - then Observe Request to the client marked as observe from the profile configuration. * - * @param registration - Registration LwM2M Client - * @param lwM2MClient - object with All parameters off client + * @param lwM2MClient - object with All parameters off client */ - private void initLwM2mFromClientValue(Registration registration, LwM2mClient lwM2MClient) { - LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration); - Set clientObjects = clientContext.getSupportedIdVerInClient(registration); + private void initClientTelemetry(LwM2mClient lwM2MClient) { + LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(lwM2MClient.getProfileId()); + Set clientObjects = clientContext.getSupportedIdVerInClient(lwM2MClient); if (clientObjects != null && clientObjects.size() > 0) { if (LWM2M_STRATEGY_2 == LwM2mTransportUtil.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) { // #2 lwM2MClient.getPendingReadRequests().addAll(clientObjects); - clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, READ, ContentFormat.TLV.getName(), + clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, READ, null, this.config.getTimeout(), null)); } // #1 - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, READ, clientObjects); - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, OBSERVE, clientObjects); - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, WRITE_ATTRIBUTES, clientObjects); - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, DISCOVER, clientObjects); + this.initReadAttrTelemetryObserveToClient(lwM2MClient, READ, clientObjects); + this.initReadAttrTelemetryObserveToClient(lwM2MClient, OBSERVE, clientObjects); + this.initReadAttrTelemetryObserveToClient(lwM2MClient, WRITE_ATTRIBUTES, clientObjects); + this.initReadAttrTelemetryObserveToClient(lwM2MClient, DISCOVER, clientObjects); } } @@ -749,15 +740,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } } - /** - * Start observe/read: Attr/Telemetry - * #1 - Analyze: path in resource profile == client resource - * - * @param registration - - */ - private void initReadAttrTelemetryObserveToClient(Registration registration, LwM2mClient lwM2MClient, + private void initReadAttrTelemetryObserveToClient(LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, Set clientObjects) { - LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration); + LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(lwM2MClient.getProfileId()); Set result = null; ConcurrentHashMap params = null; if (READ.equals(typeOper)) { @@ -789,7 +774,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler lwM2MClient.getPendingReadRequests().addAll(pathSend); ConcurrentHashMap finalParams = params; pathSend.forEach(target -> { - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TEXT.getName(), + lwM2mTransportRequest.sendAllRequest(lwM2MClient, target, typeOper, finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null); }); if (OBSERVE.equals(typeOper)) { @@ -1023,7 +1008,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) { // update value in Resources clients.forEach(client -> { - this.readObserveFromProfile(client.getRegistration(), sendAttrToThingsboard.getPathPostParametersAdd(), READ); + this.readObserveFromProfile(client, sendAttrToThingsboard.getPathPostParametersAdd(), READ); }); } // #4.2 del @@ -1050,12 +1035,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler clients.forEach(client -> { Registration registration = client.getRegistration(); if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) { - this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); + this.readObserveFromProfile(client, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); } // 5.3 del // send Request cancel observe to Client if (postObserveAnalyzer.getPathPostParametersDel().size() > 0) { - this.cancelObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersDel()); + this.cancelObserveFromProfile(client, postObserveAnalyzer.getPathPostParametersDel()); } }); } @@ -1092,19 +1077,18 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler * Update Resource value after change RezAttrTelemetry in config Profile * send response Read to Client and add path to pathResAttrTelemetry in LwM2MClient.getAttrTelemetryObserveValue() * - * @param registration - Registration LwM2M Client - * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] + * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] */ - private void readObserveFromProfile(Registration registration, Set targets, LwM2mTypeOper typeOper) { + private void readObserveFromProfile(LwM2mClient client, Set targets, LwM2mTypeOper typeOper) { targets.forEach(target -> { LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target)); if (pathIds.isResource()) { if (READ.equals(typeOper)) { - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, - ContentFormat.TLV.getName(), null, this.config.getTimeout(), null); + lwM2mTransportRequest.sendAllRequest(client, target, typeOper, + null, this.config.getTimeout(), null); } else if (OBSERVE.equals(typeOper)) { - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, - null, null, this.config.getTimeout(), null); + lwM2mTransportRequest.sendAllRequest(client, target, typeOper, + null, this.config.getTimeout(), null); } } }); @@ -1153,13 +1137,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler // #6.2 if (analyzerParameters.getPathPostParametersAdd().size() > 0) { clients.forEach(client -> { - Registration registration = client.getRegistration(); - Set clientObjects = clientContext.getSupportedIdVerInClient(registration); + Set clientObjects = clientContext.getSupportedIdVerInClient(client); Set pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) .collect(Collectors.toUnmodifiableSet()); if (!pathSend.isEmpty()) { ConcurrentHashMap finalParams = lwm2mAttributesNew; - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TEXT.getName(), + pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES, finalParams.get(target), this.config.getTimeout(), null)); } }); @@ -1168,7 +1151,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler if (analyzerParameters.getPathPostParametersDel().size() > 0) { clients.forEach(client -> { Registration registration = client.getRegistration(); - Set clientObjects = clientContext.getSupportedIdVerInClient(registration); + Set clientObjects = clientContext.getSupportedIdVerInClient(client); Set pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) .collect(Collectors.toUnmodifiableSet()); if (!pathSend.isEmpty()) { @@ -1176,8 +1159,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler Map params = (Map) lwm2mAttributesOld.get(target); params.clear(); params.put(OBJECT_VERSION, ""); - lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TEXT.getName(), - params, this.config.getTimeout(), null); + lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES, params, this.config.getTimeout(), null); }); } }); @@ -1185,12 +1167,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } - private void cancelObserveFromProfile(Registration registration, Set paramAnallyzer) { - LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint()); + private void cancelObserveFromProfile(LwM2mClient lwM2mClient, Set paramAnallyzer) { paramAnallyzer.forEach(pathIdVer -> { - if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) { - lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, OBSERVE_CANCEL, null, - null, this.config.getTimeout(), null); + if (this.getResourceValueFromLwM2MClient(lwM2mClient, pathIdVer) != null) { + lwM2mTransportRequest.sendAllRequest(lwM2mClient, pathIdVer, OBSERVE_CANCEL, null, this.config.getTimeout(), null); } } ); @@ -1198,9 +1178,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler private void updateResourcesValueToClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) { if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) { - lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, WRITE_REPLACE, - ContentFormat.TLV.getName(), valueNew, - this.config.getTimeout(), null); + lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, WRITE_REPLACE, valueNew, this.config.getTimeout(), null); } else { log.error("Failed update resource [{}] [{}]", path, valueNew); String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad", diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index f1839e718a..b69825843e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -87,7 +87,7 @@ public class LwM2mServerListener { @Override public void cancelled(Observation observation) { String msg = String.format("%s: Canceled Observation %s.", LOG_LW2M_INFO, observation.getPath()); - service.sendLogsToThingsboard2(observation.getRegistrationId(), msg); + service.sendLogsToThingsboard(observation.getRegistrationId(), msg); log.warn(msg); } @@ -109,7 +109,7 @@ public class LwM2mServerListener { String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO, observation.getPath()); log.warn(msg); - service.sendLogsToThingsboard2(registration.getId(), msg); + service.sendLogsToThingsboard(registration.getId(), msg); } }; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java index 36f1209ff3..9709d71ef5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportMsgHandler.java @@ -58,15 +58,13 @@ public interface LwM2mTransportMsgHandler { void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse); - void doTrigger(Registration registration, String path); - void doDisconnect(TransportProtos.SessionInfoProto sessionInfo); void onAwakeDev(Registration registration); void sendLogsToThingsboard(LwM2mClient client, String msg); - void sendLogsToThingsboard2(String registrationId, String msg); + void sendLogsToThingsboard(String registrationId, String msg); LwM2MTransportServerConfig getConfig(); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index d382b0b734..ad515840b0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java @@ -116,21 +116,19 @@ public class LwM2mTransportRequest { new NamedThreadFactory(String.format("LwM2M %s channel response after request", RESPONSE_REQUEST_CHANNEL))); } - /** - * Device management and service enablement, including Read, Write, Execute, Discover, Create, Delete and Write-Attributes - * - * @param registration - - * @param targetIdVer - - * @param typeOper - - * @param contentFormatName - - */ + public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) { + sendAllRequest(lwM2MClient, targetIdVer, typeOper, lwM2MClient.getDefaultContentFormat(), params, timeoutInMs, lwm2mClientRpcRequest); + } + - public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper, - String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) { - LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByEndpoint(registration.getEndpoint()); + public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper, + ContentFormat contentFormat, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) { + Registration registration = lwM2MClient.getRegistration(); try { String target = convertPathFromIdVerToObjectId(targetIdVer); - ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; + if(contentFormat == null){ + contentFormat = ContentFormat.DEFAULT; + } LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null; if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { if (lwM2MClient.isValidObjectVersion(targetIdVer)) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 1fc876cc45..449a3f7d8b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -26,6 +26,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance; 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.request.ContentFormat; import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.SecurityInfo; @@ -69,7 +70,8 @@ public class LwM2mClient implements Cloneable { @Getter private final String endpoint; private final Lock lock; - @Getter @Setter + @Getter + @Setter private LwM2MClientState state; @Getter private final Map resources; @@ -385,5 +387,14 @@ public class LwM2mClient implements Cloneable { } } + public ContentFormat getDefaultContentFormat() { + if (registration == null) { + return ContentFormat.DEFAULT; + } else if (registration.getLwM2mVersion().equals("1.0")) { + return ContentFormat.TLV; + } else { + return ContentFormat.TEXT; + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index e2e24ad1ff..2f2799bb03 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -40,15 +40,6 @@ public interface LwM2mClientContext { void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException; - -// LwM2mClient getOrRegister(Registration registration); - -// LwM2mClient registerOrUpdate(Registration registration); - -// LwM2mClient fetchClientByEndpoint(String endpoint); - -// Registration getRegistration(String registrationId); - Collection getLwM2mClients(); Map getProfiles(); @@ -61,7 +52,7 @@ public interface LwM2mClientContext { LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile); - Set getSupportedIdVerInClient(Registration registration); + Set getSupportedIdVerInClient(LwM2mClient registration); LwM2mClient getClientByDeviceId(UUID deviceId); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index aa204ae868..37113a3df1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -205,19 +205,13 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } } - /** - * if isVer - ok or default ver=DEFAULT_LWM2M_VERSION - * - * @param registration - - * @return - all objectIdVer in client - */ @Override - public Set getSupportedIdVerInClient(Registration registration) { + public Set getSupportedIdVerInClient(LwM2mClient client) { Set clientObjects = ConcurrentHashMap.newKeySet(); - Arrays.stream(registration.getObjectLinks()).forEach(url -> { - LwM2mPath pathIds = new LwM2mPath(url.getUrl()); + Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> { + LwM2mPath pathIds = new LwM2mPath(link.getUrl()); if (!pathIds.isRoot()) { - clientObjects.add(convertPathFromObjectIdToIdVer(url.getUrl(), registration)); + clientObjects.add(convertPathFromObjectIdToIdVer(link.getUrl(), client.getRegistration())); } }); return (clientObjects.size() > 0) ? clientObjects : null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java index 7a93d15988..a81021eed1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java @@ -169,7 +169,7 @@ public class LwM2mFwSwUpdate { LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE.name(), FW_PACKAGE_ID); handler.sendLogsToThingsboard(lwM2MClient, fwMsg); log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer); - request.sendAllRequest(this.lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(), + request.sendAllRequest(this.lwM2MClient, targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE, firmwareChunk, handler.config.getTimeout(), this.rpcRequest); } else { @@ -202,8 +202,7 @@ public class LwM2mFwSwUpdate { public void executeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) { this.setStateUpdate(UPDATING.name()); this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null); - request.sendAllRequest(this.lwM2MClient.getRegistration(), this.pathInstallId, EXECUTE, ContentFormat.TLV.getName(), - null, 0, this.rpcRequest); + request.sendAllRequest(this.lwM2MClient, this.pathInstallId, EXECUTE, null, 0, this.rpcRequest); } /** @@ -334,10 +333,10 @@ public class LwM2mFwSwUpdate { } private void observeStateUpdate(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) { - request.sendAllRequest(lwM2MClient.getRegistration(), + request.sendAllRequest(lwM2MClient, convertPathFromObjectIdToIdVer(this.pathStateId, this.lwM2MClient.getRegistration()), OBSERVE, null, null, 0, null); - request.sendAllRequest(lwM2MClient.getRegistration(), + request.sendAllRequest(lwM2MClient, convertPathFromObjectIdToIdVer(this.pathResultId, this.lwM2MClient.getRegistration()), OBSERVE, null, null, 0, null); } @@ -364,8 +363,7 @@ public class LwM2mFwSwUpdate { this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer( this.pathResultId, this.lwM2MClient.getRegistration())); this.pendingInfoRequestsStart.forEach(pathIdVer -> { - request.sendAllRequest(this.lwM2MClient.getRegistration(), pathIdVer, OBSERVE, ContentFormat.TLV.getName(), - null, 0, this.rpcRequest); + request.sendAllRequest(this.lwM2MClient, pathIdVer, OBSERVE, null, 0, this.rpcRequest); }); } From 4287d838be199f2a37463089748fc1359fa75506 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 8 Jun 2021 15:27:38 +0300 Subject: [PATCH 9/9] Refactoring or requests to the client --- .../DefaultLwM2MTransportMsgHandler.java | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index 3f8901b028..e05b3de0ac 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -740,8 +740,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler } } - private void initReadAttrTelemetryObserveToClient(LwM2mClient lwM2MClient, - LwM2mTypeOper typeOper, Set clientObjects) { + private void initReadAttrTelemetryObserveToClient(LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, Set clientObjects) { LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(lwM2MClient.getProfileId()); Set result = null; ConcurrentHashMap params = null; @@ -762,28 +761,42 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()); result = params.keySet(); } - if (result != null && !result.isEmpty()) { - // #1 - Set pathSend = result.stream().filter(target -> { - return target.split(LWM2M_SEPARATOR_PATH).length < 3 ? - clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]) : - clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1] + "/" + target.split(LWM2M_SEPARATOR_PATH)[2]); - } + sendRequestsToClient(lwM2MClient, typeOper, clientObjects, result, params); + } + + private void sendRequestsToClient(LwM2mClient lwM2MClient, LwM2mTypeOper operationType, Set supportedObjectIds, Set desiredObjectIds, ConcurrentHashMap params) { + if (desiredObjectIds != null && !desiredObjectIds.isEmpty()) { + Set targetObjectIds = desiredObjectIds.stream().filter(target -> isSupportedTargetId(supportedObjectIds, target) ).collect(Collectors.toUnmodifiableSet()); - if (!pathSend.isEmpty()) { - lwM2MClient.getPendingReadRequests().addAll(pathSend); - ConcurrentHashMap finalParams = params; - pathSend.forEach(target -> { - lwM2mTransportRequest.sendAllRequest(lwM2MClient, target, typeOper, - finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null); + if (!targetObjectIds.isEmpty()) { + //TODO: remove this side effect? + lwM2MClient.getPendingReadRequests().addAll(targetObjectIds); + targetObjectIds.forEach(target -> { + Object additionalParams = params != null ? params.get(target) : null; + lwM2mTransportRequest.sendAllRequest(lwM2MClient, target, operationType, additionalParams, this.config.getTimeout(), null); }); - if (OBSERVE.equals(typeOper)) { + if (OBSERVE.equals(operationType)) { lwM2MClient.initReadValue(this, null); } } } } + private boolean isSupportedTargetId(Set supportedIds, String targetId) { + String[] targetIdParts = targetId.split(LWM2M_SEPARATOR_PATH); + if (targetIdParts.length <= 1) { + return false; + } + String targetIdSearch = targetIdParts[0]; + for (int i = 1; i < targetIdParts.length; i++) { + targetIdSearch += "/" + targetIdParts[i]; + if (supportedIds.contains(targetIdSearch)) { + return true; + } + } + return false; + } + private ConcurrentHashMap getPathForWriteAttributes(JsonObject objectJson) { ConcurrentHashMap pathAttributes = new Gson().fromJson(objectJson.toString(), new TypeToken>() {