1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.coap.codec;
21
22 import java.nio.ByteBuffer;
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.apache.mina.coap.CoapMessage;
27 import org.apache.mina.coap.CoapOption;
28 import org.apache.mina.coap.CoapOptionType;
29 import org.apache.mina.coap.MessageType;
30 import org.apache.mina.codec.ProtocolDecoderException;
31 import org.apache.mina.codec.StatelessProtocolDecoder;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35
36
37
38
39
40
41
42 public class CoapDecoder implements StatelessProtocolDecoder<ByteBuffer, CoapMessage> {
43
44 private static final Logger LOG = LoggerFactory.getLogger(CoapDecoder.class);
45
46 private static final CoapOption[] EMPTY_OPTION = new CoapOption[0];
47
48 private static final byte[] EMPTY_PAYLOAD = new byte[0];
49
50
51
52
53 @Override
54 public Void createDecoderState() {
55 return null;
56 }
57
58
59
60
61 @Override
62 public CoapMessage decode(ByteBuffer input, Void context) {
63 LOG.debug("decode");
64
65 if (input.remaining() <= 0) {
66 LOG.debug("nothing to decode");
67 return null;
68 }
69 int byte0 = input.get() & 0xFF;
70 int version = (byte0 >> 6) & 0x3;
71 MessageType type = MessageType.fromCode((byte0 >> 4) & 0x3);
72 byte[] token = new byte[byte0 & 0xF];
73 int code = input.get() & 0xFF;
74 int id = input.getShort() & 0xFFFF;
75 input.get(token);
76
77
78 int optionCode = 0;
79 byte[] payload = EMPTY_PAYLOAD;
80 List<CoapOption> options = new ArrayList<CoapOption>();
81 while (input.hasRemaining()) {
82 int next = input.get() & 0xFF;
83
84
85 if (next == 0xFF) {
86 payload = new byte[input.remaining()];
87 input.get(payload);
88 break;
89 } else {
90 int optionDeltaQuartet = (next >> 4) & 0xF;
91
92 optionCode += optionFromQuartet(optionDeltaQuartet, input);
93
94
95 int optionLenQuartet = next & 0x0F;
96 int optionLength = optionFromQuartet(optionLenQuartet, input);
97
98
99 CoapOptionType optType = CoapOptionType.fromCode(optionCode);
100 if (optType == null) {
101 throw new ProtocolDecoderException("unknown option code : " + optionCode);
102 }
103
104
105 byte[] optionValue = new byte[optionLength];
106 input.get(optionValue);
107
108 options.add(new CoapOption(optType, optionValue));
109 }
110 }
111
112 if (input.hasRemaining()) {
113 throw new ProtocolDecoderException("trailling " + input.remaining() + " bytes in the UDP datagram");
114 }
115 return new CoapMessage(version, type, code, id, token, options.toArray(EMPTY_OPTION), payload);
116 }
117
118
119
120
121 @Override
122 public void finishDecode(Void context) {
123 }
124
125 private int optionFromQuartet(int value, ByteBuffer input) {
126 if (value < 13) {
127 return value;
128 } else if (value == 13) {
129 return (input.get() & 0xFF) + 13;
130 } else if (value == 14) {
131 return (input.getShort() & 0xFFFF) + 269;
132 } else {
133 throw new ProtocolDecoderException("illegal option quartet value : " + value);
134 }
135 }
136 }