// Simple Java Ping Applet
// Unsupported Freeware by Jay Fenton Aug 1996
// jay@fentonia.com


import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.lang.Thread;
import SAL.util.unbug;


// 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);
	   unbug.hex_dump ("Sending", msg, msg.length);
           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);
		    unbug.hex_dump ("Reply", repBuf, repBuf.length);

        	    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;
    }

}

public class PingDisplay2 extends Applet
implements ActionListener
{
    Pinger ping;
    TextField timeDisplay;
    String fromHost;
    Button refreshButton;

    public void init()
    {
     try {
        fromHost = this.getCodeBase().getHost();
  // Alternative for testing on unrestricted browsers.
  //    fromHost = "albee.sal.wisc.edu";

        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.setSize(40,20);
        refreshButton.addActionListener(this);
        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 void actionPerformed (ActionEvent e) {
       displayPing();
    }
}
