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