Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
New Developer
Posts: 9
Registered: ‎04-29-2009
My Device: Not Specified

Problem with SecureConnection

Hi guys and girls,

 

I'm trying to receive data over a connection that can optionally have SSL enabled by the user, so my code should work with or without SSL.  Sounds pretty simple, but it seems that when I'm not using SSL (on the simulator, or on a device both), the code is working, when I'm using SSL, it's not. The only difference in the code is that for SSL I'm using a SecureConnection, for non-SSL I'm using a SocketConnection.

 

DataInputStream is;

DataOutputStream os;

SocketConnection con;

String url;

boolean connected;

 

 try {

    String url;

    if (useSSL) {

        url = "ssl://" + session.getHostName() + ":" + session.getPort() + ";deviceside=true";

        con = (SecureConnection)Connector.open(url);

    }

    else {

        url = "socket://" + session.getHostName() + ":" + session.getPort() + ";deviceside=true";

        con = (SocketConnection)Connector.open(url);

    }

 

    os =
con.openDataOutputStream();is = con.openDataInputStream();

    connected = true;

 

    final IntVector iv = new IntVector();

    while (connected) {

        iv.removeAllElements();

        // check for incoming data, read it, and process it

        int av = is.available();

        for (int i = 0; i < av; ++i)

            iv.addElement(is.read());

 

        if (iv.size() > 0) {

            UiApplication.getUiApplication().invokeAndWait(new Runnable() {

                public void run() {

                    // process this data in main thread

                }

            }

        );

    }

 

    try { Thread.sleep(100); } catch (InterruptedException ex) { /* do nothing */ }

 

    // check here for outgoing data and send it ...

 

}

catch (....)

 

It appears that the 'available()' method of the DataInputStream class always returns 0 if the connection is a SecureConnection, though it works fine when the connection is a SocketConnection.

 

I know that there are three bytes of data available after the connection has been made, yet 'available' returns 0.  If I take the 'available' call out and just read one byte (or int) at a time, then the first three calls return the data, the fourth one blocks.  If I now send some data, the host responds, but the blocking call still doesn't continue, so I don't see how I can use that either.

 

Am I doing this wrong?  Is there a bug in the 'available' method?  Is there a better way to do this?  I have looked at the samples, and searched the web, but all I can find follows the old 'connect - send - receive - disconnect' scheme.  I have to stay connected, and I have to listen for the host to send data, and at the same time be ready to send data as well.

 

Thanks for reading. Any help would be greatly appreciated.

Mike 

 

Developer
Posts: 132
Registered: ‎02-11-2009
My Device: Not Specified

Re: Problem with SecureConnection

I've seen this too. InputStream.available() simply doesn't work with ssl connection (and I'm tempted to say it doesn't work so well with regular socket connections either). Don't use it.

 

InputStream.read(byte[]) will read as many bytes as the stream has (up to the size of the array) and it will only block when the stream (really) has no bytes. AFAIK, there's no way to test will-it-block? If you're at risk of blocking, spawn another thread to implement a timeout.

 

Cheers, Barak.

New Developer
Posts: 9
Registered: ‎04-29-2009
My Device: Not Specified

Re: Problem with SecureConnection

Thank you for your suggestion, Barak, nice to know I'm not the only one.

 

So if I understand this correctly, I'd have to do it this way:

// inside a new thread

is.read(byte[])  ===> reads avail. data, or blocks if no data available

// process the incoming data

is.read(byte[])  ===> if no data, this will block forever, even if data is available later?

That does seem like a strange way of doing things.  Since the 'read' call would be blocking, the thread would effectively be locked, and you'd have to kill it and create a new one each time you want to check for available data, which would be at least once every second.  Last time I tried that I was getting a 'maximum number of threads exceeded' error, but I'm sure I messed up there. I'll try it again.

 

Would be nice if RIM would fix their API so that it at least works as advertised :smileywink:

 

Thanks, Mike.

Developer
Posts: 132
Registered: ‎02-11-2009
My Device: Not Specified

Re: Problem with SecureConnection

is.read(byte[]) block until data becomes available, not forever.

 

You won't need to code anything special in order to check every N seconds. Just leave a thread blocked on read, and it will spring back to life when data comes in.

 

New Developer
Posts: 9
Registered: ‎04-29-2009
My Device: Not Specified

Re: Problem with SecureConnection

I have never used the is.read(byte[]) method. I seem to remember that 'is.read() : int' was supposed to behave like you describe, but (at least for me) it didn't. It would block indefinitely even after data became available again.  I will give your suggestion a try.

 

Thanks again,

Mike

Developer
Posts: 1,474
Registered: ‎04-14-2009
My Device: Not Specified

Re: Problem with SecureConnection

Standard Java SSLSocket's InputStream.available() also returns 0 always. This is because with stream-oriented SSL it is impossible to know, without blocking, how much data can be read without blocking. As the contract of the available() method is that the method does not block and that it tells how much data can be read without blocking, then it actually makes sense.
New Developer
Posts: 9
Registered: ‎04-29-2009
My Device: Not Specified

Re: Problem with SecureConnection

Ok, so I've stopped using 'available()' method, and changed my code to this (connection and opening streams omitted for brevity, incoming and outgoing reader and writer are in separate threads):

 

private byte[] in = new byte[1000];
while (this.connected) {
int read = is.read(in, 0, 10);
if (read == -1) { // end of stream, connection closed?
connected = false;
}
else {

// process data

}

 

try { Thread.sleep(100); }
catch (InterruptedException ex) { /* do nothing */ }
}
is.close();
os.close();
con.close();

 

The problem with that is:

 

1. if the above code runs immediately after the connection has been established, there is no data available on the first call to is.read(). When, about 100ms later, data becomes available, the call does not 'unblock'.

 

2. if I put in a short wait period before calling read(byte[], int, int) for the first time, to make certain that data is available (in my case there are 3 bytes), the above still blocks. I have to change that to 'is.read(in, 0, 3)', in which case the three incoming bytes are actually read.  Since then 'read' is called again, it blocks again (and no, more incoming data does not unblock the thread). So basically the 'read' method behaves as the docs describe the 'readFully' method should behave.

 

So the read call, contrary to the docs, does not 'Read up to len bytes of data from this input stream into an array of bytes'. I seem to have to call it with 'len' set to the exact amount of data available on the stream, or a lower number. I can only find out the available data by using 'available', which I can't use with SSL, or I could use '1'.

 

I have used '1' for the 'len' parameter, which is the same as simply using 'read()' (which I've also tried). But now I'm back to the original problem: with 3 bytes available, I call 'read()' three times and get the data, and the fourth call blocks, no matter how much more data is becoming available later.  When I close the connection, the call unblocks,and returns the data that is waiting on the stream, but not before.

 

It seems I can only read incoming data if I know how much data is available on the stream. My original code works perfectly (without SSL), using 'available()' followed by 'read(byte[], int, int)'.

 

It must be possible to do this, and I'm sure I'm just missing something (or just being dense), but I can't see how. All the examples I can find either use 'available()', or they do HTTP.

 

Thanks, Mike

 

 

Developer
Posts: 1,474
Registered: ‎04-14-2009
My Device: Not Specified

Re: Problem with SecureConnection

When you say that more than 3 bytes become available, how do you know that? Have you had a look at the network sniffer output for the receiving end? The scenario you're describing sounds like the remote endpoint isn't actually explicitly flushing after its writes and only when it closes the connection is the flush (automatically) invoked and you receive all the data that the remote endpoint had buffered for output.
New Developer
Posts: 9
Registered: ‎04-29-2009
My Device: Not Specified

Re: Problem with SecureConnection

klyubin:

Thanks for the reply.  Yes, I have used Wireshark to verify that data is indeed available on the connection. This is a telnet server I'm connecting to, and the server is sending three bytes to the client to start the telnet negotiation.  A different server may be sending more, but never less.

 

Also, I can see that the data is there, by calling 'read()' three times. I get the data that I'm expecting, but I don't know if there is more data available. If I call 'read()' again, the call blocks.  I have tried sending my reply to the host at that time (which works), and the host is responding to that (verified with sniffer), but the 'read()' call continues to block, even though there is now data available. So in my opinion, the only way to continue at this point is to kill the thread that contains the blocking 'read()' call, then start a new one with a new 'read()'. But if there is no data available, I would be continuously starting and killing threads just to wait for incoming data, which doesn't seem right.

 

I have tried this with multiple hosts, and it seems to work (or not work) the same with all of them.

 

Thanks, Mike

Developer
Posts: 1,474
Registered: ‎04-14-2009
My Device: Not Specified

Re: Problem with SecureConnection

[ Edited ]

 

That's really weird (I've dealt with SSL connections on BlackBerry many times and I've never had any problems like the one you describe). Sorry for being a nag, but how do you know in Wireshark that a specific number of plaintext bytes (say exactly 3) are available when you actually eavesdrop on an end-to-end secured SSL connection where you only see the ciphertext? Have you tried connecting to the same SSL-secured port on the same server but via stunnel + NetCat (nc) combo?

 

P.S. Try using streams returned by openInputStream and openOutputStream instead of openDataInputStream/openDataOutputStream just to see whether it makes a difference (although it shouldn't).

 

 

P.P.S. Also, try opening the connection in read+write mode and with connection and read timeouts enabled ( Connector.open(url, Connector.READ_WRITE, true) .

Message Edited by klyubin on 05-13-2009 07:57 PM