CoapReq.java
/*******************************************************************************
* Copyright (c) 2019, RISE AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
package se.sics.ace.coap;
import java.security.Principal;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.coap.OptionSet;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.coap.Token;
import org.eclipse.californium.elements.DtlsEndpointContext;
import org.eclipse.californium.elements.EndpointContext;
import org.eclipse.californium.elements.MapBasedEndpointContext;
import org.eclipse.californium.elements.util.Bytes;
import org.eclipse.californium.elements.util.StringUtil;
import org.eclipse.californium.oscore.OSCoreEndpointContextInfo;
import com.upokecenter.cbor.CBORException;
import com.upokecenter.cbor.CBORObject;
import com.upokecenter.cbor.CBORType;
import se.sics.ace.AceException;
import se.sics.ace.Constants;
import se.sics.ace.Message;
/**
* A CoAP request implementing the Message interface for the ACE library.
*
* @author Ludwig Seitz and Marco Tiloca
*
*/
public class CoapReq implements Message {
/**
* The parameters in the payload of this message as a Map for convenience,
* if the payload is a CBOR Map.
*/
private Map<Short, CBORObject> parameters;
/**
* The underlying Request from Californium
*/
private Request request;
/**
* Create a request from an underlying Californium request.
*
* @param req the underlying Californium request
* @param payloadMustBeCbor if true, the payload (if any) MUST be in CBOR
* @throws AceException
*/
protected CoapReq(Request req, boolean payloadMustBeCbor) throws AceException {
this.request = req;
CBORObject cborPayload = null;
if (req.getPayload() != null && req.getPayload() != Bytes.EMPTY && payloadMustBeCbor) {
try {
cborPayload = CBORObject.DecodeFromBytes(req.getPayload());
} catch (CBORException ex) {
throw new AceException(ex.getMessage());
}
if (cborPayload != null
&& cborPayload.getType().equals(CBORType.Map)) {
this.parameters = Constants.getParams(cborPayload);
}
}
}
@Override
public byte[] getRawPayload() {
return this.request.getPayload();
}
@Override
public String getSenderId() {
EndpointContext ctx = this.request.getSourceContext();
if (ctx==null) {
return null;
}
if (ctx instanceof DtlsEndpointContext) {
Principal p = ctx.getPeerIdentity();
if (p==null) {
return null;
}
return p.getName();
}
// If OSCORE is used, retrieve the OSCORE SenderID and ContextID that the client
// used in the request, by using the information in the endpoint context.
// The OSCORE Sender ID that the client used in the request is the local OSCORE Recipient ID.
// The returned string has format ["ContextID:" +] "SenderID", depending on the presence of the OSCORE Context ID.
else if (ctx instanceof MapBasedEndpointContext) {
MapBasedEndpointContext mapCtx = (MapBasedEndpointContext) ctx;
byte[] clientSenderId = StringUtil
.hex2ByteArray((String) mapCtx.get(OSCoreEndpointContextInfo.OSCORE_RECIPIENT_ID));
byte[] idContext = StringUtil
.hex2ByteArray((String) mapCtx.get(OSCoreEndpointContextInfo.OSCORE_CONTEXT_ID));
if (clientSenderId == null) {
return null;
}
// The identity is a string with format ["A" + ":" +] "B", where A and B are
// the base64 encoding of the ContextID (if present) and of the SenderID.
String senderId = "";
if (idContext != null && idContext.length != 0) {
senderId += Base64.getEncoder().encodeToString(idContext);
senderId += ":";
}
senderId += Base64.getEncoder().encodeToString(clientSenderId);
return senderId;
}
return null;
}
@Override
public Set<Short> getParameterNames() {
if (this.parameters != null) {
return this.parameters.keySet();
}
return null;
}
@Override
public CBORObject getParameter(Short name) {
if (this.parameters != null) {
return this.parameters.get(name);
}
return null;
}
@Override
public Map<Short, CBORObject> getParameters() {
if (this.parameters != null) {
Map<Short, CBORObject> map = new HashMap<>();
map.putAll(this.parameters);
return map;
}
return null;
}
@Override
public Message successReply(int code, CBORObject payload) {
ResponseCode coapCode = ResponseCode.valueOf(code);
CoapRes res = new CoapRes(coapCode, payload);
return res;
}
@Override
public Message failReply(int failureReason, CBORObject payload) {
ResponseCode coapCode = ResponseCode.valueOf(failureReason);
CoapRes res = new CoapRes(coapCode, payload);
return res;
}
/**
* Create a CoAPRequest from a Californium <code>Request</code>.
*
* @param req the Californium Request
* @return the ACE CoAP request
* @throws AceException
*/
public static CoapReq getInstance(Request req) throws AceException {
return new CoapReq(req, true);
}
/**
* Create a CoAPRequest from a Californium <code>Request</code>.
*
* @param req the Californium Request
* @param payloadMustBeCbor if true, the payload (if any) MUST be in CBOR
* @return the ACE CoAP request
* @throws AceException
*/
public static CoapReq getInstance(Request req, boolean payloadMustBeCbor) throws AceException {
return new CoapReq(req, payloadMustBeCbor);
}
@Override
public int getMessageCode() {
return this.request.getCode().value;
}
/**
* @return the CoAP token associated with this message
*/
public Token getToken() {
return this.request.getToken();
}
/**
* @return the OptionSet associated with this message
*/
public OptionSet getOptions() {
return this.request.getOptions();
}
}