• Main Page
  • Related Pages
  • Classes
  • Files
  • File List

TraceroutePane.java

Go to the documentation of this file.
00001 
00002 import java.awt.Color;
00003 import java.awt.Dimension;
00004 import java.awt.Font;
00005 import java.awt.Toolkit;
00006 import java.awt.event.KeyAdapter;
00007 import java.awt.event.KeyEvent;
00008 import java.awt.event.MouseAdapter;
00009 import java.awt.event.MouseEvent;
00010 import java.text.SimpleDateFormat;
00011 import java.util.Calendar;
00012 
00013 import javax.swing.GroupLayout;
00014 import javax.swing.GroupLayout.Alignment;
00015 import javax.swing.JButton;
00016 import javax.swing.JComboBox;
00017 import javax.swing.JFrame;
00018 import javax.swing.JScrollPane;
00019 import javax.swing.JTextArea;
00020 import javax.swing.JTextField;
00021 import javax.swing.WindowConstants;
00022 
00023 /**
00024  *  Trace-route/ping application using ICMP from Jpcap
00025  * 
00026  *  @author Mikica B Kocic
00027  */
00028 public class TraceroutePane extends JFrame implements Traceroute.Context
00029 {
00030     /**
00031      *  Implements java.io.Serializable interface
00032      */
00033     private static final long serialVersionUID = 3590355845490077407L;
00034 
00035     /*  GUI components
00036      */
00037     private JButton     startButton;
00038     private JTextField  inputCmd;
00039     private JTextArea   logArea;
00040     private Traceroute  tracer;
00041     private JComboBox   ifaceList;
00042     
00043     /**
00044      *  Creates a new instance of the <code>ChatClientFrame</code>.
00045      *  
00046      *  @param args the command line arguments passed to main
00047      */
00048     public TraceroutePane( String args[] )
00049     {
00050         super( "IP1-4.3: Traceroute, Idle" );
00051         
00052         setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
00053 
00054         //////////////////////////////////////////////////////////////////////////////////
00055         
00056         /* GUI Components
00057          */
00058         Font textFont = new Font( Font.SANS_SERIF, Font.PLAIN, 14 );
00059         Font logFont  = new Font( Font.MONOSPACED, Font.PLAIN, 16 );
00060         
00061         inputCmd = new JTextField( "atlas.dsv.su.se" );
00062         inputCmd.setFont( textFont );
00063         inputCmd.setColumns( 30 );
00064         inputCmd.selectAll ();
00065 
00066         startButton = new JButton ();
00067         startButton.setText( "Go!" );
00068         startButton.setForeground( Color.black );
00069 
00070         startButton.addMouseListener(
00071                 new MouseAdapter () {
00072                     public void mouseClicked( MouseEvent evt ) {
00073                         startButton_Clicked( evt );
00074                     }
00075                 }
00076             );
00077 
00078         ifaceList = new JComboBox ();
00079         ifaceList.setEditable( false );
00080         
00081         /* Scrollable log area
00082          */
00083         logArea = new JTextArea ();
00084         
00085         logArea.setLineWrap( true );
00086         logArea.setWrapStyleWord( true );
00087         logArea.setEditable( false );
00088         logArea.setFont( logFont );
00089         logArea.setBackground( new Color(  32,  32,   0 ) );
00090         logArea.setForeground( new Color( 240, 192,   0 ) );
00091 
00092         JScrollPane logPane = new JScrollPane ();
00093         logPane.setViewportView( logArea );
00094             
00095         //////////////////////////////////////////////////////////////////////////////////
00096         
00097         /* Layout (self explained?): 
00098          *     Upper: startButton, inputCmd and ifaceList
00099          *     Lower: logPane
00100          */
00101         GroupLayout layout = new GroupLayout( getContentPane () );
00102         getContentPane().setLayout( layout );
00103         layout.setAutoCreateContainerGaps( true );
00104         layout.setAutoCreateGaps( true );
00105 
00106         layout.setHorizontalGroup
00107         (
00108             layout
00109             .createParallelGroup( Alignment.LEADING )
00110             .addGroup
00111             ( 
00112                 layout
00113                 .createSequentialGroup ()
00114                 .addGroup
00115                 ( 
00116                     layout
00117                     .createParallelGroup( Alignment.LEADING )
00118                     .addGroup
00119                     (
00120                         Alignment.TRAILING, 
00121                         layout
00122                         .createSequentialGroup ()
00123                         .addComponent( startButton, 80, 80, 80 )
00124                         .addComponent( inputCmd )
00125                         .addComponent( ifaceList, 100, 300, 300 )
00126                             
00127                     )
00128                     .addComponent( logPane )
00129                 )
00130             )
00131         );
00132         
00133         layout.setVerticalGroup
00134         (
00135             layout
00136             .createParallelGroup( Alignment.LEADING )
00137             .addGroup
00138             (
00139                 layout
00140                 .createSequentialGroup ()
00141                 .addGroup
00142                 (
00143                     layout
00144                     .createParallelGroup( Alignment.CENTER )
00145                     .addComponent( startButton )
00146                     .addComponent( inputCmd, Alignment.CENTER, 0, 27, 27 )
00147                     .addComponent( ifaceList, Alignment.CENTER, 0, 26, 26 )
00148                 )
00149                 .addComponent( logPane )
00150             )
00151         );
00152         
00153         pack();
00154         
00155         //////////////////////////////////////////////////////////////////////////////////
00156         
00157         /* Adjust window dimensions not to exceed screen dimensions ...
00158          */
00159         Dimension win = new Dimension( 1024, 600 );
00160         Dimension scsz = Toolkit.getDefaultToolkit().getScreenSize();
00161         win.width  = Math.min( win.width, scsz.width );
00162         win.height = Math.min( win.height, scsz.height - 40 );
00163         setSize( win );
00164         
00165         /* ... then center window on the screen.
00166          */
00167         setLocation( ( scsz.width - win.width )/2, ( scsz.height - 40 - win.height )/2 );
00168         
00169         /* Ready for user to type in something...
00170          */
00171         inputCmd.requestFocus ();
00172 
00173         /* Keyboard event handler for ENTER in input text field
00174          */
00175         inputCmd.addKeyListener( new KeyAdapter ()
00176         {
00177             @Override public void keyPressed( KeyEvent e )
00178             {
00179                 int keyCode = e.getKeyCode ();
00180                 
00181                 if( keyCode == KeyEvent.VK_ENTER )
00182                 {
00183                     parseCommand ();
00184                 }
00185             }
00186         } );
00187         
00188         /* Creates trace-route instance. We should have heavy exception handling here
00189          * as we are relying on external components: Jpcap and WinPCAP.
00190          * Both must be installed properly for <code>Traceroute</code> to be
00191          * instantiated. 
00192          */
00193         try
00194         {
00195             tracer = new Traceroute ( this );
00196         }
00197         catch( NoClassDefFoundError e ) // Jpcap is probably missing
00198         {
00199             tracer = null;
00200 
00201             if ( e.getMessage().toLowerCase().contains( "jpcap" ) )
00202             {
00203                 println( " " );
00204                 println( " ERROR:" );
00205                 println( "     Jpcap is not installed!" );
00206                 logNewLine ();
00207                 println( " Please, download and install Jpcap from: " );
00208                 println( "     http://netresearch.ics.uci.edu/kfujii/Jpcap/doc/download.html" );
00209                 logNewLine ();
00210                 println( " You will also need to get and install WinPCAP from: " );
00211                 println( "     http://www.winpcap.org/install/default.htm" );
00212             }
00213             else
00214             {
00215                 e.printStackTrace ();
00216             }
00217         }
00218         catch( UnsatisfiedLinkError e ) // Wincap is probably missing
00219         {
00220             tracer = null;
00221 
00222             if ( e.getMessage().toLowerCase().contains( "cap.dll" ) )
00223             {
00224                 println( " " );
00225                 println( " ERROR:" );
00226                 println( "     WinPCAP is not installed!" );
00227                 logNewLine ();
00228                 println( " Please, download and install WinPCAP from: " );
00229                 println( "     http://www.winpcap.org/install/default.htm" );
00230                 logNewLine ();
00231             }
00232             else
00233             {
00234                 e.printStackTrace ();
00235             }
00236         }
00237 
00238         if ( tracer != null ) // survived Jpcap & WinPCAP i.e. up and running
00239         {
00240             /* Print usage
00241              */
00242             println( " " );
00243             println( " Usage:" );
00244             println( "    1) Select network interface used for transmission"
00245                      + " (from the upper right combo box)" );
00246             println( "    2) Enter hostname then press Enter or click 'Go!'" );
00247             logNewLine ();
00248             println( " To ping instead to trace route, add 'ping' after the hostname." );
00249             logNewLine ();
00250 
00251             /* Add all interfaces to combo box
00252              */
00253             for( String s : tracer.getInterfaceList () )
00254             {
00255                 ifaceList.addItem( s );
00256             }
00257         }
00258         
00259         /* Transfer command line arguments into inputCmd (if any) 
00260          * then parse them immediately...
00261          */
00262         if ( args.length > 0 )
00263         {
00264             String join = "";
00265             for( String s : args ) {
00266                 join += ( join.length () == 0 ? s : " " + s );
00267             }
00268             inputCmd.setText( join );
00269             parseCommand ();
00270         }
00271     }
00272 
00273     /**
00274      *  Starts fetching data from URL specified in <code>urlText</code>.
00275      */
00276     private void startButton_Clicked( MouseEvent evt ) 
00277     {
00278         parseCommand ();
00279     }
00280 
00281     /**
00282      *  Gets current time stamp (millis resolution)
00283      *  
00284      *  @return time in ISO format 
00285      */
00286     private static String now ()
00287     {
00288         Calendar cal = Calendar.getInstance ();
00289         SimpleDateFormat sdf = new SimpleDateFormat( "HH:mm:ss.SSS" );
00290         return sdf.format( cal.getTime() );
00291     }
00292 
00293     /**
00294      *  println() == short cut for logMesage() + logNewLine () without timestamp 
00295      */
00296     public void println( String str )
00297     {
00298         logMessage( str, /*timestamp*/ false );
00299         logNewLine ();
00300     }
00301     
00302     /**
00303      *  Logs new line
00304      */
00305     @Override
00306     public void logNewLine ()
00307     {
00308         synchronized( logArea )
00309         {
00310             if ( logArea.getText().length() != 0 )
00311             {
00312                 logArea.append( "\n" );
00313                 logArea.setRows( logArea.getRows () + 1 );
00314                 logArea.setCaretPosition( logArea.getText().length () );
00315             }
00316         }
00317     }
00318     
00319     /**
00320      *  Logs message, with optional timestamp
00321      *  
00322      *  @param str    message that will be logged
00323      *  @param timestamp   whether to prefix message with timestamp or not
00324      */
00325     @Override
00326     public void logMessage( String str, boolean timestamp )
00327     {
00328         synchronized( logArea )
00329         {
00330             if ( timestamp )
00331             {
00332                 // Ensure that there is a new-line before time-stamp
00333                 //
00334                 String log = logArea.getText ();
00335                 if ( log.length () > 0 && log.charAt( log.length () - 1 ) != '\n' ) {
00336                     logNewLine ();
00337                 }
00338                 
00339                 logArea.append( now () + "  " + str );
00340             }
00341             else
00342             {
00343                 logArea.append( str );
00344             }
00345 
00346             logArea.setCaretPosition( logArea.getText().length () );
00347         }
00348     }
00349     
00350     /**
00351      *  On trace route completed call-back from the instance of <code>Traceroute</code>
00352      */
00353     @Override
00354     public void onTracerouteCompleted ()
00355     {
00356         setTitle( "IP1-4.3: Traceroute, Idle" );
00357         startButton.setText( "Go!" );
00358         startButton.setForeground( Color.black );
00359     }
00360     
00361     /**
00362      *  Parses input message or command from inputMsg.
00363      *  Also performs various commands :open, :close, :exit ...
00364      */
00365     public void parseCommand ()
00366     {
00367         if ( tracer == null ) {
00368             return;
00369         }
00370 
00371         /* Split string into words, removing all leading, trailing 
00372          * and superfluous (btw words) white-spaces
00373          */
00374         String[] args = inputCmd.getText().trim().split( "\\s{1,}" );
00375         
00376         if ( args.length < 1 ) {
00377             return;
00378         }
00379 
00380         if ( tracer.isIdle () )
00381         {
00382             boolean ping = ( args.length >= 2 && args[1].equalsIgnoreCase("ping") );
00383             
00384             startButton.setText( "Cancel" );
00385             startButton.setForeground( Color.red );
00386 
00387             if ( ping ) {
00388                 setTitle( "IP1-4.3: Pinging " + args[0] + "..." );
00389             } else {
00390                 setTitle( "IP1-4.3: Tracing route to " + args[0] + "..." );
00391             }
00392             
00393             /* Start trace-route/ping. TTL is set to 64 if second word in cmd line
00394              * is 'ping'.
00395              */
00396             tracer.startPinging( ifaceList.getSelectedIndex (), args[0], ping ? 64 : 0 );
00397         }
00398         else
00399         {
00400             tracer.stopTrace ();
00401         }
00402     }
00403     
00404     /**
00405      *  Main entry point. Creates and makes visible GUI...
00406      *  
00407      *  @param args the command line arguments
00408      */
00409     public static void main( String args[] ) 
00410     {
00411         final String[] copyOfArgs = args;
00412         
00413         java.awt.EventQueue.invokeLater( 
00414                 new Runnable() {
00415                     public void run() {
00416                         new TraceroutePane( copyOfArgs ).setVisible( true );
00417                     }
00418                 }
00419             );
00420     }
00421 }
00422 
00423 /*! 
00424  *  \mainpage ICMP Traceroute and Ping based on Jpcap
00425  *
00426  *  \section s_intro Introduction
00427  *  
00428  *  The package implements solution to \ref p_task as a part of 
00429  *  the <a href="http://dsv.su.se/utbildning/distans/ip1" target="_blank"><b>SU/IP1 
00430  *  course</b></a>.
00431  *  
00432  *  \image html traceRouteApp.png
00433  *  
00434  *  \section s_desc Description
00435  *  
00436  *  Application's graphical user interface is implemented in the class TraceroutePane.
00437  *  The application offers user to enter IP address or hostname and to select network 
00438  *  interface used for originating ICMP packets.
00439  *  
00440  *  The applications accepts commands in the following format:
00441  *  
00442  *   - <code>&lt;host&gt; [ ping ]</code>
00443  *  
00444  *  where optional keyword <i>ping</i> (following the host name) indicates to 
00445  *  application to perform ping instead of trace route.
00446  *  
00447  *  ICMP packets are sent and received in a separate worker thread  Traceroute.run()
00448  *  instantiated from the class Traceroute. User can stop trace route at any time by 
00449  *  pressing "Cancel" button (the thread will be stopped gracefully).
00450  *  
00451  *  One can alternatively start application from the os command line with parameters:
00452  *  
00453  *   - <code>java -jar <a href="../traceRoute.jar">traceRoute.jar</a>
00454  *     [ &lt;host&gt; [ ping ] ]</code>
00455  *   
00456  *  where the default is to trace route and not to ping.
00457  *  
00458  *  \section s_req Requirements
00459  *  
00460  *  <div style="color:darkred; font-weight: bold;">
00461  *  Application needs the following components to be installed:
00462  *  </div> 
00463  *  
00464  *   - <a href="http://netresearch.ics.uci.edu/kfujii/Jpcap/doc/download.html" target="_blank">
00465  *     <b>Jpcap</b></a>: java library for capturing and sending network packets<br>
00466  *   - <a href="http://www.winpcap.org/install/default.htm" target="_blank">
00467  *     <b>WinPCAP</b></a>: (industry standard) windows capture library.
00468  *  
00469  *  \section s_jar Executable
00470  *  
00471  *  The jar file of the package can be found <a href="../traceRoute.jar"><b>here</b></a>.
00472  *   
00473  *  \section s_src Sources
00474  *  
00475  *  Source files:
00476  *   - \ref Traceroute.java
00477  *   - \ref TraceroutePane.java
00478  *
00479  */
00480 /*! \page p_task IP1-4.3 Uppgift
00481  *
00482  *  Gör ett program som implementerar ping, traceroute eller något annat 
00483  *  nätverksprogram som använder eller något som man inte kan göra i standardversionen
00484  *  av Java. Man ska inte anropa motsvarande funktioner i operativsystemet via 
00485  *  exempelvis: <code>Runtime.getRuntime().exec("myprog.exe")</code> utan man ska
00486  *  använda ett Java-paket som anropar C-kod som implementerar raw sockets. 
00487  */

Generated on Thu Dec 16 2010 12:29:23 for Traceroute and Ping by  doxygen 1.7.2