View Javadoc

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 }