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 java.io.ByteArrayOutputStream;
19  import java.io.DataInputStream;
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.nio.charset.Charset;
24  import java.util.Arrays;
25  import java.util.Random;
26  import java.util.zip.CRC32;
27  
28  import org.apache.commons.lang.ArrayUtils;
29  
30  /**
31   * This class represent a generic NRPE protocol packet.
32   * 
33   * @author Massimiliano Ziccardi
34   */
35  class JNRPEProtocolPacket {
36  
37  	/**
38  	 * Max amount of data we'll send in one query/response.
39  	 */
40  	private static final int MAX_PACKETBUFFER_LENGTH = 1024;
41  
42  	/**
43  	 * The charset.
44  	 */
45  	private Charset charset = Charset.forName("UTF-8");
46  
47  	/**
48  	 * The CRC value.
49  	 */
50  	private int crcValue;
51  
52  	/**
53  	 * The packet type.
54  	 */
55  	private int packetTypeCode;
56  
57  	/**
58  	 * The packet version.
59  	 */
60  	private int packetVersion;
61  
62  	/**
63  	 * The result code.
64  	 */
65  	private int resultCode;
66  
67  	/**
68  	 * The packet buffer.
69  	 */
70  	private byte[] byteBufferAry = new byte[MAX_PACKETBUFFER_LENGTH];
71  
72  	/**
73  	 * Dummy bytes.
74  	 */
75  	private final byte[] dummyBytesAry = new byte[2];
76  
77  	/**
78  	 * Returns the packet CRC value.
79  	 * 
80  	 * @return the CRC value
81  	 */
82  	int getCRC() {
83  		return crcValue;
84  	}
85  
86  	/**
87  	 * Returns the packet type.
88  	 * 
89  	 * @return The packet type
90  	 */
91  	PacketType getPacketType() {
92  		return PacketType.fromIntValue(packetTypeCode);
93  	}
94  
95  	/**
96  	 * Returns the packet version.
97  	 * 
98  	 * @return The packet version
99  	 */
100 	public PacketVersion getPacketVersion() {
101 		return PacketVersion.fromIntValue(packetVersion);
102 	}
103 
104 	/**
105 	 * Sets the CRC value.
106 	 * 
107 	 * @param crc
108 	 *            The new CRC value
109 	 */
110 	void setCRC(final int crc) {
111 		crcValue = crc;
112 	}
113 
114 	/**
115 	 * Sets the packet type.
116 	 * 
117 	 * @param packetType
118 	 *            The new packet type
119 	 */
120 	protected void setPacketType(final PacketType packetType) {
121 		packetTypeCode = packetType.intValue();
122 	}
123 
124 	/**
125 	 * Sets the packet version.
126 	 * 
127 	 * @param version
128 	 *            The packet version
129 	 */
130 	public void setPacketVersion(final PacketVersion version) {
131 		packetVersion = version.intValue();
132 	}
133 
134 	/**
135 	 * Changes the default charset.
136 	 * 
137 	 * @param newCharset
138 	 *            the new charset,
139 	 */
140 	public void setCharset(final Charset newCharset) {
141 		this.charset = newCharset;
142 	}
143 
144 	/**
145 	 * Returns the result code.
146 	 * 
147 	 * @return The result code
148 	 */
149 	public int getResultCode() {
150 		return resultCode;
151 	}
152 
153 	/**
154 	 * Sets the result code.
155 	 * 
156 	 * @param status
157 	 *            The new result code
158 	 */
159 	public void setResultCode(final int status) {
160 		resultCode = status;
161 	}
162 
163 	/**
164 	 * Validates the packet CRC.
165 	 * 
166 	 * @throws BadCRCException
167 	 *             If the CRC can't be validated
168 	 */
169 	public void validate() throws BadCRCException {
170 		ByteArrayOutputStream bout = new ByteArrayOutputStream();
171 		DataOutputStream dout = new DataOutputStream(bout);
172 
173 		try {
174 			dout.writeShort(packetVersion);
175 			dout.writeShort(packetTypeCode);
176 			dout.writeInt(0); // NO CRC
177 			dout.writeShort(resultCode);
178 			dout.write(byteBufferAry);
179 			dout.write(dummyBytesAry);
180 
181 			dout.close();
182 
183 			byte[] vBytes = bout.toByteArray();
184 
185 			CRC32 crcAlg = new CRC32();
186 			crcAlg.update(vBytes);
187 
188 			if (!(((int) crcAlg.getValue()) == crcValue)) {
189 				throw new BadCRCException("Bad CRC");
190 			}
191 		} catch (IOException e) {
192 			throw new IllegalStateException(e);
193 		}
194 	}
195 
196 	protected byte[] getBuffer() {
197 		return byteBufferAry;
198 	}
199 
200 	protected String getPacketString() {
201 		byte[] buffer = getBuffer();
202 		int zeroIndex = ArrayUtils.indexOf(buffer, (byte) 0);
203 
204 		if (zeroIndex == ArrayUtils.INDEX_NOT_FOUND) {
205 			return new String(buffer);
206 		} else {
207 			return new String(buffer, 0, zeroIndex);
208 		}
209 	}
210 
211 	/**
212 	 * Initializes the arrays with random data. Not sure it is really needed...
213 	 */
214 	private void initRandomBuffer() {
215 		Random r = new Random(System.currentTimeMillis());
216 
217 		r.nextBytes(byteBufferAry);
218 		r.nextBytes(dummyBytesAry);
219 	}
220 
221 	protected void setBuffer(final String buffer) {
222 		initRandomBuffer();
223 		byteBufferAry = Arrays.copyOf(buffer.getBytes(charset),
224 				MAX_PACKETBUFFER_LENGTH);
225 	}
226 
227 	void setDummy(final byte[] dummyBytes) {
228 		if (dummyBytes == null || dummyBytes.length != 2) {
229 			throw new IllegalArgumentException(
230 					"Dummy bytes array must have exactly two elements");
231 		}
232 
233 		System.arraycopy(dummyBytes, 0, this.dummyBytesAry, 0, 2);
234 	}
235 
236 	byte[] getDummy() {
237 		return dummyBytesAry;
238 	}
239 
240 	void updateCRC() {
241 		setCRC(0);
242 		CRC32 crcAlg = new CRC32();
243 		crcAlg.update(toByteArray());
244 
245 		setCRC((int) crcAlg.getValue());
246 	}
247 
248 	/**
249 	 * Converts the packet object to its byte array representation.
250 	 * 
251 	 * @return The byte array representation of this packet.
252 	 */
253 	public byte[] toByteArray() {
254 		ByteArrayOutputStream bout = new ByteArrayOutputStream();
255 		DataOutputStream dout = new DataOutputStream(bout);
256 
257 		try {
258 			dout.writeShort(packetVersion);
259 			dout.writeShort(packetTypeCode);
260 			dout.writeInt(crcValue);
261 			dout.writeShort(resultCode);
262 			dout.write(byteBufferAry);
263 			dout.write(dummyBytesAry);
264 
265 			dout.close();
266 		} catch (IOException e) {
267 			throw new IllegalStateException(e);
268 		}
269 		return bout.toByteArray();
270 	}
271 
272 	protected void fromInputStream(final InputStream in) throws IOException {
273 		DataInputStream din = new DataInputStream(in);
274 		packetVersion = din.readShort();
275 		packetTypeCode = din.readShort();
276 		crcValue = din.readInt();
277 		resultCode = din.readShort();
278 		din.readFully(byteBufferAry);
279 		din.readFully(dummyBytesAry);
280 	}
281 }