View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  
21  package org.apache.mina.filter.errorgenerating;
22  
23  import java.util.Random;
24  
25  import org.apache.mina.core.buffer.IoBuffer;
26  import org.apache.mina.core.filterchain.IoFilter;
27  import org.apache.mina.core.filterchain.IoFilterAdapter;
28  import org.apache.mina.core.session.IoSession;
29  import org.apache.mina.core.write.DefaultWriteRequest;
30  import org.apache.mina.core.write.WriteRequest;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  /**
35   * An {@link IoFilter} implementation generating random bytes and PDU modification in
36   * your communication streams.
37   * It's quite simple to use :
38   * <code>ErrorGeneratingFilter egf = new ErrorGeneratingFilter();</code>
39   * For activate the change of some bytes in your {@link IoBuffer}, for a probability of 200 out
40   * of 1000 {@link IoBuffer} processed :
41   * <code>egf.setChangeByteProbability(200);</code>
42   * For activate the insertion of some bytes in your {@link IoBuffer}, for a
43   * probability of 200 out of 1000 :
44   * <code>egf.setInsertByteProbability(200);</code>
45   * And for the removing of some bytes :
46   * <code>egf.setRemoveByteProbability(200);</code>
47   * You can activate the error generation for write or read with the
48   * following methods :
49   * <code>egf.setManipulateReads(true);
50   * egf.setManipulateWrites(true); </code>
51   * 
52   * @author The Apache MINA Project (dev@mina.apache.org)
53   * @version $Rev: 612456 $, $Date: 2008-01-16 14:49:47 +0100 (mer., 16 janv. 2008) $
54   * @org.apache.xbean.XBean
55   */
56  public class ErrorGeneratingFilter extends IoFilterAdapter {
57      private int removeByteProbability = 0;
58  
59      private int insertByteProbability = 0;
60  
61      private int changeByteProbability = 0;
62  
63      private int removePduProbability = 0;
64  
65      private int duplicatePduProbability = 0;
66  
67      private int resendPduLasterProbability = 0;
68  
69      private int maxInsertByte = 10;
70  
71      private boolean manipulateWrites = false;
72  
73      private boolean manipulateReads = false;
74  
75      private Random rng = new Random();
76  
77      final private Logger logger = LoggerFactory
78              .getLogger(ErrorGeneratingFilter.class);
79  
80      @Override
81      public void filterWrite(NextFilter nextFilter, IoSession session,
82              WriteRequest writeRequest) throws Exception {
83          if (manipulateWrites) {
84              // manipulate bytes
85              if (writeRequest.getMessage() instanceof IoBuffer) {
86                  manipulateIoBuffer(session, (IoBuffer) writeRequest
87                          .getMessage());
88                  IoBuffer buffer = insertBytesToNewIoBuffer(session,
89                          (IoBuffer) writeRequest.getMessage());
90                  if (buffer != null) {
91                      writeRequest = new DefaultWriteRequest(buffer, writeRequest
92                              .getFuture(), writeRequest.getDestination());
93                  }
94                  // manipulate PDU
95              } else {
96                  if (duplicatePduProbability > rng.nextInt()) {
97                      nextFilter.filterWrite(session, writeRequest);
98                  }
99                  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, IoSession session,
114             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, IoBuffer buffer) {
132         if (insertByteProbability > rng.nextInt(1000)) {
133             logger.info(buffer.getHexDump());
134             // where to insert bytes ?
135             int pos = rng.nextInt(buffer.remaining()) - 1;
136 
137             // how many byte to insert ?
138             int count = rng.nextInt(maxInsertByte-1)+1;
139 
140             IoBuffer newBuff = IoBuffer.allocate(buffer.remaining() + count);
141             for (int i = 0; i < pos; i++)
142                 newBuff.put(buffer.get());
143             for (int i = 0; i < count; i++) {
144                 newBuff.put((byte) (rng.nextInt(256)));
145             }
146             while (buffer.remaining() > 0) {
147                 newBuff.put(buffer.get());
148             }
149             newBuff.flip();
150 
151             logger.info("Inserted " + count + " bytes.");
152             logger.info(newBuff.getHexDump());
153             return newBuff;
154         }
155         return null;
156     }
157 
158     private void manipulateIoBuffer(IoSession session, IoBuffer buffer) {
159         if (removeByteProbability > rng.nextInt(1000)) {
160             logger.info(buffer.getHexDump());
161             // where to remove bytes ?
162             int pos = rng.nextInt(buffer.remaining());
163             // how many byte to remove ?
164             int count = rng.nextInt(buffer.remaining() - pos) + 1;
165             if (count == buffer.remaining())
166                 count = buffer.remaining() - 1;
167 
168             IoBuffer newBuff = IoBuffer.allocate(buffer.remaining() - count);
169             for (int i = 0; i < pos; i++)
170                 newBuff.put(buffer.get());
171 
172             buffer.skip(count); // hole
173             while (newBuff.remaining() > 0)
174                 newBuff.put(buffer.get());
175             newBuff.flip();
176             // copy the new buffer in the old one
177             buffer.rewind();
178             buffer.put(newBuff);
179             buffer.flip();
180             logger.info("Removed " + count + " bytes at position " + pos + ".");
181             logger.info(buffer.getHexDump());
182         }
183         if (changeByteProbability > rng.nextInt(1000)) {
184             logger.info(buffer.getHexDump());
185             // how many byte to change ?
186             int count = rng.nextInt(buffer.remaining() - 1) + 1;
187 
188             byte[] values = new byte[count];
189             rng.nextBytes(values);
190             for (int i = 0; i < values.length; i++) {
191                 int pos = rng.nextInt(buffer.remaining());
192                 buffer.put(pos, values[i]);
193             }
194             logger.info("Modified " + count + " bytes.");
195             logger.info(buffer.getHexDump());
196         }
197     }
198 
199     public int getChangeByteProbability() {
200         return changeByteProbability;
201     }
202     
203     /**
204      * Set the probability for the change byte error.
205      * If this probability is > 0 the filter will modify a random number of byte
206      * of the processed {@link IoBuffer}.
207      * @param changeByteProbability probability of modifying an IoBuffer out of 1000 processed {@link IoBuffer} 
208      */
209     public void setChangeByteProbability(int changeByteProbability) {
210         this.changeByteProbability = changeByteProbability;
211     }
212 
213     public int getDuplicatePduProbability() {
214         return duplicatePduProbability;
215     }
216     
217 	/**
218 	 * not functional ATM
219 	 * @param duplicatePduProbability
220 	 */
221     public void setDuplicatePduProbability(int duplicatePduProbability) {
222         this.duplicatePduProbability = duplicatePduProbability;
223     }
224 
225     public int getInsertByteProbability() {
226         return insertByteProbability;
227     }
228 
229     /**
230      * Set the probability for the insert byte error.
231      * If this probability is > 0 the filter will insert a random number of byte
232      * in the processed {@link IoBuffer}.
233      * @param changeByteProbability probability of inserting in IoBuffer out of 1000 processed {@link IoBuffer} 
234      */
235     public void setInsertByteProbability(int insertByteProbability) {
236         this.insertByteProbability = insertByteProbability;
237     }
238 
239     public boolean isManipulateReads() {
240         return manipulateReads;
241     }
242 
243     /**
244      * Set to true if you want to apply error to the read {@link IoBuffer}
245      * @param manipulateReads
246      */
247     public void setManipulateReads(boolean manipulateReads) {
248         this.manipulateReads = manipulateReads;
249     }
250 
251     public boolean isManipulateWrites() {
252         return manipulateWrites;
253     }
254 
255     /**
256      * Set to true if you want to apply error to the written {@link IoBuffer}
257      * @param manipulateWrites
258      */
259     public void setManipulateWrites(boolean manipulateWrites) {
260         this.manipulateWrites = manipulateWrites;
261     }
262 
263     public int getRemoveByteProbability() {
264         return removeByteProbability;
265     }
266 
267     /**
268      * Set the probability for the remove byte error.
269      * If this probability is > 0 the filter will remove a random number of byte
270      * in the processed {@link IoBuffer}.
271      * @param changeByteProbability probability of modifying an {@link IoBuffer} out of 1000 processed IoBuffer 
272      */
273     public void setRemoveByteProbability(int removeByteProbability) {
274         this.removeByteProbability = removeByteProbability;
275     }
276 
277     public int getRemovePduProbability() {
278         return removePduProbability;
279     }
280 
281     /**
282      * not functional ATM
283      * @param removePduProbability
284      */
285     public void setRemovePduProbability(int removePduProbability) {
286         this.removePduProbability = removePduProbability;
287     }
288 
289     public int getResendPduLasterProbability() {
290         return resendPduLasterProbability;
291     }
292 	/**
293 	 * not functional ATM
294 	 * @param resendPduLasterProbability
295 	 */
296     public void setResendPduLasterProbability(int resendPduLasterProbability) {
297         this.resendPduLasterProbability = resendPduLasterProbability;
298     }
299 
300     public int getMaxInsertByte() {
301         return maxInsertByte;
302     }
303 
304     /**
305      * Set the maximum number of byte the filter can insert in a {@link IoBuffer}.
306      * The default value is 10.
307      * @param maxInsertByte maximum bytes inserted in a {@link IoBuffer} 
308      */
309     public void setMaxInsertByte(int maxInsertByte) {
310         this.maxInsertByte = maxInsertByte;
311     }
312 }