Package ch.ethz.inf.vs.californium.network.serialization

Source Code of ch.ethz.inf.vs.californium.network.serialization.DataParser

package ch.ethz.inf.vs.californium.network.serialization;

import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.CODE_BITS;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.EMPTY_CODE;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.MESSAGE_ID_BITS;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.PAYLOAD_MARKER;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.REQUEST_CODE_LOWER_BOUND;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.REQUEST_CODE_UPPER_BOUNT;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.RESPONSE_CODE_LOWER_BOUND;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.RESPONSE_CODE_UPPER_BOUND;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.TOKEN_LENGTH_BITS;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.TYPE_BITS;
import static ch.ethz.inf.vs.californium.coap.CoAP.MessageFormat.VERSION_BITS;
import ch.ethz.inf.vs.californium.coap.CoAP;
import ch.ethz.inf.vs.californium.coap.CoAP.Code;
import ch.ethz.inf.vs.californium.coap.CoAP.ResponseCode;
import ch.ethz.inf.vs.californium.coap.CoAP.Type;
import ch.ethz.inf.vs.californium.coap.EmptyMessage;
import ch.ethz.inf.vs.californium.coap.Message;
import ch.ethz.inf.vs.californium.coap.Option;
import ch.ethz.inf.vs.californium.coap.OptionSet;
import ch.ethz.inf.vs.californium.coap.Request;
import ch.ethz.inf.vs.californium.coap.Response;

/**
* The DataParser parses incoming byte arrays to messages.
*/
public class DataParser {

  private DatagramReader reader;
 
  private int version;
  private int type;
  private int tokenlength;
  private int code;
  private int mid;
 
  public DataParser(byte[] bytes) {
    setBytes(bytes);
  }
 
  public void setBytes(byte[] bytes) {
    this.reader = new DatagramReader(bytes);
    this.version = reader.read(VERSION_BITS);
    this.type = reader.read(TYPE_BITS);
    this.tokenlength = reader.read(TOKEN_LENGTH_BITS);
    this.code = reader.read(CODE_BITS);
    this.mid = reader.read(MESSAGE_ID_BITS);
  }
 
  public boolean isWellFormed() {
    return version == CoAP.VERSION;
  }
 
  public int getVersion() {
    return version;
  }
 
  public int getMID() {
    return mid;
  }
 
  public boolean isReply() {
    return type > CoAP.Type.NON.value;
  }
 
  public boolean isRequest() {
    return code >= REQUEST_CODE_LOWER_BOUND &&
        code <= REQUEST_CODE_UPPER_BOUNT;
  }
 
  public boolean isResponse() {
    return code >= RESPONSE_CODE_LOWER_BOUND &&
        code <= RESPONSE_CODE_UPPER_BOUND;
  }
 
  public boolean isEmpty() {
    return code == EMPTY_CODE;
  }
 
  public Request parseRequest() {
    assert(isRequest());
    Request request = new Request(Code.valueOf(code));
    parseMessage(request);
    return request;
  }
 
  public Response parseResponse() {
    assert(isResponse());
    Response response = new Response(ResponseCode.valueOf(code));
    parseMessage(response);
    return response;
  }
 
  public EmptyMessage parseEmptyMessage() {
    assert(!isRequest() && !isResponse());
    EmptyMessage message = new EmptyMessage(Type.valueOf(type));
    parseMessage(message);
    return message;
  }
 
  private void parseMessage(Message message) {
    message.setType(Type.valueOf(type));
    message.setMID(mid);   
   
    if (tokenlength>0) {
      message.setToken(reader.readBytes(tokenlength));
    } else {
      message.setToken(new byte[0]);
    }
   
    int currentOption = 0;
    byte nextByte = 0;
    while(reader.bytesAvailable()) {
      nextByte = reader.readNextByte();
      if (nextByte != PAYLOAD_MARKER) {
        // the first 4 bits of the byte represent the option delta
        int optionDeltaNibble = (0xF0 & nextByte) >> 4;
        currentOption += readOptionValueFromNibble(optionDeltaNibble);
       
        // the second 4 bits represent the option length
        int optionLengthNibble = (0x0F & nextByte);
        int optionLength = readOptionValueFromNibble(optionLengthNibble);
       
        // read option
        Option option = new Option(currentOption);
        option.setValue(reader.readBytes(optionLength));
       
        // add option to message
        addOptionToSet(option, message.getOptions());
      } else break;
    }
   
    if (nextByte == PAYLOAD_MARKER) {
      // the presence of a marker followed by a zero-length payload must be processed as a message format error
      if (!reader.bytesAvailable())
        throw new IllegalStateException();
     
      // get payload
      message.setPayload(reader.readBytesLeft());
    } else {
      message.setPayload(new byte[0]); // or null?
    }
  }
 
  // TODO: Can we optimize this a little by not creating new option objects for known options
  private void addOptionToSet(Option option, OptionSet optionSet) {
    switch (option.getNumber()) {
      case CoAP.OptionRegistry.IF_MATCH:       optionSet.addIfMatch(option.getValue()); break;
      case CoAP.OptionRegistry.URI_HOST:       optionSet.setURIHost(option.getStringValue()); break;
      case CoAP.OptionRegistry.ETAG:           optionSet.addETag(option.getValue()); break;
      case CoAP.OptionRegistry.IF_NONE_MATCH:  optionSet.setIfNoneMatch(true); break;
      case CoAP.OptionRegistry.URI_PORT:       optionSet.setURIPort(option.getIntegerValue()); break;
      case CoAP.OptionRegistry.LOCATION_PATH:  optionSet.addLocationPath(option.getStringValue()); break;
      case CoAP.OptionRegistry.URI_PATH:       optionSet.addURIPath(option.getStringValue()); break;
      case CoAP.OptionRegistry.CONTENT_FORMAT: optionSet.setContentFormat(option.getIntegerValue()); break;
      case CoAP.OptionRegistry.MAX_AGE:        optionSet.setMaxAge(option.getLongValue()); break;
      case CoAP.OptionRegistry.URI_QUERY:      optionSet.addURIQuery(option.getStringValue()); break;
      case CoAP.OptionRegistry.ACCEPT:         optionSet.setAccept(option.getIntegerValue()); break;
      case CoAP.OptionRegistry.LOCATION_QUERY: optionSet.addLocationQuery(option.getStringValue()); break;
      case CoAP.OptionRegistry.PROXY_URI:      optionSet.setProxyURI(option.getStringValue()); break;
      case CoAP.OptionRegistry.PROXY_SCHEME:   optionSet.setProxyScheme(option.getStringValue()); break;
      case CoAP.OptionRegistry.BLOCK1:         optionSet.setBlock1(option.getValue()); break;
      case CoAP.OptionRegistry.BLOCK2:         optionSet.setBlock2(option.getValue()); break;
      case CoAP.OptionRegistry.OBSERVE:        optionSet.setObserve(option.getIntegerValue()); break;
      default: optionSet.addOption(option);
    }
  }
 
  /**
   * Calculates the value used in the extended option fields as specified in
   * draft-ietf-core-coap-14, section 3.1
   *
   * @param nibble
   *            the 4-bit option header value.
   * @param datagram
   *            the datagram.
   * @return the value calculated from the nibble and the extended option
   *         value.
   */
  private int readOptionValueFromNibble(int nibble) {
    if (nibble <= 12) {
      return nibble;
    } else if (nibble == 13) {
      return reader.read(8) + 13;
    } else if (nibble == 14) {
      return reader.read(16) + 269;
    } else {
      throw new IllegalArgumentException("Unsupported option delta "+nibble);
    }
  }
}
TOP

Related Classes of ch.ethz.inf.vs.californium.network.serialization.DataParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.