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   */
55  public class ErrorGeneratingFilter extends IoFilterAdapter {
56      private int removeByteProbability = 0;
57  
58      private int insertByteProbability = 0;
59  
60      private int changeByteProbability = 0;
61  
62      private int removePduProbability = 0;
63  
64      private int duplicatePduProbability = 0;
65  
66      private int resendPduLasterProbability = 0;
67  
68      private int maxInsertByte = 10;
69  
70      private boolean manipulateWrites = false;
71  
72      private boolean manipulateReads = false;
73  
74      private Random rng = new Random();
75  
76      final private Logger logger = LoggerFactory
77              .getLogger(ErrorGeneratingFilter.class);
78  
79      @Override
80      public void filterWrite(NextFilter nextFilter, IoSession session,
81              WriteRequest writeRequest) throws Exception {
82          if (manipulateWrites) {
83              // manipulate bytes
84              if (writeRequest.getMessage() instanceof IoBuffer) {
85                  manipulateIoBuffer(session, (IoBuffer) writeRequest
86                          .getMessage());
87                  IoBuffer buffer = insertBytesToNewIoBuffer(session,
88                          (IoBuffer) writeRequest.getMessage());
89                  if (buffer != null) {
90                      writeRequest = new DefaultWriteRequest(buffer, writeRequest
91                              .getFuture(), writeRequest.getDestination());
92                  }
93                  // manipulate PDU
94              } else {
95                  if (duplicatePduProbability > rng.nextInt()) {
96                      nextFilter.filterWrite(session, writeRequest);
97                  }
98                  if (resendPduLasterProbability > rng.nextInt()) {
99                      // store it somewhere and trigger a write execution for
100                     // later
101                     // TODO
102                 }
103                 if (removePduProbability > rng.nextInt()) {
104                     return;
105                 }
106             }
107         }
108         nextFilter.filterWrite(session, writeRequest);
109     }
110 
111     @Override
112     public void messageReceived(NextFilter nextFilter, IoSession session,
113             Object message) throws Exception {
114         if (manipulateReads) {
115             if (message instanceof IoBuffer) {
116                 // manipulate bytes
117                 manipulateIoBuffer(session, (IoBuffer) message);
118                 IoBuffer buffer = insertBytesToNewIoBuffer(session,
119                         (IoBuffer) message);
120                 if (buffer != null) {
121                     message = buffer;
122                 }
123             } else {
124                 // manipulate PDU
125             }
126         }
127         nextFilter.messageReceived(session, message);
128     }
129 
130     private IoBuffer insertBytesToNewIoBuffer(IoSession session, IoBuffer buffer) {
131         if (insertByteProbability > rng.nextInt(1000)) {
132             logger.info(buffer.getHexDump());
133             // where to insert bytes ?
134             int pos = rng.nextInt(buffer.remaining()) - 1;
135 
136             // how many byte to insert ?
137             int count = rng.nextInt(maxInsertByte-1)+1;
138 
139             IoBuffer newBuff = IoBuffer.allocate(buffer.remaining() + count);
140             for (int i = 0; i < pos; i++)
141                 newBuff.put(buffer.get());
142             for (int i = 0; i < count; i++) {
143                 newBuff.put((byte) (rng.nextInt(256)));
144             }
145             while (buffer.remaining() > 0) {
146                 newBuff.put(buffer.get());
147             }
148             newBuff.flip();
149 
150             logger.info("Inserted " + count + " bytes.");
151             logger.info(newBuff.getHexDump());
152             return newBuff;
153         }
154         return null;
155     }
156 
157     private void manipulateIoBuffer(IoSession session, IoBuffer buffer) {
158         if (removeByteProbability > rng.nextInt(1000)) {
159             logger.info(buffer.getHexDump());
160             // where to remove bytes ?
161             int pos = rng.nextInt(buffer.remaining());
162             // how many byte to remove ?
163             int count = rng.nextInt(buffer.remaining() - pos) + 1;
164             if (count == buffer.remaining())
165                 count = buffer.remaining() - 1;
166 
167             IoBuffer newBuff = IoBuffer.allocate(buffer.remaining() - count);
168             for (int i = 0; i < pos; i++)
169                 newBuff.put(buffer.get());
170 
171             buffer.skip(count); // hole
172             while (newBuff.remaining() > 0)
173                 newBuff.put(buffer.get());
174             newBuff.flip();
175             // copy the new buffer in the old one
176             buffer.rewind();
177             buffer.put(newBuff);
178             buffer.flip();
179             logger.info("Removed " + count + " bytes at position " + pos + ".");
180             logger.info(buffer.getHexDump());
181         }
182         if (changeByteProbability > rng.nextInt(1000)) {
183             logger.info(buffer.getHexDump());
184             // how many byte to change ?
185             int count = rng.nextInt(buffer.remaining() - 1) + 1;
186 
187             byte[] values = new byte[count];
188             rng.nextBytes(values);
189             for (int i = 0; i < values.length; i++) {
190                 int pos = rng.nextInt(buffer.remaining());
191                 buffer.put(pos, values[i]);
192             }
193             logger.info("Modified " + count + " bytes.");
194             logger.info(buffer.getHexDump());
195         }
196     }
197 
198     public int getChangeByteProbability() {
199         return changeByteProbability;
200     }
201     
202     /**
203      * Set the probability for the change byte error.
204      * If this probability is > 0 the filter will modify a random number of byte
205      * of the processed {@link IoBuffer}.
206      * @param changeByteProbability probability of modifying an IoBuffer out of 1000 processed {@link IoBuffer} 
207      */
208     public void setChangeByteProbability(int changeByteProbability) {
209         this.changeByteProbability = changeByteProbability;
210     }
211 
212     public int getDuplicatePduProbability() {
213         return duplicatePduProbability;
214     }
215     
216 	/**
217 	 * not functional ATM
218 	 * @param duplicatePduProbability
219 	 */
220     public void setDuplicatePduProbability(int duplicatePduProbability) {
221         this.duplicatePduProbability = duplicatePduProbability;
222     }
223 
224     public int getInsertByteProbability() {
225         return insertByteProbability;
226     }
227 
228     /**
229      * Set the probability for the insert byte error.
230      * If this probability is > 0 the filter will insert a random number of byte
231      * in the processed {@link IoBuffer}.
232      * @param changeByteProbability probability of inserting in IoBuffer out of 1000 processed {@link IoBuffer} 
233      */
234     public void setInsertByteProbability(int insertByteProbability) {
235         this.insertByteProbability = insertByteProbability;
236     }
237 
238     public boolean isManipulateReads() {
239         return manipulateReads;
240     }
241 
242     /**
243      * Set to true if you want to apply error to the read {@link IoBuffer}
244      * @param manipulateReads
245      */
246     public void setManipulateReads(boolean manipulateReads) {
247         this.manipulateReads = manipulateReads;
248     }
249 
250     public boolean isManipulateWrites() {
251         return manipulateWrites;
252     }
253 
254     /**
255      * Set to true if you want to apply error to the written {@link IoBuffer}
256      * @param manipulateWrites
257      */
258     public void setManipulateWrites(boolean manipulateWrites) {
259         this.manipulateWrites = manipulateWrites;
260     }
261 
262     public int getRemoveByteProbability() {
263         return removeByteProbability;
264     }
265 
266     /**
267      * Set the probability for the remove byte error.
268      * If this probability is > 0 the filter will remove a random number of byte
269      * in the processed {@link IoBuffer}.
270      * @param changeByteProbability probability of modifying an {@link IoBuffer} out of 1000 processed IoBuffer 
271      */
272     public void setRemoveByteProbability(int removeByteProbability) {
273         this.removeByteProbability = removeByteProbability;
274     }
275 
276     public int getRemovePduProbability() {
277         return removePduProbability;
278     }
279 
280     /**
281      * not functional ATM
282      * @param removePduProbability
283      */
284     public void setRemovePduProbability(int removePduProbability) {
285         this.removePduProbability = removePduProbability;
286     }
287 
288     public int getResendPduLasterProbability() {
289         return resendPduLasterProbability;
290     }
291 	/**
292 	 * not functional ATM
293 	 * @param resendPduLasterProbability
294 	 */
295     public void setResendPduLasterProbability(int resendPduLasterProbability) {
296         this.resendPduLasterProbability = resendPduLasterProbability;
297     }
298 
299     public int getMaxInsertByte() {
300         return maxInsertByte;
301     }
302 
303     /**
304      * Set the maximum number of byte the filter can insert in a {@link IoBuffer}.
305      * The default value is 10.
306      * @param maxInsertByte maximum bytes inserted in a {@link IoBuffer} 
307      */
308     public void setMaxInsertByte(int maxInsertByte) {
309         this.maxInsertByte = maxInsertByte;
310     }
311 }