Exception handling multiple messages inside Buffer [JAVA-Mina] - java

---EDIT below
I'm actually implementing the Mina ProtocolCodecFilter in order to receive messages from a serial device.
The codec specifies multiple different messages (with their pojos), and even thou the implementation works correctly 99% of the time, I'm getting issues with one type of message: the only message that doesn't have a fixed length. I can know the minimum length, but never the maximum.
This is the exception message I'm receiving (just the important parts):
org.apache.mina.filter.codec.ProtocolDecoderException: org.apache.mina.core.buffer.BufferDataException: dataLength: -2143812863 (Hexdump: 02 01 A2 02 01 A0 02)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:25
...
Caused by: org.apache.mina.core.buffer.BufferDataException: dataLength: -2143812863
at org.apache.mina.core.buffer.AbstractIoBuffer.prefixedDataAvailable(AbstractIoBuffer.java:2058)
at my.codec.in.folder.codec.MAFrameDecoder.doDecode(MAFrameDecoder.java:29)
at org.apache.mina.filter.codec.CumulativeProtocolDecoder.decode(CumulativeProtocolDecoder.java:178)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:241)
Sometimes the dataLength is negative, sometimes positive (didn't find any clue about the cause of this).
The MAFrameDecoder:29 is the second sentence of my implementation of the CumulativeProtocolDecoder's doDecode() method (MAX_SIZE=4096):
public boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception
{
boolean result=false;
if(in.prefixedDataAvailable(4, MAX_SIZE)) //-->This is line 29
{
int length = in.getInt();
byte[] idAndData = new byte[length];
in.get(idAndData);
//do things, read from buffer, create message, out.write, etc
//if all has been correct, result=true
}
return result;
}
While debugging the error through a TCP sniffer, we figured out that the exception was thrown when multiple messages where inserted in the same IoBuffer (in).
Seems like my Decoder simply cannot handle multiple messages inside the same buffer. But as I told before, there's also the non-fixed length message issue ( which I really can't know if it has some relevance ). In other doDecode implementations I've seen another methods to manage the buffer, such as:
while (in.hasRemaining())
or
InputStream is=in.asInputStream();
Anyway, I'm trying to avoid blind steps, so this is why I'm asking this here. Instead of just fixing the error, I would like to know the reason of it.
Hope you can help me, any advice would be really appreciated. : )
p.s: The encoder that sends me the messages through the buffer has its autoExpand parameter in false.
EDIT 10/11/2014
I've been exploring the AbstractIoBuffer method and found out this:
#Override
public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
if (remaining() < prefixLength) {
return false;
}
int dataLength;
switch (prefixLength) {
case 1:
dataLength = getUnsigned(position());
break;
case 2:
dataLength = getUnsignedShort(position());
break;
case 4:
dataLength = getInt(position());
break;
default:
throw new IllegalArgumentException("prefixLength: " + prefixLength);
}
if (dataLength < 0 || dataLength > maxDataLength) {
throw new BufferDataException("dataLength: " + dataLength);
}
return remaining() - prefixLength >= dataLength;
}
The prefixLength I'm sending is 4, so the switch enters on the last valid case:
dataLength = getInt(position());
After that, it throws the BufferDataException with the negative dataLength, which means the AbstractIoBuffer's position() method is returning a negative value.
I always thought that a nioBuffer could never hold a negative value on its position parameter. Any clues of why is this happening?

I think you should try first reading the size of the packet you have to decode, and ensuring you have enough bytes remaining in the buffer for the decoding to complete successfully.
If there aren't enough bytes you should return false, so the cumulative protocol decoder can get more data for you.
Be careful to return the buffer to the appropriate position before returning the buffer, otherwise you will lose the length data for the next iteration. (If you are using 4 bytes for the length you should be rewinding 4 bytes).
Edit: You could actually use the mark() and reset() methods of the IoBuffer to achieve this behaviour

Related

How can I get the byte array value returned from a bluetooth incoming message and edit it before displaying it on the other device?

So I asked this question a few days ago, but maybe I can elaborate a bit more, or in a different way now. I am a big java and android newbie, so it takes a lot of time to figure stuff out for me. I have a Bluetooth connecting between 2 devices. I tried using sensors and everything works fine. The devices connect and they send sensor values to one another.
This sensor value, however, is auto-generated. What I want is to get DB values from one of the devices, convert them to bytes, add them to a byte array and send this byte array as a single message to the other device, where it is going to reverse the process. I have everything set up, everything is as it should be with only 1 exception - I need to somehow catch the incomingMessage as a byte array, so I can finish the process.
How can I get the value of the incomingMessage(which is supposed to be transferring a byte array) and add it to another byte array that I am then "decoding"?
The commented out one is the example that I tried and was working.
if (mBluetoothConnection.incomingMessage != null) {
//messageTemp = mBluetoothConnection.incomingMessage;
msg = mBluetoothConnection.incomingMessage;
}
The one that is not commented out is the one, whose value I want to assign to a byte array:
byte[] array = msg;
This is the only thing that I have not been able to figure out so far.
My current issue is that "array" returns null object reference.
Please, help me! I feel like I have almost connected 2 bridges and the paint on each differest by just a centimeter from being okay.
Alright, I managed to figure it out, but forgot to update, here is my other post with a little bit more code:
How can I assing the value of an incoming Bluetooth message to a byte array which I want to decode into integers?
Here's what I changed:
I only touched the run() method in my BluetoothConnectionService
Instead of using the byte[] buffer, as I mention in the commented code, I declared a public static byte[] incomingBytes and gave it a size of 44, since this is what my 11 integer array going to need. Then I just replaced the "buffer" with "incomingBytes" in the example code, and looks like this:
public static byte[] incomingBytes = new byte[44];
public void run(){
//byte [] buffer replaced with incomingBytes
byte[] buffer = new byte[44]; // this was in the example, but it is not used. It was replaced by incomingBytes, declared at the start of the class
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(incomingBytes);
incomingMessage = new String(incomingBytes, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
} catch (IOException e) {
Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage() );
break;
}
}
}
Then I only need to call incomingBytes for my convertion in the other class and it works fine.

Input shouldnt exceed xxx KB

im solving some questions in java and i come across this line in the question... " The total size of the input doesn't exceed 300 KB" , " The total size of the input doesn't exceed 256 KB"
my doubt is how can i make sure that my input is less than that value.
i actually tried using
CountingInputStream (CountingInputStream input = new CountingInputStream(System.in);)
to validate it. this is an external jar file by Google.
but when i submit my solution in the online compilers, CountingInputStream is not taken by the compiler. so how do i do it without using this ?.. in a general way ?
CountingInputStream input = new CountingInputStream(System.in);
System.out.println("Enter Values: ");
while (scanner.hasNext() && input.getCount() < (256 * 1024))
this is now im doing ...but is there a way where i can control my input without using CountingInputStream. Kindly help
Write your own class that decorates an InputStream, overriding the read method to count bytes and then throw an exception when the number of bytes exceeds some threshold. Your driver could look like this:
InputStream in = new ByteLimiterInputStream(new FileInputStream("file.bin"));
while(...)
in.read();
This will throw an exception when you've read too much data. It's up to you to write the ByteLimiterInputStream class. This is an academic exercise after all: exercise your own brain and don't ask others for the answers.
Use an InputStream, call the read() method, and increment a counter.
read() will return a single byte, or -1 at end of stream.
e.g.
int MAX = 256 * 1024;
int count = 0;
while (true) {
int return = is.read();
if (return == -1) break;
if (++count >= MAX) {
// maximum limit reached
} else {
// store the byte somewhere, do something with it...
}
}

Strcture data communication between Java and C socket programming

I have a Java socket channel and I'm sending a object data and receiving it in C socket ..
Java Code::
//structure
class data
{
public String jobtype;
public String budget;
public String time ;
}
//creating a Socket Channel and sending data through it in java
Selector incomingMessageSelector = Selector.open();
SocketChannel sChannel = SocketChannel.open();
sChannel.configureBlocking(false);
sChannel.connect(new InetSocketAddress("localhost", 5000));
sChannel.register(incomingMessageSelector, SelectionKey.OP_CONNECT);
if(sChannel.finishConnect()==true)
{
sChannel.register(incomingMessageSelector, SelectionKey.OP_WRITE);
}
int len = 256;
ByteBuffer buf = ByteBuffer.allocate(len);
buf.putInt(len);
// Writing object of data in socket
buf.put(obj.jobtype.getBytes("US-ASCII"));
buf.put(obj.budget.getBytes("US-ASCII"));
buf.put(obj.time.getBytes("US-ASCII"));
buf.put((byte) 0);
buf.flip();
sChannel.write(buf);
C Code ::
struct data
{
char time[50];
char jobtype[50];
char budget[50];
};
n = read(newsockfd, &size, sizeof(size));
struct data *result = malloc(size);
n = read(newsockfd, result, size);
printf("\njobtype :: %s\nbudget :: %s\ntime :: %s\n",result->jobtype,result->budget,result->time);
After giving input in Java as:
jobtype = h1
budget = 20
time = 12
I'm getting these output in C:
jobtype ::
budget ::
time :: h1
The buffer which you are sending from Java to C needs to have exactly the same definition (from a byte point of view) in both languages. In your code that is not the case. The buffer you construct in Java does not have the same format as the struct you are using in C to interpret that buffer. Both the length of the strings and order of the strings do not match between sender (Java) and receiver (C). In addition, the size of the buffer sent does not match the size of the buffer expected based on the length information sent (i.e. you are not sending the correct length of your buffer).
In C you have defined a structure that is 150 bytes long containing 3 char arrays (strings), each 50 bytes long. With the order: time, jobtype, budget
In Java you have created a buffer of variable length with strings of variable length in the order: jobtype, budget, time. Fundamentally, the Java code is creating a variable length buffer where the C code is expecting to map this to a fixed length structure.
While it is not what you desire, your C program is obtaining the jobtype string which you placed first in the buffer and assigns it to time. This is how it is currently written.
Assuming that you leave the C program the same, the portion of your Java code which creates and fills the buffer could look something like:
public ByteBuffer createFixedLengthCString(String src, int len) {
//If the string is longer than len-1 it is truncated.
ByteBuffer cString = ByteBuffer.allocate(len);
if(src.length() > len - 1) {
//Using len-1 prevents the last 0 in the ByteBuffer from being
// overwritten. A final 0 is needed:C uses null (0) terminated strings.
cString.put(src.getBytes("US-ASCII"), 0, len-1);
} else {
//The string is not longer than the maximum length.
cString.put(src.getBytes("US-ASCII"));
}
//Already have null termination. Do not want to flip (would change length).
//Reset the position to 0.
cString.position(0);
return cString;
}
int maxBufLen = 256;
int payloadLen = 150
int cStringLen = 50;
ByteBuffer buf = ByteBuffer.allocate(maxBufLen);
//Tell C that the payload is 150 bytes long.
buf.putInt(payloadLen);
// Writing object data in the buffer
buf.put(createFixedLengthCString(obj.time, cStringLen));
buf.put(createFixedLengthCString(obj.jobtype, cStringLen));
buf.put(createFixedLengthCString(obj.budget, cStringLen));
//Use flip() here as it changes the length of bytes sent to the correct
// number (an int plus 150) and sets the position to 0, ready for reading.
buf.flip();
while(buf.hasRemaining()) {
//There is the possibility that a single call to write() will not
// write the entire buffer. Thus, loop until all data is written.
//There should be other conditions which cause us to break out of
// this loop (e.g. a maximum number of write attempts). Without such,
// if the channel is hung this is code will hang in this loop; effectively
// a blocking (for this code) write loop.
sChannel.write(buf);
}
This answer is only intended to address the specific malfunction you have identified in the question. However, the code as presented is really only appropriate as an example/test of transmitting limited data from one process to another on the same machine. Even for that there should be exception and error handling which is not included here.
As EJP implied in his comment, it is often better/easier to use already existing protocols when communicating over a bit pipe. These protocols are designed to address many different issues which can become relevant, even in simple inter-process communications.

Remove junk trailing xml from an inputstream

My free webhost appends analytics javascript to all PHP and HTML files. Which is fine, except that I want to send XML to my Android app, and it's invalidating my files.
Since XML is parsed in its entirety (and blows up) before passed along to my SAX ContentHandler, I can't just catch the exception and continue merrily along with a fleshed out object. (Which I tried, and then felt sheepish about.)
Any suggestions on a reasonably efficient strategy?
I'm about to create a class that will take my InputStream, read through it until I find the junk, break, then take what I just wrote to, convert it back into an InputStream and pass it along like nothing happened. But I'm worried that it'll be grossly inefficient, have bugs I shouldn't have to deal with (e.g. breaking on binary values such as embedded images) and hopefully unnecessary.
FWIW, this is part of an Android project, so I'm using the android.util.Xml class (see source code). When I traced the exception, it took me to a native appendChars function that is itself being called from a network of private methods anyway, so subclassing anything seems to be unreasonably useless.
Here's the salient bit from my stacktrace:
E/AndroidRuntime( 678): Caused by: org.apache.harmony.xml.ExpatParser$ParseException: At line 3, column 0: junk after document element
E/AndroidRuntime( 678): at org.apache.harmony.xml.ExpatParser.parseFragment(ExpatParser.java:523)
E/AndroidRuntime( 678): at org.apache.harmony.xml.ExpatParser.parseDocument(ExpatParser.java:482)
E/AndroidRuntime( 678): at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:320)
E/AndroidRuntime( 678): at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:277)
I guess in the end I'm asking for opinions on whether the InputStream -> manually parse to OutputStream -> recreate InputStream -> pass along solution is as horrible as I think it is.
I'm about to create a class that will take my InputStream, read
through it until I find the junk, break, then take what I just wrote
to, convert it back into an InputStream and pass it along like nothing
happened. But I'm worried that it'll be grossly inefficient, have bugs
I shouldn't have to deal with (e.g. breaking on binary values such as
embedded images) and hopefully unnecessary.
you could use a FilterStream for that no need for a buffer
best thing to do is add a delimiter to the end of the XML like --theXML ends HERE -- or a char not found in XML like a group of 16 \u04 chars (you then only need to check every 16th byte) to the end of the XML and read until you find it
implementation assuming \u04 delim
class WebStream extends FilterInputStream {
byte[] buff = new byte[1024];
int offset = 0, length = 0;
public WebStream(InputStream i) {
super(i);
}
#Override
public boolean markSupported() {
return false;
}
#Override
public int read() throws IOException {
if (offset == length)
readNextChunk();
if (length == -1)
return -1;// eof
return buff[offset++];
}
#Override
public int read(byte[] b, int off, int len) throws IOException {
if (offset == length)
readNextChunk();
if (length == -1)
return -1;// eof
int cop = length - offset;
if (len < cop)
cop = len;
System.arraycopy(buff, offset, b, off, cop);
offset += cop;
return cop;
}
private void readNextChunk() throws IOException {
if (offset <= length) {
System.arraycopy(buff, offset, buff, 0, length - offset);
length -= offset;
offset = 0;
}
int read = in.read(buff, length, buff.length - length);
if (read < 0 && length <= 0) {
length = -1;
offset = 0;
return;
}
// note that this is assuming ascii compatible
// anything like utf16 or utf32 will break here
for (int i = length; i < read + length; i += 16) {
if (buff[i] == 0x04) {
while (buff[--i] == 0x04)
;// find beginning of delim block
length = i;
read = 0;
}
}
}
}
note this misses throws, some error checking and needs proper debugging
"I'm about to create a class that will take my InputStream, read through it until I find the junk, break, then take what I just wrote to, convert it back into an InputStream and pass it along like nothing happened. But I'm worried that it'll be grossly inefficient, have bugs I shouldn't have to deal with (e.g. breaking on binary values such as embedded images) and hopefully unnecessary."
That'll work. You can read into a StringBuffer and then use a ByteArrayInputStream or something similar (like StreamReader if that's applicable).
http://developer.android.com/reference/java/io/ByteArrayInputStream.html
The downside is that you're reading in the entire XML file into memory, for large files, it can be inefficient memory-wise.
Alternatively, you can subclass InputStream and do the filtering out via the stream. You'd probably just need to override the 3 read() methods by calling super.read() and flagging when you've gotten to the garbage at the end and return an EOF as needed.
Free webhost have this issue. I'm still yet to find an alternative still in free mode.

Are there any parallel issues with Integer.MAX_VALUE

I have the following code:
if (maxLength>=0 && (++totalLength > maxLength))
throw new IllegalStateException("Form too large");
in a loop where bytes are read from byte array input stream. The maxLength is set to Integer.MAX_VALUE so I think that the condition could never be true (and I'm not talking about the size of the byte array in input stream which I'm absolutely sure is not long enough). But I get the IllegalStateException thrown from that line!!! Now the real bummer is that when I put a breakpoint on that throw line, everything is ok. How the hell is this possible?
EDIT:
both variables are of type int
totalLength is a local variable, maxLength is a parameter
the debugger don't stop there AND the exception is not thrown at all, when there is a breakpoint on that throw line.
I actualy don't know why I'm suspecting parallelism, it's just because it's web application
I admit that using MAX_VALUE is very risky (in the next step I will try to decrease this limit), but I would expect some other execption than that in the success branch of if statement. And moreover that byte array used in input stream is really not long enough. This should be plainly impossible situation in JVM:-).
The code above is in jetty-util-7.1.5.v20100705.jar in the class UrlEncoded and I'm using it by calling
byte[] decodedBytes;
byte[] encodedBytes;
// v pripade url encoded requestu je potreba pouze odriznout
// jmeno falesneho parametru nesouciho kodovany blok
encodedBytes = Arrays.copyOfRange(content, "encdata=".length(), content.length);
decodedBytes = decodeBytes(request, encodedBytes);
// priprav desifrovany text jako vstupni proud
decodedInputStream = new ByteArrayInputStream(decodedBytes);
// pokud je request url encoded je potreba jej manualne parsovat
// pro potreby funkci vracejicich parametry
UrlEncoded.decodeTo(decodedInputStream, parameters, request.getCharacterEncoding(), Integer.MAX_VALUE);
Are there any parallel issues with Integer.MAX_VALUE
No, this is most likely not due to any race-conditions (unless you have other threads modifying maxLength or so).
According to the JLS on integer is larger than Integer.MAX_VALUE so this is either due to a bug in your VM or based on the false assumption that maxLength is indeed Integer.MAX_VALUE.
The maxLength is set to Integer.MAX_VALUE so I think that the condition could never be true
Make sure totalLength is not a long.
(The snippet below always throws the exception.)
int maxLength = Integer.MAX_VALUE;
long totalLength = 2147483647;
if (maxLength>=0 && (++totalLength > maxLength))
throw new IllegalStateException("Form too large");
If it's not reproducible with the debugger, just give a more informative error message to the exception, for instance: "Form too large: " + totalLength + " is larger than " + maxLength
Are you sure you want to increment totalLength before the comparison, rather than after? If your totalLength going into that statement is equal to maxLength, the exception will be thrown... is that a possible scenario?
Try totalLength++ instead.
Just a thought. Hope this helps.
Now the real bummer is that when I put a breakpoint on that throw line, everything is ok
Do you mean the debugger doesn't stop there?
From your question title it seems you suspect a racing condition (multithreading) issue.
How are the variables defined?
Could you post some more code?
Could maxLength be modified elsewhere? Or is it final?

Categories