From 5241c371dfa93c4cceff6de14546b986a522a180 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 16 Feb 2022 16:18:49 +0200 Subject: [PATCH 1/4] lwm2m: The method "getTasks" is thread-safe --- .../LwM2mDefaultBootstrapSessionManager.java | 27 ++-- .../LwM2MBootstrapClientInstanceIds.java | 31 +++++ ...LwM2MBootstrapConfigStoreTaskProvider.java | 120 +++++++++++------- .../store/LwM2MBootstrapTaskProvider.java | 26 ++++ 4 files changed, 153 insertions(+), 51 deletions(-) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapClientInstanceIds.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapTaskProvider.java 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 15bf71b917..886ef918f3 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 @@ -27,6 +27,7 @@ import org.eclipse.leshan.server.bootstrap.BootstrapSession; import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSession; import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSessionManager; +import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import org.eclipse.leshan.server.model.LwM2mBootstrapModelProvider; import org.eclipse.leshan.server.model.StandardBootstrapModelProvider; import org.eclipse.leshan.server.security.BootstrapSecurityStore; @@ -35,6 +36,7 @@ import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapConfigStoreTaskProvider; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; +import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapTaskProvider; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; import java.util.ArrayList; @@ -48,10 +50,10 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LO @Slf4j public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager { - private BootstrapSecurityStore bsSecurityStore; - private SecurityChecker securityChecker; - private BootstrapTaskProvider tasksProvider; - private LwM2mBootstrapModelProvider modelProvider; + private final BootstrapSecurityStore bsSecurityStore; + private final SecurityChecker securityChecker; + private final LwM2MBootstrapTaskProvider tasksProvider; + private final LwM2mBootstrapModelProvider modelProvider; private TransportService transportService; /** @@ -73,7 +75,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession * @param securityChecker used to accept or refuse new {@link BootstrapSession}. */ public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, SecurityChecker securityChecker, - BootstrapTaskProvider tasksProvider, LwM2mBootstrapModelProvider modelProvider) { + LwM2MBootstrapTaskProvider tasksProvider, LwM2mBootstrapModelProvider modelProvider) { super(bsSecurityStore, securityChecker, tasksProvider, modelProvider); this.bsSecurityStore = bsSecurityStore; this.securityChecker = securityChecker; @@ -100,7 +102,12 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession } DefaultBootstrapSession session = new DefaultBootstrapSession(request, clientIdentity, authorized); if (authorized) { - this.sendLogs (request.getEndpointName(), + try { + this.tasksProvider.put(session.getEndpoint()); + } catch (InvalidConfigurationException e){ + log.error("Failed put to lwM2MBootstrapSessionClients by endpoint [{}]", request.getEndpointName(), e); + } + this.sendLogs(request.getEndpointName(), String.format("%s: Bootstrap session started...", LOG_LWM2M_INFO, request.getEndpointName())); } return session; @@ -108,7 +115,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public boolean hasConfigFor(BootstrapSession session) { - BootstrapTaskProvider.Tasks firstTasks = tasksProvider.getTasks(session, null); + BootstrapTaskProvider.Tasks firstTasks = this.tasksProvider.getTasks(session, null); if (firstTasks == null) { return false; } @@ -147,7 +154,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession return requestsToSend.remove(0); } else { if (session.hasMoreTasks()) { - BootstrapTaskProvider.Tasks nextTasks = tasksProvider.getTasks(session, session.getResponses()); + BootstrapTaskProvider.Tasks nextTasks = this.tasksProvider.getTasks(session, session.getResponses()); if (nextTasks == null) { session.setMoreTasks(false); return new BootstrapFinishRequest(); @@ -178,6 +185,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession // on success for bootstrap finish request we stop the session this.sendLogs(bsSession.getEndpoint(), String.format("%s: receives success response for bootstrap finish.", LOG_LWM2M_INFO)); + this.tasksProvider.remove(bsSession.getEndpoint()); return BootstrapPolicy.finished(); } } @@ -199,6 +207,7 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession // on response error for bootstrap finish request we stop the session this.sendLogs(bsSession.getEndpoint(), String.format("%s: error response for request bootstrap finish. Stop the session: %s", LOG_LWM2M_ERROR, bsSession.toString())); + this.tasksProvider.remove(bsSession.getEndpoint()); return BootstrapPolicy.failed(); } } @@ -215,12 +224,14 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession @Override public void end(BootstrapSession bsSession) { this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session finished.", LOG_LWM2M_INFO)); + this.tasksProvider.remove(bsSession.getEndpoint()); } @Override public void failed(BootstrapSession bsSession, BootstrapFailureCause cause) { this.sendLogs(bsSession.getEndpoint(), String.format("%s: Bootstrap session failed because of %s", LOG_LWM2M_ERROR, cause.toString())); + this.tasksProvider.remove(bsSession.getEndpoint()); } private void sendLogs(String endpointName, String logMsg) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapClientInstanceIds.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapClientInstanceIds.java new file mode 100644 index 0000000000..85aee2b9b9 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapClientInstanceIds.java @@ -0,0 +1,31 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.store; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class LwM2MBootstrapClientInstanceIds { + + /** + * Map + */ + private Map securityInstances = new HashMap<>(); + private Map serverInstances = new HashMap<>(); +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index 9100df57a1..edcacfa057 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -30,8 +30,8 @@ import org.eclipse.leshan.core.response.LwM2mResponse; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; import org.eclipse.leshan.server.bootstrap.BootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.BootstrapSession; -import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; import org.eclipse.leshan.server.bootstrap.BootstrapUtil; +import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import java.math.BigInteger; import java.util.ArrayList; @@ -42,28 +42,35 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; @Slf4j -public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvider { +public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTaskProvider { + + protected final ReadWriteLock readWriteLock; + protected final Lock writeLock; private BootstrapConfigStore store; private Map supportedObjects; /** - * Map + * Map */ - protected Map securityInstances; - protected Map serverInstances; - protected Integer bootstrapServerIdOld; - protected Integer bootstrapServerIdNew; + protected Map lwM2MBootstrapSessionClients; public LwM2MBootstrapConfigStoreTaskProvider(BootstrapConfigStore store) { this.store = store; + this.lwM2MBootstrapSessionClients = new ConcurrentHashMap<>(); + readWriteLock = new ReentrantReadWriteLock(); + writeLock = readWriteLock.writeLock(); } @Override @@ -91,13 +98,13 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi BootstrapDiscoverResponse discoverResponse = (BootstrapDiscoverResponse) previousResponse.get(0); if (discoverResponse.isSuccess()) { this.initAfterBootstrapDiscover(discoverResponse); - findSecurityInstanceId(discoverResponse.getObjectLinks()); + findSecurityInstanceId(discoverResponse.getObjectLinks(), session.getEndpoint()); } else { log.warn( "Bootstrap Discover return error {} : to continue bootstrap session without autoIdForSecurityObject mode. {}", discoverResponse, session); } - if (this.securityInstances.get(0) == null) { + if (this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getSecurityInstances().get(0) == null) { log.error( "Unable to find bootstrap server instance in Security Object (0) in response {}: unable to continue bootstrap session with autoIdForSecurityObject mode. {}", discoverResponse, session); @@ -109,8 +116,12 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi return tasks; } BootstrapReadResponse readResponse = (BootstrapReadResponse) previousResponse.get(0); + Integer bootstrapServerIdOld = null; if (readResponse.isSuccess()) { - findServerInstanceId(readResponse); + findServerInstanceId(readResponse, session.getEndpoint()); + if (this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getSecurityInstances().size() > 0 && this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getServerInstances().size() > 0) { + bootstrapServerIdOld = this.findBootstrapServerId(session.getEndpoint()); + } } else { log.warn( "Bootstrap ReadResponse return error {} : to continue bootstrap session without find Server Instance Id. {}", @@ -118,7 +129,8 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi } // create requests from config tasks.requestsToSend = this.toRequests(config, - config.contentFormat != null ? config.contentFormat : session.getContentFormat()); + config.contentFormat != null ? config.contentFormat : session.getContentFormat(), + bootstrapServerIdOld, session.getEndpoint()); } else { // create requests from config tasks.requestsToSend = BootstrapUtil.toRequests(config, @@ -132,9 +144,8 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi return config.autoIdForSecurityObject; } - protected void findSecurityInstanceId(Link[] objectLinks) { + protected void findSecurityInstanceId(Link[] objectLinks, String endpoint) { log.info("Object after discover: [{}]", objectLinks); - this.securityInstances = new HashMap<>(); for (Link link : objectLinks) { if (link.getUriReference().startsWith("/0/")) { try { @@ -142,15 +153,15 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi if (path.isObjectInstance()) { if (link.getLinkParams().containsKey("ssid")) { int serverId = Integer.parseInt(link.getLinkParams().get("ssid").getUnquoted()); - if (!this.securityInstances.containsKey(serverId)) { - this.securityInstances.put(serverId, path.getObjectInstanceId()); + if (!lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(serverId)) { + lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(serverId, path.getObjectInstanceId()); } else { log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId()); } - this.securityInstances.put(Integer.valueOf(link.getLinkParams().get("ssid").getUnquoted()), path.getObjectInstanceId()); + lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(Integer.valueOf(link.getLinkParams().get("ssid").getUnquoted()), path.getObjectInstanceId()); } else { - if (!this.securityInstances.containsKey(0)) { - this.securityInstances.put(0, path.getObjectInstanceId()); + if (!this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(0)) { + this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(0, path.getObjectInstanceId()); } else { log.error("Invalid bootstrapSecurityInstance by [{}]", path.getObjectInstanceId()); } @@ -164,8 +175,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi } } - protected void findServerInstanceId(BootstrapReadResponse readResponse) { - this.serverInstances = new HashMap<>(); + protected void findServerInstanceId(BootstrapReadResponse readResponse, String endpoint) { try { ((LwM2mObject) readResponse.getContent()).getInstances().values().forEach(instance -> { var shId = OPAQUE.equals(instance.getResource(0).getType()) ? new BigInteger((byte[]) instance.getResource(0).getValue()).intValue() : instance.getResource(0).getValue(); @@ -175,23 +185,22 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi } else { shortId = (int) shId; } - serverInstances.put(shortId, instance.getId()); + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().put(shortId, instance.getId()); }); } catch (Exception e) { log.error("Failed find Server Instance Id. ", e); } - if (this.securityInstances != null && this.securityInstances.size() > 0 && this.serverInstances != null && this.serverInstances.size() > 0) { - this.findBootstrapServerId(); - } } - protected void findBootstrapServerId() { - Map filteredMap = this.serverInstances.entrySet() - .stream().filter(x -> !this.securityInstances.containsKey(x.getKey())) + protected Integer findBootstrapServerId(String endpoint) { + Integer bootstrapServerIdOld = null; + Map filteredMap = this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().entrySet() + .stream().filter(x -> !this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(x.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); if (filteredMap.size() > 0) { - this.bootstrapServerIdOld = filteredMap.keySet().stream().findFirst().get(); + bootstrapServerIdOld = filteredMap.keySet().stream().findFirst().get(); } + return bootstrapServerIdOld; } public BootstrapConfigStore getStore() { @@ -213,7 +222,9 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi public List> toRequests(BootstrapConfig bootstrapConfig, - ContentFormat contentFormat) { + ContentFormat contentFormat, + Integer bootstrapServerIdOld, + String endpoint) { List> requests = new ArrayList<>(); Set pathsDelete = new HashSet<>(); List> requestsWrite = new ArrayList<>(); @@ -221,36 +232,38 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi boolean isLwServer = false; /** Map */ Map instances = new HashMap<>(); + Integer bootstrapServerIdNew = null; // handle security int id = 0; for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { if (security.bootstrapServer) { - requestsWrite.add(toWriteRequest(this.securityInstances.get(0), security, contentFormat)); + requestsWrite.add(toWriteRequest(this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0), security, contentFormat)); isBsServer = true; - this.bootstrapServerIdNew = security.serverId; - instances.put(security.serverId, this.securityInstances.get(0)); + bootstrapServerIdNew = security.serverId; + instances.put(security.serverId, this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0)); } else { - if (id == this.securityInstances.get(0)) { + if (id == this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0)) { id++; } requestsWrite.add(toWriteRequest(id, security, contentFormat)); instances.put(security.serverId, id); isLwServer = true; - if (!isBsServer && this.securityInstances.containsKey(security.serverId) && id != this.securityInstances.get(security.serverId)) { - pathsDelete.add("/0/" + this.securityInstances.get(security.serverId)); + if (!isBsServer && this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(security.serverId) && + id != this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId)) { + pathsDelete.add("/0/" + this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId)); } /** * If there is an instance in the serverInstances with serverId which we replace in the securityInstances */ // find serverId in securityInstances by id (instance) Integer serverIdOld = null; - for (Map.Entry entry : this.securityInstances.entrySet()) { + for (Map.Entry entry : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().entrySet()) { if (entry.getValue().equals(id)) { serverIdOld = entry.getKey(); } } - if (!isBsServer && serverIdOld != null && this.serverInstances.containsKey(serverIdOld)) { - pathsDelete.add("/1/" + this.serverInstances.get(serverIdOld)); + if (!isBsServer && serverIdOld != null && this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().containsKey(serverIdOld)) { + pathsDelete.add("/1/" + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(serverIdOld)); } id++; } @@ -261,12 +274,13 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi requestsWrite.add(toWriteRequest(securityInstanceId, server.getValue(), contentFormat)); if (!isBsServer) { /** Delete instance if bootstrapServerIdNew not equals bootstrapServerIdOld or securityInstanceBsIdNew not equals serverInstanceBsIdOld */ - if (this.bootstrapServerIdNew != null && server.getValue().shortId == this.bootstrapServerIdNew && - (this.bootstrapServerIdNew != this.bootstrapServerIdOld || securityInstanceId != this.serverInstances.get(this.bootstrapServerIdOld))) { - pathsDelete.add("/1/" + this.serverInstances.get(this.bootstrapServerIdOld)); + if (bootstrapServerIdNew != null && server.getValue().shortId == bootstrapServerIdNew && + (bootstrapServerIdNew != bootstrapServerIdOld || securityInstanceId != this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(bootstrapServerIdOld))) { + pathsDelete.add("/1/" + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(bootstrapServerIdOld)); /** Delete instance if serverIdNew is present in serverInstances and securityInstanceIdOld by serverIdNew not equals serverInstanceIdOld */ - } else if (this.serverInstances.containsKey(server.getValue().shortId) && securityInstanceId != this.serverInstances.get(server.getValue().shortId)) { - pathsDelete.add("/1/" + this.serverInstances.get(server.getValue().shortId)); + } else if (this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().containsKey(server.getValue().shortId) && + securityInstanceId != this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(server.getValue().shortId)) { + pathsDelete.add("/1/" + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(server.getValue().shortId)); } } } @@ -294,4 +308,24 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi this.supportedObjects.put(1, "1.1"); this.supportedObjects.put(2, "1.0"); } + + @Override + public void remove(String endpoint) { + writeLock.lock(); + try { + this.lwM2MBootstrapSessionClients.remove(endpoint); + } finally { + writeLock.unlock(); + } + } + + @Override + public void put(String endpoint) throws InvalidConfigurationException { + writeLock.lock(); + try { + this.lwM2MBootstrapSessionClients.put(endpoint, new LwM2MBootstrapClientInstanceIds()); + } finally { + writeLock.unlock(); + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapTaskProvider.java new file mode 100644 index 0000000000..6bc792fed7 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapTaskProvider.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.bootstrap.store; + +import org.eclipse.leshan.server.bootstrap.BootstrapTaskProvider; +import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; + +public interface LwM2MBootstrapTaskProvider extends BootstrapTaskProvider { + + void put(String endpoint) throws InvalidConfigurationException; + + void remove(String endpoint); +} From dce0ca91491cd416545c3af83379012e5392e413 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 22 Feb 2022 12:08:23 +0200 Subject: [PATCH 2/4] lwm2m: Comments... --- ...LwM2MBootstrapConfigStoreTaskProvider.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index edcacfa057..d358edfd48 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -144,6 +144,13 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask return config.autoIdForSecurityObject; } + /** + * "Short Server ID": This Resource MUST be set when the Bootstrap-Server Resource has a value of 'false'. + * The values ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server. + * "Short Server ID": + * - Link Instance (lwm2m Server) hase linkParams with key = "ssid" value = "shortId" (ver lvm2m = 1.1). + * - Link Instance (bootstrap Server) hase not linkParams with key = "ssid" (ver lvm2m = 1.1). + */ protected void findSecurityInstanceId(Link[] objectLinks, String endpoint) { log.info("Object after discover: [{}]", objectLinks); for (Link link : objectLinks) { @@ -230,26 +237,27 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask List> requestsWrite = new ArrayList<>(); boolean isBsServer = false; boolean isLwServer = false; - /** Map */ + /** Map */ Map instances = new HashMap<>(); Integer bootstrapServerIdNew = null; // handle security - int id = 0; + int lwm2mSecurityInstanceId = 0; + int bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0); for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { if (security.bootstrapServer) { - requestsWrite.add(toWriteRequest(this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0), security, contentFormat)); + requestsWrite.add(toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); isBsServer = true; bootstrapServerIdNew = security.serverId; - instances.put(security.serverId, this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0)); + instances.put(security.serverId, bootstrapSecurityInstanceId); } else { - if (id == this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0)) { - id++; + if (lwm2mSecurityInstanceId == bootstrapSecurityInstanceId) { + lwm2mSecurityInstanceId++; } - requestsWrite.add(toWriteRequest(id, security, contentFormat)); - instances.put(security.serverId, id); + requestsWrite.add(toWriteRequest(lwm2mSecurityInstanceId, security, contentFormat)); + instances.put(security.serverId, lwm2mSecurityInstanceId); isLwServer = true; if (!isBsServer && this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(security.serverId) && - id != this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId)) { + lwm2mSecurityInstanceId != this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId)) { pathsDelete.add("/0/" + this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(security.serverId)); } /** @@ -258,14 +266,14 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask // find serverId in securityInstances by id (instance) Integer serverIdOld = null; for (Map.Entry entry : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().entrySet()) { - if (entry.getValue().equals(id)) { + if (entry.getValue().equals(lwm2mSecurityInstanceId)) { serverIdOld = entry.getKey(); } } if (!isBsServer && serverIdOld != null && this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().containsKey(serverIdOld)) { pathsDelete.add("/1/" + this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(serverIdOld)); } - id++; + lwm2mSecurityInstanceId++; } } // handle server From 53ab636505beb933274f579f38d3e98a6b7e1878 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 23 Feb 2022 10:04:50 +0200 Subject: [PATCH 3/4] lwm2m: add BOOTSTRAP_DEFAULT_SHORT_ID = 0 --- .../store/LwM2MBootstrapConfigStoreTaskProvider.java | 7 ++++--- .../server/transport/lwm2m/utils/LwM2MTransportUtil.java | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index d358edfd48..0d12f884d1 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -50,6 +50,7 @@ import java.util.stream.Collectors; import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.BOOTSTRAP_DEFAULT_SHORT_ID; @Slf4j public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTaskProvider { @@ -104,7 +105,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask "Bootstrap Discover return error {} : to continue bootstrap session without autoIdForSecurityObject mode. {}", discoverResponse, session); } - if (this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getSecurityInstances().get(0) == null) { + if (this.lwM2MBootstrapSessionClients.get(session.getEndpoint()).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID) == null) { log.error( "Unable to find bootstrap server instance in Security Object (0) in response {}: unable to continue bootstrap session with autoIdForSecurityObject mode. {}", discoverResponse, session); @@ -168,7 +169,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(Integer.valueOf(link.getLinkParams().get("ssid").getUnquoted()), path.getObjectInstanceId()); } else { if (!this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().containsKey(0)) { - this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(0, path.getObjectInstanceId()); + this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().put(BOOTSTRAP_DEFAULT_SHORT_ID, path.getObjectInstanceId()); } else { log.error("Invalid bootstrapSecurityInstance by [{}]", path.getObjectInstanceId()); } @@ -242,7 +243,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask Integer bootstrapServerIdNew = null; // handle security int lwm2mSecurityInstanceId = 0; - int bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(0); + int bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID); for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfig.security).values()) { if (security.bootstrapServer) { requestsWrite.add(toWriteRequest(bootstrapSecurityInstanceId, security, contentFormat)); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index e415858755..ca001e3b83 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -92,6 +92,7 @@ public class LwM2MTransportUtil { public static final String LOG_LWM2M_INFO = "info"; public static final String LOG_LWM2M_ERROR = "error"; public static final String LOG_LWM2M_WARN = "warn"; + public static final int BOOTSTRAP_DEFAULT_SHORT_ID = 0; public enum LwM2MClientStrategy { CLIENT_STRATEGY_1(1, "Read only resources marked as observation"), From 506d9279c29e80b379c302dd45357d0e1d1c530f Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 8 Mar 2022 10:34:26 +0200 Subject: [PATCH 4/4] lwm2m: for build --- .../bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index 0d12f884d1..50aff2a5bd 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -311,6 +311,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask return (requests); } + private void initSupportedObjectsDefault() { this.supportedObjects = new HashMap<>(); this.supportedObjects.put(0, "1.1");