LWM2M: fix bug update FwUrl in client after change in profile

This commit is contained in:
nickAS21 2021-06-19 16:58:32 +03:00
parent 427ab87443
commit c03893fb57
12 changed files with 112 additions and 23 deletions

View File

@ -36,6 +36,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME;
@Slf4j
@Component
@TbCoapServerComponent
@ -91,7 +93,21 @@ public class DefaultCoapServerService implements CoapServerService {
InetAddress addr = InetAddress.getByName(coapServerContext.getHost());
InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort());
noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr);
noSecCoapEndpointBuilder.setNetworkConfig(NetworkConfig.getStandard());
NetworkConfig coapConfig = new NetworkConfig();
coapConfig.setInt(NetworkConfig.Keys.COAP_PORT, 5683);
coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, 5684);
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
coapConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME);
coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED");
coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024);
coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10);
noSecCoapEndpointBuilder.setNetworkConfig(coapConfig);
CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build();
server.addEndpoint(noSecCoapEndpoint);

View File

@ -18,11 +18,12 @@ package org.thingsboard.server.transport.coap;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.TbTransportService;
import org.thingsboard.server.coapserver.CoapServerService;
import org.thingsboard.server.coapserver.TbCoapServerComponent;
import org.thingsboard.server.common.data.TbTransportService;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource;
@ -30,6 +31,8 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.net.UnknownHostException;
import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME;
@Service("CoapTransportService")
@TbCoapServerComponent
@Slf4j
@ -52,6 +55,14 @@ public class CoapTransportService implements TbTransportService {
public void init() throws UnknownHostException {
log.info("Starting CoAP transport...");
coapServer = coapServerService.getCoapServer();
coapServer.getConfig().setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
coapServer.getConfig().setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
coapServer.getConfig().setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME);
coapServer.getConfig().setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
coapServer.getConfig().setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED");
coapServer.getConfig().setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024);
coapServer.getConfig().setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
coapServer.getConfig().setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10);
CoapResource api = new CoapResource(API);
api.add(new CoapTransportResource(coapTransportContext, coapServerService, V1));

View File

@ -17,11 +17,13 @@ package org.thingsboard.server.transport.coap;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.network.Exchange;
import org.eclipse.californium.core.server.resources.CoapExchange;
import org.eclipse.californium.core.server.resources.Resource;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.ota.OtaPackageType;
@ -32,16 +34,21 @@ import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
@Slf4j
public class OtaPackageTransportResource extends AbstractCoapTransportResource {
private static final int ACCESS_TOKEN_POSITION = 2;
private final OtaPackageType otaPackageType;
private final ExecutorService sendOtaDataOutUriLarge;
public OtaPackageTransportResource(CoapTransportContext ctx, OtaPackageType otaPackageType) {
super(ctx, otaPackageType.getKeyPrefix());
this.otaPackageType = otaPackageType;
this.setObservable(true);
this.sendOtaDataOutUriLarge = ThingsBoardExecutors.newWorkStealingPool(10, "LwM2M sendOtaDataOutUriLarge");
}
@Override
@ -132,11 +139,13 @@ public class OtaPackageTransportResource extends AbstractCoapTransportResource {
Response response = new Response(CoAP.ResponseCode.CONTENT);
if (data != null && data.length > 0) {
response.setPayload(data);
response.getOptions().setAccept(MediaTypeRegistry.APPLICATION_OCTET_STREAM);
if (exchange.getRequestOptions().getBlock2() != null) {
int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
boolean lastFlag = data.length > chunkSize;
boolean lastFlag = data.length <= chunkSize;
this.sendOtaDataOutUriLarge.submit(() -> {
response.getOptions().setBlock2(chunkSize, lastFlag, 0);
}
}); }
exchange.respond(response);
}
}

View File

@ -58,10 +58,12 @@ public class LwM2mCredentialsSecurityInfoValidator {
public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
CountDownLatch latch = new CountDownLatch(1);
final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1];
log.warn("001) [{}]", credentialsId);
context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(credentialsId).build(),
new TransportServiceCallback<>() {
@Override
public void onSuccess(ValidateDeviceCredentialsResponse msg) {
log.warn("002) [{}] [{}]", credentialsId, msg);
String credentialsBody = msg.getCredentials();
resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue);
resultSecurityStore[0].setMsg(msg);
@ -71,6 +73,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
@Override
public void onError(Throwable e) {
log.warn("003) [{}] [{}] Failed to process credentials ", credentialsId, e);
log.trace("[{}] [{}] Failed to process credentials ", credentialsId, e);
resultSecurityStore[0] = createSecurityInfo(credentialsId, null, null);
latch.countDown();

View File

@ -25,8 +25,6 @@ import org.eclipse.californium.core.server.resources.CoapExchange;
import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.core.server.resources.ResourceObserver;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@ -143,7 +141,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource {
response.setPayload(fwData);
if (exchange.getRequestOptions().getBlock2() != null) {
int chunkSize = exchange.getRequestOptions().getBlock2().getSzx();
boolean lastFlag = fwData.length > chunkSize;
boolean lastFlag = fwData.length <= chunkSize;
response.getOptions().setBlock2(chunkSize, lastFlag, 0);
log.warn("92) with blokc2 Send currentId: [{}], length: [{}], chunkSize [{}], moreFlag [{}]", currentId.toString(), fwData.length, chunkSize, lastFlag);
}

View File

@ -33,6 +33,7 @@ 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.server.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.LwM2MSoftwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw;
@ -174,6 +175,24 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
fwInfo.setCurrentName(name);
}
@Override
public void onCurrentFirmwareStrategyUpdate(LwM2mClient client, Integer newStrategy, String newBaseUrl) {
log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), newStrategy);
LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setFwStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(newStrategy));
fwInfo.setBaseUrl(newBaseUrl);
startFirmwareUpdateIfNeeded(client, fwInfo);
}
@Override
public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, Integer newStrategy, String newBaseUrl) {
log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), newStrategy);
LwM2MClientOtaInfo swInfo = getOrInitSwInfo(client);
swInfo.setSwStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(newStrategy));
swInfo.setBaseUrl(newBaseUrl);
startSoftwareUpdateIfNeeded(client, swInfo);
}
@Override
public void onCurrentFirmwareVersion3Update(LwM2mClient client, String version) {
log.debug("[{}] Current fw version: {}", client.getEndpoint(), version);
@ -250,6 +269,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
}
}
private void startSoftwareUpdateIfNeeded(LwM2mClient client, LwM2MClientOtaInfo swInfo) {
}
private void startFirmwareUpdateUsingUrl(LwM2mClient client, String url) {
String targetIdVer = convertObjectIdToVersionedId(FW_URL_ID, client.getRegistration());
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(url).timeout(config.getTimeout()).build();
@ -277,7 +300,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
UUID otaPackageId = new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB());
LwM2MFirmwareUpdateStrategy strategy;
if (fwInfo.getDeliveryMethod() == null || fwInfo.getDeliveryMethod() == 2) {
strategy = fwInfo.getStrategy();
strategy = fwInfo.getFwStrategy();
} else {
strategy = fwInfo.getDeliveryMethod() == 0 ? LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL : LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY;
}
@ -328,9 +351,9 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
return Optional.empty();
}
private LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) {
public LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) {
//TODO: fetch state from the cache or DB.
return fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> {
var profile = clientContext.getProfile(client.getProfileId());
return new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy(),
profile.getClientLwM2mSettings().getFwUpdateRecourse());

View File

@ -19,8 +19,9 @@ import lombok.Data;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw;
import org.thingsboard.server.transport.lwm2m.server.LwM2MSoftwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.UpdateResultFw;
import org.thingsboard.server.transport.lwm2m.server.UpdateStateFw;
import java.util.Optional;
@ -44,7 +45,8 @@ public class LwM2MClientOtaInfo {
private Integer deliveryMethod;
//TODO: use value from device if applicable;
private LwM2MFirmwareUpdateStrategy strategy;
private LwM2MFirmwareUpdateStrategy fwStrategy;
private LwM2MSoftwareUpdateStrategy swStrategy;
private UpdateStateFw updateState;
private UpdateResultFw updateResult;
@ -54,7 +56,7 @@ public class LwM2MClientOtaInfo {
public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, Integer strategyCode, String baseUrl) {
this.endpoint = endpoint;
this.type = type;
this.strategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode);
this.fwStrategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode);
this.baseUrl = baseUrl;
}

View File

@ -31,6 +31,10 @@ public interface LwM2MOtaUpdateService {
void onCurrentFirmwareNameUpdate(LwM2mClient client, String name);
void onCurrentFirmwareStrategyUpdate(LwM2mClient client, Integer newStrategy, String newBaseUrl);
void onCurrentSoftwareStrategyUpdate(LwM2mClient client, Integer newStrategy, String newBaseUrl);
void onCurrentFirmwareVersion3Update(LwM2mClient client, String version);
void onCurrentFirmwareVersion5Update(LwM2mClient client, String version);

View File

@ -37,7 +37,6 @@ import org.eclipse.leshan.server.registration.Registration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.DonAsynchron;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
@ -53,6 +52,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.server.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.LwM2MSoftwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert;
import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
@ -100,7 +101,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -779,6 +779,29 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
clients.forEach(client -> sendCancelObserveRequest(targetId, client));
}
}
// # 7.1
// update value in fwInfo
if (!newProfile.getClientLwM2mSettings().getFwUpdateStrategy().equals(oldProfile.getClientLwM2mSettings().getFwUpdateStrategy())
|| (LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == newProfile.getClientLwM2mSettings().getFwUpdateStrategy() &&
!newProfile.getClientLwM2mSettings().getFwUpdateRecourse().equals(oldProfile.getClientLwM2mSettings().getFwUpdateRecourse()))) {
clients.forEach(lwM2MClient -> {
otaService.onCurrentFirmwareStrategyUpdate(lwM2MClient,
newProfile.getClientLwM2mSettings().getFwUpdateStrategy(),
newProfile.getClientLwM2mSettings().getFwUpdateRecourse());
});
}
//# 7.2 // update value in swInfo
if (!newProfile.getClientLwM2mSettings().getSwUpdateStrategy().equals(oldProfile.getClientLwM2mSettings().getSwUpdateStrategy())
|| (LwM2MSoftwareUpdateStrategy.TEMP_URL.code == newProfile.getClientLwM2mSettings().getSwUpdateStrategy() &&
!newProfile.getClientLwM2mSettings().getSwUpdateRecourse().equals(oldProfile.getClientLwM2mSettings().getSwUpdateRecourse()))) {
clients.forEach(lwM2MClient -> {
otaService.onCurrentSoftwareStrategyUpdate(lwM2MClient,
newProfile.getClientLwM2mSettings().getFwUpdateStrategy(),
newProfile.getClientLwM2mSettings().getFwUpdateRecourse());
});
}
}
}

View File

@ -160,9 +160,9 @@
<!-- <div fxLayout="column">-->
<!-- <mat-form-field class="mat-block">-->
<!-- <mat-label>{{ 'device-profile.lwm2m.client-strategy-label' | translate }}</mat-label>-->
<!-- <mat-select formControlName="clientStrategy"-->
<!-- <mat-select formControlName="clientOnlyObserveAfterConnect"-->
<!-- matTooltip="{{ 'device-profile.lwm2m.client-strategy-tip' | translate:-->
<!-- { count: +lwm2mDeviceProfileFormGroup.get('clientStrategy').value } }}"-->
<!-- { count: +lwm2mDeviceProfileFormGroup.get('clientOnlyObserveAfterConnect').value } }}"-->
<!-- matTooltipPosition="above">-->
<!-- <mat-option value=1>{{ 'device-profile.lwm2m.client-strategy-connect' | translate:-->
<!-- {count: 1} }}</mat-option>-->

View File

@ -97,7 +97,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
binding: [],
bootstrapServer: [null, Validators.required],
lwm2mServer: [null, Validators.required],
clientStrategy: [1, []],
clientOnlyObserveAfterConnect: [1, []],
fwUpdateStrategy: [1, []],
swUpdateStrategy: [1, []],
fwUpdateRecourse: [{value: '', disabled: true}, []],
@ -216,7 +216,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
binding: this.configurationValue.bootstrap.servers.binding,
bootstrapServer: this.configurationValue.bootstrap.bootstrapServer,
lwm2mServer: this.configurationValue.bootstrap.lwm2mServer,
clientStrategy: this.configurationValue.clientLwM2mSettings.clientStrategy,
clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect,
fwUpdateStrategy: this.configurationValue.clientLwM2mSettings.fwUpdateStrategy || 1,
swUpdateStrategy: this.configurationValue.clientLwM2mSettings.swUpdateStrategy || 1,
fwUpdateRecourse: fwResource,
@ -257,7 +257,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
bootstrapServers.defaultMinPeriod = config.defaultMinPeriod;
bootstrapServers.notifIfDisabled = config.notifIfDisabled;
bootstrapServers.binding = config.binding;
this.configurationValue.clientLwM2mSettings.clientStrategy = config.clientStrategy;
this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect = config.clientOnlyObserveAfterConnect;
this.configurationValue.clientLwM2mSettings.fwUpdateStrategy = config.fwUpdateStrategy;
this.configurationValue.clientLwM2mSettings.swUpdateStrategy = config.swUpdateStrategy;
this.configurationValue.clientLwM2mSettings.fwUpdateRecourse = config.fwUpdateRecourse;

View File

@ -168,7 +168,7 @@ export interface Lwm2mProfileConfigModels {
}
export interface ClientLwM2mSettings {
clientStrategy: string;
clientOnlyObserveAfterConnect: number;
fwUpdateStrategy: number;
swUpdateStrategy: number;
fwUpdateRecourse: string;
@ -240,7 +240,7 @@ export function getDefaultProfileConfig(hostname?: any): Lwm2mProfileConfigModel
function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings {
return {
clientStrategy: '1',
clientOnlyObserveAfterConnect: 1,
fwUpdateStrategy: 1,
swUpdateStrategy: 1,
fwUpdateRecourse: DEFAULT_FW_UPDATE_RESOURCE,