/*
 Copyright (c) 1997 by Columbia University. All rights reserved.
 */

import java.lang.*;
import java.io.*;

/** 
 * PingWrapper is a wrapper around the common ping program
 * that exists on many operating systems. 
 * @version 1.0 31 Aug 1998
 * @author Terrence Truta
 */
public class PingWrapper extends java.lang.Object
{
  
    String executable = "ping";
    String address = "cunix.columbia.edu"; //default host

    boolean debug = false;
	  int echoRequests = 10;
    int packetSize = 56;

		int lost;
		int avg;

		
		/**
		 * Sets the number of times to ping the host.
		 */
		public void setEchoRequests(int er) {
			echoRequests = er;
		}

		/**
		 * Sets the amount of data to be sent to the host.
		 */
		public void setPacketSize(int ps) {
			packetSize = ps;
		}

		/**
		 * Sets the host to be pinged
		 */
		public void setAddress(String a) {
			address = a;
		}

		/**
		 * Returns the avg time value of all the pings for each execution.
		 */
		public int getAvg() {
			return avg;
		}

		/**
		 * Returns the amount of ping requests lost for each execution.
		 */
		public int getLost() {
			return lost;
		}

		/** Test driver for this class.
		 */
		public static void main (String args[]) {
    try {
        PingWrapper pw = new PingWrapper();
        if (args.length > 0) 
            pw.setAddress(args[0]);
	      
		    pw.execute();
			  System.out.println("avg = " + pw.getAvg() + ", loss = " + pw.getLost());


      } catch (Exception e) {
        System.out.println(e);
        System.exit(1);
      }
    }
    
		/** Sets the command line appropriate for the OS then executes the ping
		  * program. Afterward it calls the appropriate method to parse the output.
			*/
    public void execute() {
      BufferedReader in = null;
      
			String cmd;
      try {
				if (System.getProperty("os.name").indexOf("Windows") != -1)
				  cmd = "ping -n " + echoRequests + " -l " + packetSize + 
									" " + address;						
				else
				  if (System.getProperty("os.name").compareTo("Linux") == 0 )
				    cmd = "ping " + address + " -c " + echoRequests +
					           " -s " + packetSize;
				  else //Solaris et all (I hope)
			    	    cmd = "ping -s " + address + " "+packetSize+" "+echoRequests;

				debugPrint(cmd);
        Process p = Runtime.getRuntime().exec(cmd);
        
        in = new BufferedReader(new InputStreamReader(p.getInputStream()));
				if (System.getProperty("os.name").compareTo("Windows 95") == 0)
						parseWin95Output(in);
				else {
						debugPrint("OS is: " + System.getProperty("os.name"));
						parseUnixOutput(in);
				}
					

      }
      catch (Exception e) {
            System.out.println("Error running ping");
            System.out.println(e);

      }
    }

		/** Wrapper around the BufferedReader readLine command
		 */
	  private String read(BufferedReader in) throws IOException {
		  
			String s = in.readLine();
			debugPrint("Just read s = " + s);
			return s;
		}

		/** Parses the ping output on the Windows 95 platform. 
		 * Windows NT should be similar
		 */
		public void parseWin95Output(BufferedReader in) {
			try {
			String s;
			//skip over initial lines of output
				s = read(in);
				while ((s.indexOf("Reply from")  == -1) && 
								(s.indexOf("Request timed out.") == -1)) { 
					s = read(in);
				} 
				
				//parse Traceroute output
				lost = 0;
				int total = 0;
				do {

										//skip over any blank lines in input
										while((s.trim()).compareTo("") == 0) {
												s = read(in);
												if (s == null) break;
										}
										
										debugPrint("before null test, s =" + s + ".");
										if (s == null) {
											debugPrint("s = " + s + ", breaking...");
											break;
										}
										//see if a packet was lost
										if ((s.trim()).compareTo("Request timed out.") == 0) {
												lost++;
												continue;
										}

										//ASSERT: s contains a string starting with:
										//"Reply from ..."
										//hopefully the rest of it looks like this...
										//Reply from 128.59.35.130: bytes=500 time=290ms TTL=243

										//try to extract the time value
										try {
										  int start = s.indexOf("time=");
											int end = s.indexOf("ms", start);
                      String temp = s.substring(start+5, end);
											total += Integer.parseInt(temp);
										} catch (Exception nfe) {
											//this catches the error that occurs if the request from tracert
											//times out then no host informatio is given
											//In this case just store the tracert info message
											System.out.println("Error parsing Output of Ping.");
											System.out.println(nfe);
											System.out.println("Attempting to recover...");
											lost++; //increment lost so the avg won't be inaccurate
										} 
									
				} 
				while((s = read(in)) != null); 
            
					    
        if (echoRequests - lost != 0)
				  avg = total / (echoRequests - lost);
				else
				  avg = 0;
			
				debugPrint("Finished parsing output");
			} catch (IOException e) {
				System.out.println("IOException in parseOutput()");
				System.exit(1);
			}
		}

		/** Parses the output of ping on the Unix OS. Also works with Linux.
		 */
		public void parseUnixOutput(BufferedReader in) {
			
			//the UNIX side is easy. UNIX ping is nice enough to give us a summary
			//at the end of the output.
			//Here is what the summary should look like:
			//----cunix.columbia.edu PING Statistics----
		  //10 packets transmitted, 10 packets received, 0% packet loss
			//round-trip (ms)  min/avg/max = 1/1/2
			try {
			String s;
			//skip over initial lines of output
				s = read(in);
				while (s.indexOf("packets transmitted,")  == -1) { 
					s = read(in);
				} 
				
				//parse Traceroute output
				debugPrint("s = " + s);
			  //try to extract the "packets received" value
				try {
					int start = s.indexOf("transmitted,");
					int end = s.indexOf("packets received", start);
				        String temp = s.substring(start+12, end);
					debugPrint("temp = " + temp);
					int a = Integer.parseInt(temp.trim());
					debugPrint("a = " + a);
					lost = echoRequests - a;
				} catch (NumberFormatException nfe) {
					//this catches the error that occurs if the request from tracert
					//times out then no host informatio is given
					//In this case just store the tracert info message
					System.out.println("Error parsing Output of Ping.");
					System.out.println(nfe);
					lost = -1; //flag for error
				} 
				s = read(in);
				//try to extract the "average" RTT value
				
				try {
					int start = s.indexOf("/", s.indexOf("max ="));
					int end = s.lastIndexOf("/");
				        String temp = s.substring(start+1, end);
					if (System.getProperty("os.name").compareTo("Linux") == 0)
	                                  avg = (Float.valueOf(temp)).intValue();
        	                        else
                   			  avg = Integer.parseInt(temp);

					//avg = Integer.parseInt(temp);
				} catch (NumberFormatException nfe) {
					//this catches the error that occurs if the request from tracert
					//times out then no host informatio is given
					//In this case just store the tracert info message
					System.out.println("Error parsing Output of Ping.");
					System.out.println(nfe);
					avg = -1; //flag for error
				} 

				debugPrint("Finished parsing output");
			} catch (IOException e) {
				System.out.println("IOException in parseOutput()");
				System.exit(1);
			}

		}

    
    private void debugPrint(String s) {
       if (debug) System.out.println(s);
    }
       
}
