11 Replies Latest reply on Feb 17, 2010 3:44 PM by timfox

    IndexOutOfBoundsException when receiving binary messages with Stomp

    mjustin

      Hello,

       

      sending of 100 messages with binary content works fine, the last frame (number 100)  look like this:

       

      SEND
      destination:jms.queue.ExampleQueue
      content-length:9
      correlation-id:{A5823393-DC81-4A5F-A780-8AD9B8022CD1}

       

      ☺ ☻ ♥100

       

      However no messages are received from the client and the server logs an exception. I will take a look at the Stomp sources but maybe the exception gives a hint where to search. The server also is unresponsive after this error happens and needs a restart.

       

       

      java.lang.IndexOutOfBoundsException
              at org.jboss.netty.buffer.AbstractChannelBuffer.checkReadableBytes(Abstr
      actChannelBuffer.java:543)
              at org.jboss.netty.buffer.AbstractChannelBuffer.readBytes(AbstractChanne
      lBuffer.java:292)
              at org.jboss.netty.buffer.AbstractChannelBuffer.readBytes(AbstractChanne
      lBuffer.java:298)
              at org.hornetq.core.buffers.impl.ChannelBufferWrapper.readBytes(ChannelB
      ufferWrapper.java:347)
              at org.hornetq.core.protocol.stomp.StompMarshaller.unmarshal(StompMarsha
      ller.java:171)
              at org.hornetq.core.protocol.stomp.StompProtocolManager.doHandleBuffer(S
      tompProtocolManager.java:155)
              at org.hornetq.core.protocol.stomp.StompProtocolManager.access$000(Stomp
      ProtocolManager.java:51)
              at org.hornetq.core.protocol.stomp.StompProtocolManager$1.run(StompProto
      colManager.java:139)
              at org.hornetq.utils.OrderedExecutorFactory$OrderedExecutor$1.run(Ordere
      dExecutorFactory.java:96)
              at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source
      )
              at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
              at java.lang.Thread.run(Unknown Source)

        • 1. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
          mjustin

          Hello,

           

          I found that the exception occurs if the test data in the BytesMessage contains null bytes. In the StompTest.java unit test for BytesMessages, the test data is an array containing only non-null bytes:

           

          byte[] data = new byte[] {1, 2, 3, 4};

           

          So I modified my test to use the same byte sequence. The send from client to broker seems to work but when the broker sends the message to the client, it fails with an java.lang.NegativeArraySizeException:

           


          java.lang.NegativeArraySizeException
                  at org.hornetq.core.protocol.stomp.StompSession.sendMessage(StompSession
          .java:103)
                  at org.hornetq.core.server.impl.ServerConsumerImpl.deliverStandardMessag
          e(ServerConsumerImpl.java:630)
                  at org.hornetq.core.server.impl.ServerConsumerImpl.handle(ServerConsumer
          Impl.java:257)
                  at org.hornetq.core.server.impl.QueueImpl.handle(QueueImpl.java:1347)
                  at org.hornetq.core.server.impl.QueueImpl.directDeliver(QueueImpl.java:1
          250)
                  at org.hornetq.core.server.impl.QueueImpl.add(QueueImpl.java:1307)
                  at org.hornetq.core.server.impl.QueueImpl.addLast(QueueImpl.java:231)
          ...

           

           

          So it looks like StompSession.java calculates the content length with a bad result:

           

                      int size = serverMessage.getEndOfBodyPosition() - buffer.readerIndex();
                      data = new byte[size];

           


          Can I run the unit tests (StompTest.java) from command line or is it easier from an IDE?

           

          Regards,

          Michael

          • 2. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
            jmesnil

            you can run StompTest from eclipse or from the command line:

             

            ./build.sh integration-tests -Dtest-mask=StompTest

            • 3. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
              mjustin

              Hello Jeff,

               

              null bytes in the test data break the unit test. Test data is:

               

              byte[] data = new byte[] {1, 0, 0, 4};

               

              Running the tests produces this error:

               

              junit.framework.AssertionFailedError
              at  org.hornetq.tests.integration.stomp.StompTest.testSendMessageWithContentLength(StompTest.java:215)

               

              Line 215 is:

              Assert.assertNotNull(message);

               

              This is the same what I can see in the Delphi Stomp client.

               

              So if I understand the source code correctly there is a problem with the Netty read(byte[] data) method when the input stream contains null bytes?

               

              Michael

              • 4. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                jmesnil

                I found the issue.

                 

                I'm using Netty's DelimiterBasedFrameDecoder to "delimit" a Stomp frame. It uses a NUL 0x00 byte as a delimiter.

                However this will not work if you have NUL byte in the Stomp body.

                I'll have to rewrite the decoder to fix this and make sure that if there is a content-length header, we read all the length

                before creating the frame.

                • 5. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                  timfox

                  Best to use the

                   

                  public int isReadyToHandle(HornetQBuffer buffer);
                    
                  void handleBuffer(RemotingConnection connection, HornetQBuffer buffer);

                   

                  Methods on protocol manager to do this, instead of writing another framedecoder

                  • 6. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                    jmesnil

                    timfox wrote:

                     

                    Best to use the

                     

                    public int isReadyToHandle(HornetQBuffer buffer);
                      
                    void handleBuffer(RemotingConnection connection, HornetQBuffer buffer);

                     

                    Methods on protocol manager to do this, instead of writing another framedecoder

                    that was my 1st idea but in this case, it will not be simple or efficient.

                     

                    I need to decode the buffer as it goes to be able to check if it has a "content-length" header or not.

                    If it has one, I know how many other bytes I need before handling the buffer.

                    Otherwise, I'll continue to read it until I encounter the first NUL byte.

                    I'll have decoded almost all the frame to know if I can handle it.

                     

                    At this point, it'd be simpler to work with the decoded frame and pass it directly to the StompProtocolManager rather

                    than use a HornetQBuffer with all the needed bytes and decode it a 2nd time.


                    • 7. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                      timfox

                      Why would it be less efficient?

                       

                      You have to read the buffer anyway to see if it's ready.

                       

                      I don't follow your logic here

                      • 8. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                        timfox

                        You have to write the decoding logic *anyway*, the question is whether that logic is in a FrameDecoder or in the ProtocolManager.

                         

                        It's cleaner to put it in the ProtocolManager since then all the protocol specific code is in one place.

                        • 9. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                          jmesnil

                          My point was that using HornetQFrameDecoder, I'd have to decode the Frame twice in the ProtocolManager:

                           

                             public int isReadyToHandle(HornetQBuffer buffer)
                             {
                                // decode almost all the frames to know its length
                                return length;
                             }
                          
                             public void handleBuffer(final RemotingConnection connection, final HornetQBuffer buffer)
                             {
                                // decode completely the frame a 2nd time 
                                StompFrame frame = decode(buffer);
                                // work with the frame
                             }
                          
                          • 10. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                            timfox
                            I'm still not with you, why would you need to decode the frame twice?
                            • 11. Re: IndexOutOfBoundsException when receiving binary messages with Stomp
                              timfox

                              Probably a better way to ask this question, is how would you write a FrameDecoder to do what you require?

                               

                              BTW, this discussion should be on the dev forum