import java.applet.*; import java.awt.*; import java.net.*; import java.lang.Thread; public class PingDisplay extends Applet { Pinger ping; TextField timeDisplay; String fromHost; Button refreshButton; public void init() { try { fromHost = this.getCodeBase().getHost(); // Alternative for testing on unrestricted browsers. // fromHost = "www.3dcom.com"; ping = new Pinger(InetAddress.getByName(fromHost)); timeDisplay = new TextField("Waiting"); timeDisplay.setEditable(false); this.setLayout(new BorderLayout()); this.add("Center",timeDisplay); refreshButton = new Button("Ping"); refreshButton.resize(40,20); this.add("East",refreshButton); } catch (Exception e) {} } public void start() { super.start(); displayPing(); } public void stop() { super.stop(); ping.stop(); } void displayPing() { timeDisplay.setText("Pinging: " + fromHost); // let user know test underway long echoTime = ping.doPing(); // conduct actual test if(echoTime == -1) // check timeout status timeDisplay.setText(fromHost + " timed out."); else // display time in button timeDisplay.setText("Latency to " + fromHost + ": " + Long.toString(echoTime) + " ms."); } // When "Ping" button pressed, rerun and redisplay. public boolean action(Event e, Object what) { if((e.target == refreshButton) && (e.id == Event.ACTION_EVENT)) { displayPing(); return (true); } return(false); } } // The Pinger object measures network latency by sending a packet // to the UDP Echo Port (Port 7) and timing how long it takes. // We use this port instead of ICMP because I would have to // use native methods in order to produce ICMP packets. class Pinger implements Runnable { static final int echoPort = 7; static final int maxPingTime = 3000; // Milliseconds static final int pingPollInterval = 100; // Milliseconds DatagramSocket socket; InetAddress fromIP; long sendTime; long timeMeasured; Thread timeOutMonitor; Thread pingListenThread; byte packetNumber = 0; public Pinger(InetAddress pingee) { fromIP = pingee; } // If needed, start a listener thread to notice the reply. // then we send out a brief message to the echo port. // Since the Java thread model does not allow one thread to break // another one out of a wait, we sleep for brief intervals, waking // up periodically to see if the reply has come in yet. public long doPing() { byte[] msg = new byte[1]; msg[0] = ++packetNumber; timeMeasured = -1; if(socket == null) try { socket = new DatagramSocket(); } catch (Exception e) { return(0); } if(pingListenThread == null) { pingListenThread = new Thread(this); pingListenThread.start(); } DatagramPacket packet = new DatagramPacket(msg,msg.length,fromIP,echoPort); sendTime = System.currentTimeMillis(); long timeLimit = sendTime + maxPingTime; try { socket.send(packet); while (System.currentTimeMillis() < timeLimit) { Thread.sleep(pingPollInterval); if(timeMeasured != -1) // reply has been noticed, so return result. return(timeMeasured); } } catch (Exception e) {}; return(timeMeasured); // return what is probably -1. } // Run method for the listener thread public void run() { byte[] repBuf = new byte[1]; DatagramPacket reply = new DatagramPacket(repBuf,repBuf.length); try { while (true) { socket.receive(reply); if(repBuf[0] == packetNumber) { timeMeasured = System.currentTimeMillis() - sendTime; pingListenThread = null; return; } } } catch (Exception e) { pingListenThread = null; return; } } // Clean up any dangling listener thread and release the socket. public void stop() { if(pingListenThread != null) { pingListenThread.stop(); pingListenThread = null; } socket.close(); socket = null; } }