Commit 54543ae4b51078ed6cb8ff33b8da45d02904bd69

Authored by Andrii Shvaika
1 parent 8b3e34f0

Merge improvements from outdated PR 4527

... ... @@ -674,6 +674,7 @@ transport:
674 674 registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}"
675 675 update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}"
676 676 un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}"
  677 + log_max_length: "${LWM2M_LOG_MAX_LENGTH:100}"
677 678 # Use redis for Security and Registration stores
678 679 redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
679 680 snmp:
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.client;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.UUID;
  21 +
  22 +@Data
  23 +public class LwM2mSoftwareUpdate {
  24 + private volatile String clientSwVersion;
  25 + private volatile String currentSwVersion;
  26 + private volatile UUID currentSwId;
  27 +}
\ No newline at end of file
... ...
... ... @@ -29,6 +29,7 @@ import java.io.File;
29 29 import java.io.FileInputStream;
30 30 import java.io.IOException;
31 31 import java.io.InputStream;
  32 +import java.net.URI;
32 33 import java.nio.file.Path;
33 34 import java.nio.file.Paths;
34 35 import java.security.KeyStore;
... ... @@ -136,18 +137,26 @@ public class LwM2MTransportServerConfig implements LwM2MSecureServerConfig {
136 137 @Getter
137 138 @Value("${transport.lwm2m.server.security.alias:}")
138 139 private String certificateAlias;
139   -
140   -
  140 +
  141 + @Getter
  142 + @Value("${transport.lwm2m.log_max_length:}")
  143 + private int logMaxLength;
  144 +
  145 +
141 146 @PostConstruct
142 147 public void init() {
  148 + URI uri = null;
143 149 try {
144   - File keyStoreFile = new File(Resources.getResource(keyStorePathFile).toURI());
  150 + uri = Resources.getResource(keyStorePathFile).toURI();
  151 + log.error("URI: {}", uri);
  152 + File keyStoreFile = new File(uri);
145 153 InputStream inKeyStore = new FileInputStream(keyStoreFile);
146 154 keyStoreValue = KeyStore.getInstance(keyStoreType);
147 155 keyStoreValue.load(inKeyStore, keyStorePassword == null ? null : keyStorePassword.toCharArray());
148 156 } catch (Exception e) {
149 157 log.error("Unable to lookup LwM2M keystore. Reason: " + e.getMessage(), e);
150   - throw new RuntimeException("Failed to lookup LwM2M keystore", e);
  158 +// Absence of the key store should not block user from using plain LwM2M
  159 +// throw new RuntimeException("Failed to lookup LwM2M keystore: " + (uri != null ? uri.toString() : ""), e);
151 160 }
152 161 }
153 162 }
... ...
... ... @@ -87,6 +87,7 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA
87 87 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
88 88 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.CLIENT_NOT_AUTHORIZED;
89 89 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.DEVICE_ATTRIBUTES_REQUEST;
  90 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.FR_OBJECT_ID;
90 91 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.FR_PATH_RESOURCE_VER_ID;
91 92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_ERROR;
92 93 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandlerUtil.LOG_LW2M_INFO;
... ... @@ -1420,9 +1421,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1420 1421 int chunkSize = 0;
1421 1422 int chunk = 0;
1422 1423 byte[] firmwareChunk = firmwareDataCache.get(lwM2MClient.getFrUpdate().getCurrentFwId().toString(), chunkSize, chunk);
1423   - Integer objectId = 5;
1424   - String verSupportedObject = lwM2MClient.getRegistration().getSupportedObject().get(objectId);
1425   - String targetIdVer = LWM2M_SEPARATOR_PATH + objectId + LWM2M_SEPARATOR_KEY + verSupportedObject + LWM2M_SEPARATOR_PATH + 0 + LWM2M_SEPARATOR_PATH + 0;
  1424 + String verSupportedObject = lwM2MClient.getRegistration().getSupportedObject().get(FR_OBJECT_ID);
  1425 + String targetIdVer = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_KEY + verSupportedObject + LWM2M_SEPARATOR_PATH + 0 + LWM2M_SEPARATOR_PATH + 0;
1426 1426 lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
1427 1427 firmwareChunk, config.getTimeout(), null);
1428 1428 log.warn("updateFirmwareClient [{}] [{}]", lwM2MClient.getFrUpdate().getCurrentFwVersion(), lwM2MClient.getFrUpdate().getClientFwVersion());
... ...
... ... @@ -117,29 +117,29 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
117 117 builder.setLocalAddress(config.getHost(), serverPortNoSec);
118 118 builder.setLocalSecureAddress(config.getSecureHost(), serverSecurePort);
119 119 builder.setDecoder(new DefaultLwM2mNodeDecoder());
120   - /** Use a magic converter to support bad type send by the UI. */
  120 + /* Use a magic converter to support bad type send by the UI. */
121 121 builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance()));
122 122
123 123
124   - /** Create CoAP Config */
  124 + /* Create CoAP Config */
125 125 NetworkConfig networkConfig = getCoapConfig(serverPortNoSec, serverSecurePort);
126 126 BlockwiseLayer blockwiseLayer = new BlockwiseLayer(networkConfig);
127 127 builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort));
128 128
129   - /** Define model provider (Create Models )*/
  129 + /* Define model provider (Create Models )*/
130 130 LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.helper, this.context);
131 131 config.setModelProvider(modelProvider);
132 132 builder.setObjectModelProvider(modelProvider);
133 133
134   - /** Create credentials */
  134 + /* Create credentials */
135 135 this.setServerWithCredentials(builder);
136 136
137   - /** Set securityStore with new registrationStore */
  137 + /* Set securityStore with new registrationStore */
138 138 builder.setSecurityStore(securityStore);
139 139 builder.setRegistrationStore(registrationStore);
140 140
141 141
142   - /** Create DTLS Config */
  142 + /* Create DTLS Config */
143 143 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
144 144 dtlsConfig.setServerOnly(true);
145 145 dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups());
... ... @@ -156,10 +156,10 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
156 156 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256);
157 157 }
158 158
159   - /** Set DTLS Config */
  159 + /* Set DTLS Config */
160 160 builder.setDtlsConfig(dtlsConfig);
161 161
162   - /** Create LWM2M server */
  162 + /* Create LWM2M server */
163 163 return builder.build();
164 164 }
165 165
... ... @@ -173,10 +173,10 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
173 173 trustedCertificates[0] = rootCAX509Cert;
174 174 builder.setTrustedCertificates(trustedCertificates);
175 175 } else {
176   - /** by default trust all */
  176 + /* by default trust all */
177 177 builder.setTrustedCertificates(new X509Certificate[0]);
178 178 }
179   - /** Set securityStore with registrationStore*/
  179 + /* Set securityStore with registrationStore*/
180 180 builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() {
181 181 @Override
182 182 protected boolean matchX509Identity(String endpoint, String receivedX509CommonName,
... ... @@ -189,7 +189,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
189 189 this.infoPramsUri("RPK");
190 190 this.infoParamsServerKey(this.publicKey, this.privateKey);
191 191 } else {
192   - /** by default trust all */
  192 + /* by default trust all */
193 193 builder.setTrustedCertificates(new X509Certificate[0]);
194 194 log.info("Unable to load X509 files for LWM2MServer");
195 195 this.pskMode = true;
... ... @@ -256,7 +256,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
256 256 }
257 257
258 258 private void generateKeyForRPK() throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
259   - /** Get Elliptic Curve Parameter spec for secp256r1 */
  259 + /* Get Elliptic Curve Parameter spec for secp256r1 */
260 260 AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
261 261 algoParameters.init(new ECGenParameterSpec("secp256r1"));
262 262 ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
... ... @@ -280,17 +280,17 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
280 280 }
281 281
282 282 private void infoParamsServerKey(PublicKey publicKey, PrivateKey privateKey) {
283   - /** Get x coordinate */
  283 + /* Get x coordinate */
284 284 byte[] x = ((ECPublicKey) publicKey).getW().getAffineX().toByteArray();
285 285 if (x[0] == 0)
286 286 x = Arrays.copyOfRange(x, 1, x.length);
287 287
288   - /** Get Y coordinate */
  288 + /* Get Y coordinate */
289 289 byte[] y = ((ECPublicKey) publicKey).getW().getAffineY().toByteArray();
290 290 if (y[0] == 0)
291 291 y = Arrays.copyOfRange(y, 1, y.length);
292 292
293   - /** Get Curves params */
  293 + /* Get Curves params */
294 294 String params = ((ECPublicKey) publicKey).getParams().toString();
295 295 String privHex = Hex.encodeHexString(privateKey.getEncoded());
296 296 log.info(" \n- Public Key (Hex): [{}] \n" +
... ...
... ... @@ -23,73 +23,72 @@ public class LwM2mNetworkConfig {
23 23 NetworkConfig coapConfig = new NetworkConfig();
24 24 coapConfig.setInt(NetworkConfig.Keys.COAP_PORT,serverPortNoSec);
25 25 coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT,serverSecurePort);
26   - /**
27   - * Example:Property for large packet:
28   - * #NetworkConfig config = new NetworkConfig();
29   - * #config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32);
30   - * #config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32);
31   - * #config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048);
32   - * #config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3);
33   - * #config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000);
  26 + /*
  27 + Example:Property for large packet:
  28 + #NetworkConfig config = new NetworkConfig();
  29 + #config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32);
  30 + #config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32);
  31 + #config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048);
  32 + #config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3);
  33 + #config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000);
34 34 */
35 35
36   - /**
37   - * Property to indicate if the response should always include the Block2 option \
38   - * when client request early blockwise negociation but the response can be sent on one packet.
39   - * - value of false indicate that the server will respond without block2 option if no further blocks are required.
40   - * - value of true indicate that the server will response with block2 option event if no further blocks are required.
41   - * CoAP client will try to use block mode
42   - * or adapt the block size when receiving a 4.13 Entity too large response code
  36 + /*
  37 + Property to indicate if the response should always include the Block2 option \
  38 + when client request early blockwise negociation but the response can be sent on one packet.
  39 + - value of false indicate that the server will respond without block2 option if no further blocks are required.
  40 + - value of true indicate that the server will response with block2 option event if no further blocks are required.
  41 + CoAP client will try to use block mode
  42 + or adapt the block size when receiving a 4.13 Entity too large response code
43 43 */
44 44 coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
45   - /***
46   - * Property to indicate if the response should always include the Block2 option \
47   - * when client request early blockwise negociation but the response can be sent on one packet.
48   - * - value of false indicate that the server will respond without block2 option if no further blocks are required.
49   - * - value of true indicate that the server will response with block2 option event if no further blocks are required.
  45 + /*
  46 + Property to indicate if the response should always include the Block2 option \
  47 + when client request early blockwise negociation but the response can be sent on one packet.
  48 + - value of false indicate that the server will respond without block2 option if no further blocks are required.
  49 + - value of true indicate that the server will response with block2 option event if no further blocks are required.
50 50 */
51 51 coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
52 52
53 53 coapConfig.setInt(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, 300000);
54   - /**
55   - * !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13
56   - * The maximum size of a resource body (in bytes) that will be accepted
57   - * as the payload of a POST/PUT or the response to a GET request in a
58   - * transparent> blockwise transfer.
59   - * This option serves as a safeguard against excessive memory
60   - * consumption when many resources contain large bodies that cannot be
61   - * transferred in a single CoAP message. This option has no impact on
62   - * *manually* managed blockwise transfers in which the blocks are handled individually.
63   - * Note that this option does not prevent local clients or resource
64   - * implementations from sending large bodies as part of a request or response to a peer.
65   - * The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192
66   - * A value of {@code 0} turns off transparent handling of blockwise transfers altogether.
  54 + /*
  55 + !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13
  56 + The maximum size of a resource body (in bytes) that will be accepted
  57 + as the payload of a POST/PUT or the response to a GET request in a
  58 + transparent> blockwise transfer.
  59 + This option serves as a safeguard against excessive memory
  60 + consumption when many resources contain large bodies that cannot be
  61 + transferred in a single CoAP message. This option has no impact on
  62 + *manually* managed blockwise transfers in which the blocks are handled individually.
  63 + Note that this option does not prevent local clients or resource
  64 + implementations from sending large bodies as part of a request or response to a peer.
  65 + The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192
  66 + A value of {@code 0} turns off transparent handling of blockwise transfers altogether.
67 67 */
68   -// coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 8192);
69 68 coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
70   - /**
71   - * The default DTLS response matcher.
72   - * Supported values are STRICT, RELAXED, or PRINCIPAL.
73   - * The default value is STRICT.
74   - * Create new instance of udp endpoint context matcher.
75   - * Params:
76   - * checkAddress
77   - * – true with address check, (STRICT, UDP)
78   - * - false, without
  69 + /*
  70 + The default DTLS response matcher.
  71 + Supported values are STRICT, RELAXED, or PRINCIPAL.
  72 + The default value is STRICT.
  73 + Create new instance of udp endpoint context matcher.
  74 + Params:
  75 + checkAddress
  76 + – true with address check, (STRICT, UDP)
  77 + - false, without
79 78 */
80 79 coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "STRICT");
81   - /**
82   - * https://tools.ietf.org/html/rfc7959#section-2.9.3
83   - * The block size (number of bytes) to use when doing a blockwise transfer. \
84   - * This value serves as the upper limit for block size in blockwise transfers
  80 + /*
  81 + https://tools.ietf.org/html/rfc7959#section-2.9.3
  82 + The block size (number of bytes) to use when doing a blockwise transfer. \
  83 + This value serves as the upper limit for block size in blockwise transfers
85 84 */
86 85 coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024);
87   - /**
88   - * The maximum payload size (in bytes) that can be transferred in a
89   - * single message, i.e. without requiring a blockwise transfer.
90   - * NB: this value MUST be adapted to the maximum message size supported by the transport layer.
91   - * In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol
92   - * DEFAULT_VALUE = 1024
  86 + /*
  87 + The maximum payload size (in bytes) that can be transferred in a
  88 + single message, i.e. without requiring a blockwise transfer.
  89 + NB: this value MUST be adapted to the maximum message size supported by the transport layer.
  90 + In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol
  91 + DEFAULT_VALUE = 1024
93 92 */
94 93 coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
95 94
... ...
... ... @@ -404,17 +404,40 @@ public class LwM2mTransportRequest {
404 404 }
405 405 }
406 406
407   - private void infoWriteResponse(Registration registration, LwM2mResponse response,
408   - DownlinkRequest request) {
409   - LwM2mNode node = ((WriteRequest) request).getNode();
410   - Object value = this.converter.convertValue(((LwM2mSingleResource) node).getValue(),
411   - ((LwM2mSingleResource) node).getType(), ResourceModel.Type.STRING, request.getPath());
412   - String msg = String.format("%s: Update finished successfully: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s",
413   - LOG_LW2M_INFO, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(),
414   - response.getCode().getName(), request.getPath().toString(), value);
415   - serviceImpl.sendLogsToThingsboard(msg, registration.getId());
416   - log.trace("[{}] [{}] [{}] - [{}] [{}] Update finished successfully: [{}]", request.getClass().getName().toString(), registration.getEndpoint(),
417   - ((Response) response.getCoapResponse()).getCode(), response.getCode(),
418   - request.getPath().toString(), value);
  407 + private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request) {
  408 + try {
  409 + LwM2mNode node = ((WriteRequest) request).getNode();
  410 + String msg;
  411 + Object value;
  412 + LwM2mSingleResource singleResource = (LwM2mSingleResource) node;
  413 + if (singleResource.getType() == ResourceModel.Type.STRING || singleResource.getType() == ResourceModel.Type.OPAQUE) {
  414 + int valueLength;
  415 + if (singleResource.getType() == ResourceModel.Type.STRING) {
  416 + valueLength = ((String) singleResource.getValue()).length();
  417 + value = ((String) singleResource.getValue())
  418 + .substring(Math.min(valueLength, config.getLogMaxLength()));
  419 +
  420 + } else {
  421 + valueLength = ((byte[]) singleResource.getValue()).length;
  422 + value = new String(Arrays.copyOf(((byte[]) singleResource.getValue()),
  423 + Math.min(valueLength, config.getLogMaxLength())));
  424 + }
  425 + value = valueLength > config.getLogMaxLength() ? value + "..." : value;
  426 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s length - %s value - %s",
  427 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value);
  428 + } else {
  429 + value = this.converter.convertValue(singleResource.getValue(),
  430 + singleResource.getType(), ResourceModel.Type.STRING, request.getPath());
  431 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path - %s value - %s",
  432 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value);
  433 + }
  434 + if (msg != null) {
  435 + serviceImpl.sendLogsToThingsboard(msg, registration.getId());
  436 + log.warn("[{}] [{}] [{}] - [{}] [{}] Update finished successfully: [{}]", request.getClass().getName(), registration.getEndpoint(),
  437 + ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), value);
  438 + }
  439 + } catch (Exception e) {
  440 + log.trace("Fail convert value from request to string. ", e);
  441 + }
419 442 }
420 443 }
... ...