2 * //******************************************************************
4 * // Copyright 2016 Samsung Electronics All Rights Reserved.
6 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
8 * // Licensed under the Apache License, Version 2.0 (the "License");
9 * // you may not use this file except in compliance with the License.
10 * // You may obtain a copy of the License at
12 * // http://www.apache.org/licenses/LICENSE-2.0
14 * // Unless required by applicable law or agreed to in writing, software
15 * // distributed under the License is distributed on an "AS IS" BASIS,
16 * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * // See the License for the specific language governing permissions and
18 * // limitations under the License.
20 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 package org.iotivity.cloud.base.protocols.coap;
24 import java.util.List;
26 import org.iotivity.cloud.base.protocols.coap.enums.CoapMethod;
27 import org.iotivity.cloud.base.protocols.coap.enums.CoapStatus;
29 import io.netty.buffer.ByteBuf;
30 import io.netty.channel.ChannelHandlerContext;
31 import io.netty.handler.codec.ByteToMessageDecoder;
33 public class CoapDecoder extends ByteToMessageDecoder {
35 private enum ParsingState {
36 SHIM_HEADER, OPTION_PAYLOAD_LENGTH, CODE_TOKEN_OPTION, PAYLOAD, FINISH
39 private ParsingState nextState = ParsingState.SHIM_HEADER;
40 private int bufferToRead = 1;
41 private int tokenLength = 0;
42 private int optionPayloadLength = 0;
43 private CoapMessage partialMsg = null;
46 protected void decode(ChannelHandlerContext ctx, ByteBuf in,
47 List<Object> out) throws Exception {
49 while (in.isReadable(bufferToRead)) {
53 int shimHeader = in.readByte();
54 bufferToRead = (shimHeader >>> 4) & 0x0F;
55 tokenLength = (shimHeader) & 0x0F;
56 switch (bufferToRead) {
59 nextState = ParsingState.OPTION_PAYLOAD_LENGTH;
63 nextState = ParsingState.OPTION_PAYLOAD_LENGTH;
67 nextState = ParsingState.OPTION_PAYLOAD_LENGTH;
70 optionPayloadLength = bufferToRead;
71 bufferToRead += 1 + tokenLength; // code + tkl
72 nextState = ParsingState.CODE_TOKEN_OPTION;
77 case OPTION_PAYLOAD_LENGTH:
78 switch (bufferToRead) {
80 optionPayloadLength = 13 + (in.readByte() & 0xFF);
84 optionPayloadLength = 269
85 + (((in.readByte() & 0xFF) << 8)
86 + (in.readByte() & 0xFF));
90 optionPayloadLength = 65805
91 + (((in.readByte() & 0xFF) << 24)
92 + ((in.readByte() & 0xFF) << 16)
93 + ((in.readByte() & 0xFF) << 8)
94 + (in.readByte() & 0xFF));
97 nextState = ParsingState.CODE_TOKEN_OPTION;
98 bufferToRead = 1 + tokenLength + optionPayloadLength; // code
103 case CODE_TOKEN_OPTION:
104 int code = in.readByte() & 0xFF;
107 partialMsg = new CoapRequest(CoapMethod.valueOf(code));
109 partialMsg = new CoapResponse(CoapStatus.valueOf(code));
112 if (tokenLength > 0) {
113 byte[] token = new byte[tokenLength];
115 partialMsg.setToken(token);
118 if (optionPayloadLength > 0) {
119 int optionLen = parseOptions(partialMsg, in,
120 optionPayloadLength);
121 if (optionPayloadLength > optionLen) {
122 nextState = ParsingState.PAYLOAD;
123 bufferToRead = optionPayloadLength - optionLen;
128 nextState = ParsingState.FINISH;
134 byte[] payload = new byte[bufferToRead];
135 in.readBytes(payload);
136 partialMsg.setPayload(payload);
137 nextState = ParsingState.FINISH;
142 nextState = ParsingState.SHIM_HEADER;
152 in.discardReadBytes();
155 private int parseOptions(CoapMessage coapMessage, ByteBuf byteBuf,
158 int preOptionNum = 0;
160 int startPos = byteBuf.readerIndex();
162 int firstByte = byteBuf.readByte() & 0xFF;
164 while (firstByte != 0xFF && maxLength > 0) {
165 int optionDelta = (firstByte & 0xF0) >>> 4;
166 int optionLength = firstByte & 0x0F;
168 if (optionDelta == 13) {
169 optionDelta = 13 + byteBuf.readByte() & 0xFF;
170 } else if (optionDelta == 14) {
171 optionDelta = 269 + ((byteBuf.readByte() & 0xFF) << 8)
172 + (byteBuf.readByte() & 0xFF);
175 if (optionLength == 13) {
176 optionLength = 13 + byteBuf.readByte() & 0xFF;
177 } else if (optionLength == 14) {
178 optionLength = 269 + ((byteBuf.readByte() & 0xFF) << 8)
179 + (byteBuf.readByte() & 0xFF);
182 int curOptionNum = preOptionNum + optionDelta;
183 byte[] optionValue = new byte[optionLength];
184 byteBuf.readBytes(optionValue);
186 coapMessage.addOption(curOptionNum, optionValue);
188 preOptionNum = curOptionNum;
189 if (maxLength > byteBuf.readerIndex() - startPos) {
190 firstByte = byteBuf.readByte() & 0xFF;
196 /// return option length
197 return byteBuf.readerIndex() - startPos;