1 /*******************************************************************************
2 * Copyright (c) 2007, 2014 Massimiliano Ziccardi
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16 package it.jnrpe.net;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.handler.codec.ReplayingDecoder;
21
22 import java.util.List;
23
24 import org.apache.commons.lang.ArrayUtils;
25
26 /**
27 * The NETTY implementation of the JNRPE protocol request decoder.
28 *
29 * @author Massimiliano Ziccardi
30 */
31 public class JNRPERequestDecoder extends
32 ReplayingDecoder<JNRPERequestDecoder.STAGE> {
33
34 /**
35 * The packet buffer length in bytes.
36 */
37 private static final int PACKETBUFFER_LENGTH = 1024;
38
39 /**
40 * The size of the random byte array.
41 */
42 private static final int DUMMYLENGTH = 2;
43
44 /**
45 * The decoded protocol packet.
46 */
47 private JNRPEProtocolPacket packet;
48
49 /**
50 * The decoded packet version.
51 */
52 private PacketVersion packetVersion;
53
54 /**
55 * The NETTY {@link ReplayingDecoder} will be called many times until all
56 * the data has been received from the server. This enum will be used to
57 * store the decoding process progress.
58 *
59 * @author Massimiliano Ziccardi
60 */
61 protected enum STAGE {
62 /**
63 * The next data we have to receive is the PACKET_VERSION.
64 */
65 PACKET_VERSION,
66 /**
67 * The next data we have to receive is the REQUST TYPE CODE.
68 */
69 PACKET_TYPE_CODE,
70 /**
71 * The next data we have to receive is the request CRC.
72 */
73 CRC,
74 /**
75 * The next data we have to receive is the RESULT CODE.
76 */
77 RESULT_CODE,
78 /**
79 * The next data we have to receive is DATA BUFFER.
80 */
81 BUFFER,
82 /**
83 * The next data we have to receive is DUMMY buffer.
84 */
85 DUMMY
86 };
87
88 /**
89 * Creates a new {@link JNRPERequestDecoder} object and sets the initial
90 * state at {@link STAGE#PACKET_VERSION}.
91 */
92 public JNRPERequestDecoder() {
93 super(STAGE.PACKET_VERSION);
94 }
95
96 @Override
97 protected final void decode(final ChannelHandlerContext ctx,
98 final ByteBuf in, final List<Object> out) throws Exception {
99
100 switch (state()) {
101 case PACKET_VERSION:
102 // packet.setPacketVersion(PacketVersion.fromIntValue(in.readShort()));
103 packetVersion = PacketVersion.fromIntValue(in.readShort());
104 checkpoint(STAGE.PACKET_TYPE_CODE);
105 case PACKET_TYPE_CODE:
106 // packet.setPacketType(PacketType.fromIntValue(in.readShort()));
107 PacketType type = PacketType.fromIntValue(in.readShort());
108 switch (type) {
109 case QUERY:
110 packet = new JNRPERequest();
111 break;
112 case RESPONSE:
113 packet = new JNRPEResponse();
114 break;
115 default:
116 throw new Exception("Unknown packet type");
117 }
118
119 packet.setPacketVersion(packetVersion);
120 checkpoint(STAGE.CRC);
121 case CRC:
122 packet.setCRC(in.readInt());
123 checkpoint(STAGE.RESULT_CODE);
124 case RESULT_CODE:
125 packet.setResultCode(in.readShort());
126 checkpoint(STAGE.BUFFER);
127 case BUFFER:
128 byte[] buff = new byte[PACKETBUFFER_LENGTH];
129 in.readBytes(buff);
130 packet.setBuffer(ztString2String(buff));
131 checkpoint(STAGE.DUMMY);
132 case DUMMY:
133 byte[] dummy = new byte[DUMMYLENGTH];
134 packet.setDummy(dummy);
135 out.add(packet);
136 reset();
137 break;
138 default:
139 throw new Error("Shouldn't reach here.");
140 }
141 }
142
143 /**
144 * Resets the decoder to the initial state.
145 */
146 private void reset() {
147 checkpoint(STAGE.PACKET_VERSION);
148 }
149
150 /**
151 * Convert a '0' terminated string to a java string.
152 *
153 * @param buff
154 * the '0' terminated string
155 * @return the java string
156 */
157 private String ztString2String(final byte[] buff) {
158 return new String(buff, 0, ArrayUtils.indexOf(buff, (byte) 0));
159 }
160
161 }