[Simulator] Minor UI changes fixing the IOT-1087.
[platform/upstream/iotivity.git] / cloud / stack / src / main / java / org / iotivity / cloud / base / protocols / coap / CoapEncoder.java
1 /*
2  *******************************************************************
3  *
4  * Copyright 2016 Samsung Electronics All Rights Reserved.
5  *
6  *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7  *
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
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21  */
22 package org.iotivity.cloud.base.protocols.coap;
23
24 import java.util.List;
25
26 import io.netty.buffer.ByteBuf;
27 import io.netty.buffer.Unpooled;
28 import io.netty.channel.ChannelHandlerContext;
29 import io.netty.handler.codec.MessageToByteEncoder;
30
31 public class CoapEncoder extends MessageToByteEncoder<CoapMessage> {
32
33     @Override
34     protected void encode(ChannelHandlerContext ctx, CoapMessage msg,
35             ByteBuf out) throws Exception {
36
37         CoapMessage coapMessage = (CoapMessage) msg;
38
39         ByteBuf optBuf = Unpooled.directBuffer();
40
41         /**
42          * encode options
43          */
44         encodeOptions(optBuf, coapMessage);
45         long length = optBuf.readableBytes();
46
47         if (coapMessage.getPayloadSize() > 0) {
48             // + 1 means 8bits delimiter
49             length += 1 + coapMessage.getPayloadSize();
50         }
51
52         calcShimHeader(coapMessage, out, length);
53
54         out.writeByte(coapMessage.getCode());
55
56         if (coapMessage.getTokenLength() > 0) {
57             out.writeBytes(coapMessage.getToken());
58         }
59
60         // Write option
61         if (optBuf.readableBytes() > 0) {
62             out.writeBytes(optBuf);
63         }
64
65         optBuf.release();
66
67         if (coapMessage.getPayloadSize() > 0) {
68             out.writeByte(255);
69             out.writeBytes(coapMessage.getPayload());
70         }
71     }
72
73     private void calcShimHeader(CoapMessage coapMessage, ByteBuf byteBuf,
74             long length) {
75         if (length < 13) {
76             byteBuf.writeByte(((int) length & 0x0F) << 4
77                     | (coapMessage.getTokenLength() & 0x0F));
78         } else if (length < 269) {
79             byteBuf.writeShort((13 & 0x0F) << 12
80                     | (coapMessage.getTokenLength() & 0x0F) << 8
81                     | (((int) length - 13) & 0xFF));
82         } else if (length < 65805) {
83             byteBuf.writeByte(
84                     (14 & 0x0F) << 4 | (coapMessage.getTokenLength() & 0x0F));
85             byteBuf.writeShort(((int) length - 269) & 0xFFFF);
86         } else if (length < Integer.MAX_VALUE * 2) {
87             byteBuf.writeByte(
88                     (15 & 0x0F) << 4 | (coapMessage.getTokenLength() & 0x0F));
89             byteBuf.writeLong((length - 65805) & 0xFFFFFFFF);
90         } else {
91             throw new IllegalArgumentException(
92                     "Length must be less than 4GB " + length);
93         }
94     }
95
96     private void encodeOptions(ByteBuf byteBuf, CoapMessage coapMessage)
97             throws Exception {
98         int preOptionNum = 0;
99
100         for (int i = 0; i < 40; i++) {
101             List<byte[]> values = coapMessage.getOption(i);
102             if (values != null) {
103                 for (byte[] value : values) {
104                     writeOption(i - preOptionNum,
105                             value != null ? value.length : 0, byteBuf, value);
106                     preOptionNum = i;
107                 }
108             }
109         }
110     }
111
112     private void writeOption(int optionDelta, int optionLength, ByteBuf byteBuf,
113             byte[] value) {
114
115         if (optionDelta < 13) {
116             if (optionLength < 13) {
117                 byteBuf.writeByte(
118                         ((optionDelta & 0xFF) << 4) | (optionLength & 0xFF));
119             } else if (optionLength < 269) {
120                 byteBuf.writeByte(((optionDelta << 4) & 0xFF) | (13 & 0xFF));
121                 byteBuf.writeByte((optionLength - 13) & 0xFF);
122             } else {
123                 byteBuf.writeByte(((optionDelta << 4) & 0xFF) | (14 & 0xFF));
124                 byteBuf.writeByte(((optionLength - 269) & 0xFF00) >>> 8);
125                 byteBuf.writeByte((optionLength - 269) & 0xFF);
126             }
127         }
128
129         else if (optionDelta < 269) {
130             if (optionLength < 13) {
131                 byteBuf.writeByte(((13 & 0xFF) << 4) | (optionLength & 0xFF));
132                 byteBuf.writeByte((optionDelta - 13) & 0xFF);
133             } else if (optionLength < 269) {
134                 byteBuf.writeByte(((13 & 0xFF) << 4) | (13 & 0xFF));
135                 byteBuf.writeByte((optionDelta - 13) & 0xFF);
136                 byteBuf.writeByte((optionLength - 13) & 0xFF);
137             } else {
138                 byteBuf.writeByte((13 & 0xFF) << 4 | (14 & 0xFF));
139                 byteBuf.writeByte((optionDelta - 13) & 0xFF);
140                 byteBuf.writeByte(((optionLength - 269) & 0xFF00) >>> 8);
141                 byteBuf.writeByte((optionLength - 269) & 0xFF);
142             }
143         }
144
145         else if (optionDelta < 65805) {
146
147             if (optionLength < 13) {
148                 byteBuf.writeByte(((14 & 0xFF) << 4) | (optionLength & 0xFF));
149                 byteBuf.writeByte(((optionDelta - 269) & 0xFF00) >>> 8);
150                 byteBuf.writeByte((optionDelta - 269) & 0xFF);
151             }
152
153             else if (optionLength < 269) {
154                 byteBuf.writeByte(((14 & 0xFF) << 4) | (13 & 0xFF));
155                 byteBuf.writeByte(((optionDelta - 269) & 0xFF00) >>> 8);
156                 byteBuf.writeByte((optionDelta - 269) & 0xFF);
157                 byteBuf.writeByte((optionLength - 13) & 0xFF);
158             }
159
160             else {
161                 byteBuf.writeByte(((14 & 0xFF) << 4) | (14 & 0xFF));
162                 byteBuf.writeByte(((optionDelta - 269) & 0xFF00) >>> 8);
163                 byteBuf.writeByte((optionDelta - 269) & 0xFF);
164                 byteBuf.writeByte(((optionLength - 269) & 0xFF00) >>> 8);
165                 byteBuf.writeByte((optionLength - 269) & 0xFF);
166             }
167         } else {
168             throw new IllegalArgumentException(
169                     "Unsupported option delta " + optionDelta);
170         }
171
172         if (optionLength > 0) {
173             byteBuf.writeBytes(value);
174         }
175     }
176 }