001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020:
021: package org.apache.mina.filter.errorgenerating;
022:
023: import java.util.Random;
024:
025: import org.apache.mina.common.DefaultWriteRequest;
026: import org.apache.mina.common.IoBuffer;
027: import org.apache.mina.common.IoFilter;
028: import org.apache.mina.common.IoFilterAdapter;
029: import org.apache.mina.common.IoSession;
030: import org.apache.mina.common.WriteRequest;
031: import org.slf4j.Logger;
032: import org.slf4j.LoggerFactory;
033:
034: /**
035: * An {@link IoFilter} implementation generating random bytes and PDU modification in
036: * your communication streams.
037: * It's quite simple to use :
038: * <code>ErrorGeneratingFilter egf = new ErrorGeneratingFilter();</code>
039: * For activate the change of some bytes in your {@link IoBuffer}, for a probability of 200 out
040: * of 1000 {@link IoBuffer} processed :
041: * <code>egf.setChangeByteProbability(200);</code>
042: * For activate the insertion of some bytes in your {@link IoBuffer}, for a
043: * probability of 200 out of 1000 :
044: * <code>egf.setInsertByteProbability(200);</code>
045: * And for the removing of some bytes :
046: * <code>egf.setRemoveByteProbability(200);</code>
047: * You can activate the error generation for write or read with the
048: * following methods :
049: * <code>egf.setManipulateReads(true);
050: * egf.setManipulateWrites(true); </code>
051: *
052: * @author The Apache MINA Project (dev@mina.apache.org)
053: * @version $Rev: 612456 $, $Date: 2008-01-16 14:49:47 +0100 (mer., 16 janv. 2008) $
054: */
055: public class ErrorGeneratingFilter extends IoFilterAdapter {
056: private int removeByteProbability = 0;
057:
058: private int insertByteProbability = 0;
059:
060: private int changeByteProbability = 0;
061:
062: private int removePduProbability = 0;
063:
064: private int duplicatePduProbability = 0;
065:
066: private int resendPduLasterProbability = 0;
067:
068: private int maxInsertByte = 10;
069:
070: private boolean manipulateWrites = false;
071:
072: private boolean manipulateReads = false;
073:
074: private Random rng = new Random();
075:
076: final private Logger logger = LoggerFactory
077: .getLogger(ErrorGeneratingFilter.class);
078:
079: @Override
080: public void filterWrite(NextFilter nextFilter, IoSession session,
081: WriteRequest writeRequest) throws Exception {
082: if (manipulateWrites) {
083: // manipulate bytes
084: if (writeRequest.getMessage() instanceof IoBuffer) {
085: manipulateIoBuffer(session, (IoBuffer) writeRequest
086: .getMessage());
087: IoBuffer buffer = insertBytesToNewIoBuffer(session,
088: (IoBuffer) writeRequest.getMessage());
089: if (buffer != null) {
090: writeRequest = new DefaultWriteRequest(buffer,
091: writeRequest.getFuture(), writeRequest
092: .getDestination());
093: }
094: // manipulate PDU
095: } else {
096: if (duplicatePduProbability > rng.nextInt()) {
097: nextFilter.filterWrite(session, writeRequest);
098: }
099: if (resendPduLasterProbability > rng.nextInt()) {
100: // store it somewhere and trigger a write execution for
101: // later
102: // TODO
103: }
104: if (removePduProbability > rng.nextInt()) {
105: return;
106: }
107: }
108: }
109: nextFilter.filterWrite(session, writeRequest);
110: }
111:
112: @Override
113: public void messageReceived(NextFilter nextFilter,
114: IoSession session, Object message) throws Exception {
115: if (manipulateReads) {
116: if (message instanceof IoBuffer) {
117: // manipulate bytes
118: manipulateIoBuffer(session, (IoBuffer) message);
119: IoBuffer buffer = insertBytesToNewIoBuffer(session,
120: (IoBuffer) message);
121: if (buffer != null) {
122: message = buffer;
123: }
124: } else {
125: // manipulate PDU
126: }
127: }
128: nextFilter.messageReceived(session, message);
129: }
130:
131: private IoBuffer insertBytesToNewIoBuffer(IoSession session,
132: IoBuffer buffer) {
133: if (insertByteProbability > rng.nextInt(1000)) {
134: logger.info(buffer.getHexDump());
135: // where to insert bytes ?
136: int pos = rng.nextInt(buffer.remaining()) - 1;
137:
138: // how many byte to insert ?
139: int count = rng.nextInt(maxInsertByte - 1) + 1;
140:
141: IoBuffer newBuff = IoBuffer.allocate(buffer.remaining()
142: + count);
143: for (int i = 0; i < pos; i++)
144: newBuff.put(buffer.get());
145: for (int i = 0; i < count; i++) {
146: newBuff.put((byte) (rng.nextInt(256)));
147: }
148: while (buffer.remaining() > 0) {
149: newBuff.put(buffer.get());
150: }
151: newBuff.flip();
152:
153: logger.info("Inserted " + count + " bytes.");
154: logger.info(newBuff.getHexDump());
155: return newBuff;
156: }
157: return null;
158: }
159:
160: private void manipulateIoBuffer(IoSession session, IoBuffer buffer) {
161: if (removeByteProbability > rng.nextInt(1000)) {
162: logger.info(buffer.getHexDump());
163: // where to remove bytes ?
164: int pos = rng.nextInt(buffer.remaining());
165: // how many byte to remove ?
166: int count = rng.nextInt(buffer.remaining() - pos) + 1;
167: if (count == buffer.remaining())
168: count = buffer.remaining() - 1;
169:
170: IoBuffer newBuff = IoBuffer.allocate(buffer.remaining()
171: - count);
172: for (int i = 0; i < pos; i++)
173: newBuff.put(buffer.get());
174:
175: buffer.skip(count); // hole
176: while (newBuff.remaining() > 0)
177: newBuff.put(buffer.get());
178: newBuff.flip();
179: // copy the new buffer in the old one
180: buffer.rewind();
181: buffer.put(newBuff);
182: buffer.flip();
183: logger.info("Removed " + count + " bytes at position "
184: + pos + ".");
185: logger.info(buffer.getHexDump());
186: }
187: if (changeByteProbability > rng.nextInt(1000)) {
188: logger.info(buffer.getHexDump());
189: // how many byte to change ?
190: int count = rng.nextInt(buffer.remaining() - 1) + 1;
191:
192: byte[] values = new byte[count];
193: rng.nextBytes(values);
194: for (int i = 0; i < values.length; i++) {
195: int pos = rng.nextInt(buffer.remaining());
196: buffer.put(pos, values[i]);
197: }
198: logger.info("Modified " + count + " bytes.");
199: logger.info(buffer.getHexDump());
200: }
201: }
202:
203: public int getChangeByteProbability() {
204: return changeByteProbability;
205: }
206:
207: /**
208: * Set the probability for the change byte error.
209: * If this probability is > 0 the filter will modify a random number of byte
210: * of the processed {@link IoBuffer}.
211: * @param changeByteProbability probability of modifying an IoBuffer out of 1000 processed {@link IoBuffer}
212: */
213: public void setChangeByteProbability(int changeByteProbability) {
214: this .changeByteProbability = changeByteProbability;
215: }
216:
217: public int getDuplicatePduProbability() {
218: return duplicatePduProbability;
219: }
220:
221: /**
222: * not functional ATM
223: * @param duplicatePduProbability
224: */
225: public void setDuplicatePduProbability(int duplicatePduProbability) {
226: this .duplicatePduProbability = duplicatePduProbability;
227: }
228:
229: public int getInsertByteProbability() {
230: return insertByteProbability;
231: }
232:
233: /**
234: * Set the probability for the insert byte error.
235: * If this probability is > 0 the filter will insert a random number of byte
236: * in the processed {@link IoBuffer}.
237: * @param changeByteProbability probability of inserting in IoBuffer out of 1000 processed {@link IoBuffer}
238: */
239: public void setInsertByteProbability(int insertByteProbability) {
240: this .insertByteProbability = insertByteProbability;
241: }
242:
243: public boolean isManipulateReads() {
244: return manipulateReads;
245: }
246:
247: /**
248: * Set to true if you want to apply error to the read {@link IoBuffer}
249: * @param manipulateReads
250: */
251: public void setManipulateReads(boolean manipulateReads) {
252: this .manipulateReads = manipulateReads;
253: }
254:
255: public boolean isManipulateWrites() {
256: return manipulateWrites;
257: }
258:
259: /**
260: * Set to true if you want to apply error to the written {@link IoBuffer}
261: * @param manipulateWrites
262: */
263: public void setManipulateWrites(boolean manipulateWrites) {
264: this .manipulateWrites = manipulateWrites;
265: }
266:
267: public int getRemoveByteProbability() {
268: return removeByteProbability;
269: }
270:
271: /**
272: * Set the probability for the remove byte error.
273: * If this probability is > 0 the filter will remove a random number of byte
274: * in the processed {@link IoBuffer}.
275: * @param changeByteProbability probability of modifying an {@link IoBuffer} out of 1000 processed IoBuffer
276: */
277: public void setRemoveByteProbability(int removeByteProbability) {
278: this .removeByteProbability = removeByteProbability;
279: }
280:
281: public int getRemovePduProbability() {
282: return removePduProbability;
283: }
284:
285: /**
286: * not functional ATM
287: * @param removePduProbability
288: */
289: public void setRemovePduProbability(int removePduProbability) {
290: this .removePduProbability = removePduProbability;
291: }
292:
293: public int getResendPduLasterProbability() {
294: return resendPduLasterProbability;
295: }
296:
297: /**
298: * not functional ATM
299: * @param resendPduLasterProbability
300: */
301: public void setResendPduLasterProbability(
302: int resendPduLasterProbability) {
303: this .resendPduLasterProbability = resendPduLasterProbability;
304: }
305:
306: public int getMaxInsertByte() {
307: return maxInsertByte;
308: }
309:
310: /**
311: * Set the maximum number of byte the filter can insert in a {@link IoBuffer}.
312: * The default value is 10.
313: * @param maxInsertByte maximum bytes inserted in a {@link IoBuffer}
314: */
315: public void setMaxInsertByte(int maxInsertByte) {
316: this.maxInsertByte = maxInsertByte;
317: }
318: }
|