Hi,

I'm trying to write a MIDlet that does some UDP send and receives and I'm running into a problem on the Nokia 6102i handset. The app runs fine on the Sun and Nokia emulators as well as other J2ME devices (Palm, Motorola SLVR etc.) that I have tested on. I think the problem occurs when you use the same DatagramConnection in 2 different threads - one sending packets on the connection and the other receiving packets. If one thread is blocked in the receive call (J2ME has no async i/o), attempting to send on the other thread blocks forever on the 6102i. I have a small example here (see comments after the code):

Code:
import java.io.IOException;
import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import javax.microedition.io.UDPDatagramConnection;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.MIDlet;

public class UDPTestMT extends MIDlet implements CommandListener {
    //Version info
    private static final String version = "0.1";

    private Display display;

    //Welcome Displayabale
    private Form welcomeForm = null;

    //Exit Command
    private Command exitCommand = null;

    private UDPEchoClient udpEchoClient = null;

    public UDPTestMT() {
        this.welcomeForm = new Form("UDP Echo Active Test");

        //Attach Exit command to the form
        this.exitCommand = new Command("Exit", Command.EXIT, 0);
        this.welcomeForm.addCommand(this.exitCommand);

        this.welcomeForm.setCommandListener(this);
    }

    public void startApp() {
        this.display = Display.getDisplay(this);
        this.display.setCurrent(this.welcomeForm);

        this.udpEchoClient = new UDPEchoClient();
        this.udpEchoClient.start();
    }
    
    public void pauseApp() {
    }
    
    public void destroyApp(boolean unconditional) {
        if (this.udpEchoClient != null) {
            this.udpEchoClient.close();
            try {
                this.udpEchoClient.join();
            } catch(InterruptedException e) {
            }
        }
    }
    
    public void commandAction(Command c, Displayable s) {
        if (c == this.exitCommand) {
            destroyApp(false);
            notifyDestroyed();
        }
    }

    private class UDPEchoClient extends Thread {

        private String server;
        private UDPDatagramConnection udp;

        public UDPEchoClient() {
            this.server = "datagram://10.10.20.113:7";
        }

        public void run() {
            UDPReceiver udpReceiver = null;
            boolean error = false;
            
            try {
                this.udp = (UDPDatagramConnection)Connector.open(this.server);

                udpReceiver = new UDPReceiver(this.udp);
                new Thread(udpReceiver).start();

                //Sleep to force the receiver thread to run and block in receive
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException e) {
                }

                byte []packet = new byte[100];
                for(int i = 0; i < 100; ++i)
                    packet[i] = 'B';

                Datagram pktBuf = this.udp.newDatagram(100);
                pktBuf.setAddress(this.server);
                pktBuf.setData(packet, 0, 100);
                UDPTestMT.this.welcomeForm.append("Sending packet\n");
                this.udp.send(pktBuf);
                UDPTestMT.this.welcomeForm.append("Done Sending packet\n");
            } catch(IOException e) {
                UDPTestMT.this.welcomeForm.append("Tx IO Exception: " + e);
                error = true;
            } catch(Exception e) {
                UDPTestMT.this.welcomeForm.append("Tx Exception: " + e);
                error = true;
            }

            if (!error)
                try {
                    if (udpReceiver != null)
                        udpReceiver.join();
                } catch(InterruptedException e) {
                }
        }

        public void close() {
            try {
                if (this.udp != null)
                    this.udp.close();
            } catch(Exception ignored) {
            }
        }
    }

    private class UDPReceiver extends Thread {

        private UDPDatagramConnection udp;

        public UDPReceiver(UDPDatagramConnection udp) {
            this.udp = udp;
        }

        public void run() {
            //blocking Receive - no async i/o in j2me, this will remain here if no pkt is received or until closed
            try {
                //Assume 1k is enough
                Datagram dgram = this.udp.newDatagram(1024);
                this.udp.receive(dgram);
                int length = dgram.getLength();
                UDPTestMT.this.welcomeForm.append("Rcvd datagram of length " + length);
            } catch(IOException e) {
                UDPTestMT.this.welcomeForm.append("Rx IO Exception: " + e);
            } catch(Exception e) {
                UDPTestMT.this.welcomeForm.append("Rx Exception: " + e);
            }
        }
    }
}
Comments/Caveats:

1. In the UDPEchoClient constructor, the server address is a local echo server's.
2. The sleep call in UDPEchoClient.run() is to simulate the bug I originally saw in a larger program. The larger app is like a UDP Echo Client - the transmit thread transmitting UDP datagrams periodically (using a Timer and TimerTask) and the receive thread counting/processing the echoed packets.

Is this a known bug or am I doing something wrong? I would appreciate any feedback.

Regards,
Nagarjuna