Skip to content

Commit

Permalink
Implementation of timestamped value for Observe Response
Browse files Browse the repository at this point in the history
  • Loading branch information
mgdlkundera committed May 15, 2024
1 parent 778eecd commit e920219
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -458,8 +458,8 @@ public void read_timestamped(String givenServerEndpointProvider) throws Exceptio

// send read request
Future<ReadResponse> future = Executors.newSingleThreadExecutor().submit(() -> {
// send a request with 3 seconds timeout
return server.send(registration, new ReadRequest(ContentFormat.SENML_JSON, 1, 0, 1), 3000);
// send a request with 2 seconds timeout
return server.send(registration, new ReadRequest(ContentFormat.SENML_JSON, 1, 0, 1), 2000);
});

// wait for request and send response
Expand All @@ -468,7 +468,43 @@ public void read_timestamped(String givenServerEndpointProvider) throws Exceptio
.payload(payload, ContentFormat.SENML_JSON_CODE).go();

// check response received at server side
ReadResponse response = future.get(3, TimeUnit.SECONDS);
ReadResponse response = future.get(2, TimeUnit.SECONDS);
assertThat(response.getTimestampedLwM2mNode()).isEqualTo(timestampedNode);
}

@TestAllTransportLayer
public void observe_timestamped(String givenServerEndpointProvider) throws Exception {

// register client
LockStepLwM2mClient client = new LockStepLwM2mClient(server.getEndpoint(Protocol.COAP).getURI());
Token token = client
.sendLwM2mRequest(new RegisterRequest(client.getEndpointName(), 60l, "1.1", EnumSet.of(BindingMode.U),
null, null, linkParser.parseCoreLinkFormat("</1>,</2>,</3>".getBytes()), null));
client.expectResponse().token(token).go();
server.waitForNewRegistrationOf(client.getEndpointName());
Registration registration = server.getRegistrationService().getByEndpoint(client.getEndpointName());

// create timestamped data
LwM2mEncoder encoder = new DefaultLwM2mEncoder();
Instant t1 = Instant.now();
LwM2mSingleResource resource = LwM2mSingleResource.newIntegerResource(1, 3600);
TimestampedLwM2mNode timestampedNode = new TimestampedLwM2mNode(t1, resource);
byte[] payload = encoder.encodeTimestampedData(Arrays.asList(timestampedNode), ContentFormat.SENML_JSON,
new LwM2mPath("/1/0/1"), client.getLwM2mModel());

// send observe request
Future<ObserveResponse> future = Executors.newSingleThreadExecutor().submit(() -> {
// send a request with 2 seconds timeout
return server.send(registration, new ObserveRequest(ContentFormat.SENML_JSON, 1, 0, 1), 2000);
});

// wait for request and send response
client.expectRequest().storeToken("TKN").storeMID("MID").go();
client.sendResponse(Type.ACK, ResponseCode.CONTENT).loadMID("MID").loadToken("TKN")
.payload(payload, ContentFormat.SENML_JSON_CODE).go();

// check response received at server side
ObserveResponse response = future.get(2, TimeUnit.SECONDS);
assertThat(response.getTimestampedLwM2mNode()).isEqualTo(timestampedNode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ public void visit(ReadRequest request) {
coapResponse.getPayloadString(), coapResponse);
} else if (isResponseCodeContent()) {
// handle success response
TimestampedLwM2mNode timestampedNode = decodeCoapTimestampedResponse(request.getPath(), coapResponse,
List<TimestampedLwM2mNode> timestampedNodes = decodeCoapTimestampedResponse(request.getPath(), coapResponse,
request, clientEndpoint);
lwM2mresponse = new ReadResponse(ResponseCode.CONTENT, null, timestampedNode, null, coapResponse);
lwM2mresponse = new ReadResponse(ResponseCode.CONTENT, null, timestampedNodes.get(0), null, coapResponse);
} else {
// handle unexpected response:
handleUnexpectedResponseCode(clientEndpoint, request, coapResponse);
Expand Down Expand Up @@ -249,30 +249,39 @@ public void visit(ObserveRequest request) {
} else if (isResponseCodeContent()
// This is for backward compatibility, when the spec say notification used CHANGED code
|| isResponseCodeChanged()) {

// handle success response:
LwM2mNode content = decodeCoapResponse(request.getPath(), coapResponse, request, clientEndpoint);
SingleObservation observation = null;
if (coapResponse.getOptions().hasObserve()) {
List<TimestampedLwM2mNode> timestampedNodes = decodeCoapTimestampedResponse(request.getPath(), coapResponse,
request, clientEndpoint);
if (timestampedNodes != null && !timestampedNodes.isEmpty()) {
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), null, timestampedNodes,
null, null, coapResponse);
} else {

/*
* Note: When using OSCORE and Observe the first coapRequest sent to register an observation can have
* its Token missing here. Is this because OSCORE re-creates the request before sending? When looking in
* Wireshark all messages have a Token as they should. The lines below fixes this by taking the Token
* from the response that came to the request (since the request actually has a Token when going out the
* response will have the same correct Token.
*
* TODO OSCORE : This should probably not be done here. should we fix this ? should we check if oscore
* is used ?
*/
if (coapRequest.getTokenBytes() == null) {
coapRequest.setToken(coapResponse.getTokenBytes());
LwM2mNode content = decodeCoapResponse(request.getPath(), coapResponse, request, clientEndpoint);
SingleObservation observation = null;
if (coapResponse.getOptions().hasObserve()) {

/*
* Note: When using OSCORE and Observe the first coapRequest sent to register an observation can
* have its Token missing here. Is this because OSCORE re-creates the request before sending? When
* looking in Wireshark all messages have a Token as they should. The lines below fixes this by
* taking the Token from the response that came to the request (since the request actually has a
* Token when going out the response will have the same correct Token.
*
* TODO OSCORE : This should probably not be done here. should we fix this ? should we check if
* oscore is used ?
*/
if (coapRequest.getTokenBytes() == null) {
coapRequest.setToken(coapResponse.getTokenBytes());
}

// observe request successful
observation = ObserveUtil.createLwM2mObservation(coapRequest);
}

// observe request successful
observation = ObserveUtil.createLwM2mObservation(coapRequest);
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), content, null,
observation, null, coapResponse);
}
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), content, null, observation,
null, coapResponse);
} else {
// handle unexpected response:
handleUnexpectedResponseCode(clientEndpoint, request, coapResponse);
Expand Down Expand Up @@ -490,7 +499,7 @@ private Map<LwM2mPath, LwM2mNode> decodeCompositeCoapResponse(List<LwM2mPath> pa
}
}

private TimestampedLwM2mNode decodeCoapTimestampedResponse(LwM2mPath path, Response coapResponse,
private List<TimestampedLwM2mNode> decodeCoapTimestampedResponse(LwM2mPath path, Response coapResponse,
LwM2mRequest<?> request, String endpoint) {
List<TimestampedLwM2mNode> timestampedNodes = null;
try {
Expand All @@ -501,7 +510,7 @@ private TimestampedLwM2mNode decodeCoapTimestampedResponse(LwM2mPath path, Respo
"Unable to decode response payload of request [%s] from client [%s] : should receive only 1 timestamped node but received %s",
request, endpoint, timestampedNodes.size());
}
return timestampedNodes.get(0);
return timestampedNodes;
} catch (CodecException e) {
handleCodecException(e, request, coapResponse, endpoint);
return null; // should not happen as handleCodecException raise exception
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ public void visit(ReadRequest request) {
coapResponse.getPayloadString(), coapResponse);
} else if (isResponseCodeContent()) {
// handle success response with timestamped node
TimestampedLwM2mNode timestampedNode = decodeCoapTimestampedResponse(request.getPath(), coapResponse,
List<TimestampedLwM2mNode> timestampedNodes = decodeCoapTimestampedResponse(request.getPath(), coapResponse,
request, clientEndpoint);
lwM2mresponse = new ReadResponse(ResponseCode.CONTENT, null, timestampedNode, null, coapResponse);
lwM2mresponse = new ReadResponse(ResponseCode.CONTENT, null, timestampedNodes.get(0), null, coapResponse);
} else {
// handle unexpected response:
handleUnexpectedResponseCode(clientEndpoint, request, coapResponse);
Expand Down Expand Up @@ -256,23 +256,32 @@ public void visit(ObserveRequest request) {
// This is for backward compatibility, when the spec say notification used CHANGED code
|| isResponseCodeChanged()) {
// handle success response:
LwM2mNode content = decodeCoapResponse(request.getPath(), coapResponse, request, clientEndpoint);

if (coapResponse.options().getObserve() != null) {
// Observe relation established
Observation observation = coapRequest.getTransContext().get(LwM2mKeys.LESHAN_OBSERVATION);
if (observation instanceof SingleObservation) {
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), content, null,
(SingleObservation) observation, null, coapResponse);
List<TimestampedLwM2mNode> timestampedNodes = decodeCoapTimestampedResponse(request.getPath(), coapResponse,
request, clientEndpoint);
if (timestampedNodes != null && !timestampedNodes.isEmpty()) {
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), null, timestampedNodes,
null, null, coapResponse);
} else {

LwM2mNode content = decodeCoapResponse(request.getPath(), coapResponse, request, clientEndpoint);

if (coapResponse.options().getObserve() != null) {
// Observe relation established
Observation observation = coapRequest.getTransContext().get(LwM2mKeys.LESHAN_OBSERVATION);
if (observation instanceof SingleObservation) {
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), content, null,
(SingleObservation) observation, null, coapResponse);
} else {
throw new IllegalStateException(String.format(
"A Single Observation is expected in coapRequest transport Context, but was %s",
observation == null ? "null" : observation.getClass().getSimpleName()));
}
} else {
throw new IllegalStateException(String.format(
"A Single Observation is expected in coapRequest transport Context, but was %s",
observation == null ? "null" : observation.getClass().getSimpleName()));
// Observe relation NOTestablished
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), content, null,
null, null, coapResponse);
}
} else {
// Observe relation NOTestablished
lwM2mresponse = new ObserveResponse(toLwM2mResponseCode(coapResponse.getCode()), content, null, null,
null, coapResponse);
}
} else {
// handle unexpected response:
Expand Down Expand Up @@ -505,7 +514,7 @@ private Map<LwM2mPath, LwM2mNode> decodeCompositeCoapResponse(List<LwM2mPath> pa
}
}

private TimestampedLwM2mNode decodeCoapTimestampedResponse(LwM2mPath path, CoapResponse coapResponse,
private List<TimestampedLwM2mNode> decodeCoapTimestampedResponse(LwM2mPath path, CoapResponse coapResponse,
LwM2mRequest<?> request, String endpoint) {
List<TimestampedLwM2mNode> timestampedNodes = null;
try {
Expand All @@ -517,7 +526,7 @@ private TimestampedLwM2mNode decodeCoapTimestampedResponse(LwM2mPath path, CoapR
"Unable to decode response payload of request [%s] from client [%s] : should receive only 1 timestamped node but received %s",
request, endpoint, timestampedNodes.size());
}
return timestampedNodes.get(0);
return timestampedNodes;
} catch (CodecException e) {
handleCodecException(e, request, coapResponse, endpoint);
return null; // should not happen as handleCodecException raise exception
Expand Down

0 comments on commit e920219

Please sign in to comment.